代码审计,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)。
阅读全文