代码审计,CC1 TransformedMap链,如何反向调试构造Payload?
摘要:代码审计 | CC1 TransformedMap 链 ——前言 反向调试 构造Payload 学习笔记,记录自己学 CC1 链的思路历程,不是教程,有啥问题欢迎交流。 目录 最终目标是什么 通过反射调用函数 但实际场景中没地方写代码怎么办
代码审计 | CC1 TransformedMap 链 ——前言 反向调试 构造Payload
学习笔记,记录自己学 CC1 链的思路历程,不是教程,有啥问题欢迎交流。
目录
最终目标是什么
通过反射调用函数
但实际场景中没地方写代码怎么办
方式 A:直接传输 Payload(CC 链)
方式 B:远程类加载
Gadget Chain 的由来
CC1 链构造过程
环境准备
第一步:找到能执行命令的点 —— InvokerTransformer
第二步:Runtime 不能序列化怎么办
第三步:谁来串联调用 —— ChainedTransformer
第四步:谁来触发 transform() —— TransformedMap
第五步:找到自动调用 setValue 的地方 —— AnnotationInvocationHandler
第六步:构造 AnnotationInvocationHandler
完整 Payload
完整调用链总结
最终目标是什么
攻击者想要执行这条命令:
Runtime.getRuntime().exec("calc");
那就有两个问题要想清楚:
在反序列化过程中,怎样才能让它自动执行这行代码?
不能直接写这句话,因为反序列化时只会调用 readObject() 方法
所以第一个问题就变成了:通过什么方法层层调用到 exec() 的?
通过反射调用函数
答案是:通过反射调用函数!
Runtime.class.getMethod("exec", String.class).invoke(Runtime.getRuntime(), "calc");
这是原本可以正常执行的反射调用。
但是如果随便写一个方法放入这段代码,反序列化的时候不会自动执行。那就必须把它放到一个会自动执行的方法里,比如 readObject()——反序列化时会自动调用它。
所以如果代码这样写:
package org.example;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
class cc1 implements Serializable {
private void readObject(ObjectInputStream ois) throws IOException,
ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, IllegalAccessException {
Runtime.class.getMethod("exec", String.class).invoke(Runtime.getRuntime(), "calc");
}
}
public class Main {
public static void main(String[] args) throws Exception {
// 创建恶意对象
cc1 evil = new cc1();
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(evil);
byte[] payload = baos.toByteArray();
// 反序列化(触发恶意代码)
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(payload));
ois.readObject(); // ← calc 应该会打开
}
}
是可以成功的。
但实际场景中没地方写代码怎么办
问题来了——如果是一个 Web 应用,根本没地方写代码,没有执行的地方,不可能直接开一个 readObject 的入口给我们写代码。
这就需要借助反序列化入口的服务,比如 JNDI 注入(RMI / LDAP)。
