从TemplatesImpl类Gadget中提取bytecode
字数 1545 2025-08-10 08:29:06

从TemplatesImpl类Gadget中提取bytecode的三种方法

前言

在Java反序列化漏洞利用中,TemplatesImpl类是一个常用的gadget组件,出现在多个反序列化利用链中(如CommonsCollections2-4、CommonsBeanutils1、Jdk7u21及变种JRE8u20等)。这类gadget的核心原理是通过反序列化触发TemplatesImpl类的newTransformergetOutputProperties方法,最终调用defineTransletClasses方法,将_bytecodes字段中存储的字节码重新在JVM中定义为类,并在实例化时执行其中的静态代码块或无参构造方法中的代码。

方法一:使用IDEA调试提取bytecode

准备工作

  1. 安装IDEA开发环境
  2. 部署目标环境(如shiro的samples-web.war)
  3. 准备Xray高级版(用于触发Shiro扫描)

操作步骤

  1. 在IDEA中打开目标项目

  2. TemplatesImpl类的内部类TransletClassLoaderdefineClass方法上设置断点

  3. 启动调试模式

  4. 使用Xray执行扫描命令:

    xray webscan --plugins shiro --url http://127.0.0.1:8080/samples_web_war/
    

    (注意URL结尾必须加斜杠)

  5. 当断点触发时,在IDEA的调试表达式窗口中执行以下代码:

    var f = new FileOutputStream("d:/test.class"); // 修改为实际保存路径
    f.write(b); // b是defineClass方法的参数
    f.close();
    
  6. 使用反编译工具(如JD-GUI或Luyten)查看保存的class文件

方法二:使用Java Agent动态修改类

实现原理

通过Java Agent技术,在运行时修改TemplatesImpl$TransletClassLoader类的defineClass方法,添加字节码导出功能。

示例代码

package org.fnmsd;

import javassist.*;
import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class DumperAgent {
    public static void premain(String args, Instrumentation instrumentation) {
        DumperTransformer transformer = new DumperTransformer();
        instrumentation.addTransformer(transformer);
    }

    public static class DumperTransformer implements ClassFileTransformer {
        public byte[] transform(ClassLoader loader, String className, 
                Class<?> classBeingRedefined, ProtectionDomain protectionDomain, 
                byte[] classfileBuffer) throws IllegalClassFormatException {
            
            if (className.equals("com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader")){
                ClassPool classPool = ClassPool.getDefault();
                classPool.appendClassPath(new LoaderClassPath(loader));
                try {
                    CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
                    CtMethod defineClass = ctClass.getDeclaredMethod("defineClass");
                    
                    // 插入导出字节码的代码
                    defineClass.insertBefore(
                        "long l = new java.util.Random().nextLong();" +
                        "System.out.println(\"Output Class:\"+l);" +
                        "new java.io.FileOutputStream(l+\".class\").write($1);"
                    );
                    
                    return ctClass.toBytecode();
                } catch (Exception e) {
                    System.err.println("Agent:Patch Method Error");
                    e.printStackTrace();
                }
            }
            return classfileBuffer;
        }
    }
}

使用说明

  1. 将上述代码编译为Java Agent
  2. 在JVM启动参数中添加Agent:
    -javaagent:/path/to/agent.jar
    
  3. defineClass方法被调用时,会自动将字节码保存为随机文件名的.class文件

方法三:直接解析Java序列化数据

实现原理

通过分析Java序列化数据的二进制格式,直接从中提取TemplatesImpl类的_bytecodes字段值。

工具准备

可以使用修改版的SerializationDumper工具(基于NickstaDB的实现)

关键修改点

  1. 添加识别TemplatesImpl类的逻辑
  2. 添加提取_bytecodes字段的功能
  3. 添加保存字节码的功能

操作步骤

  1. 获取目标序列化数据(如Shiro rememberMe cookie)
  2. 使用修改后的SerializationDumper解析数据
  3. 工具会自动识别并导出_bytecodes字段中的字节码

总结对比

方法 优点 缺点 适用场景
IDEA调试 直观、无需额外工具 需要调试环境、手动操作 研究分析、调试场景
Java Agent 自动化、可批量处理 需要Agent部署 生产环境监控、自动化分析
序列化解析 无需运行环境 需要处理加密数据 离线分析、加密数据研究

注意事项

  1. ysoserial生成的payload通常包含两个类:

    • 实际执行的恶意类
    • 一个无用的Foo类(用于满足某些条件)
  2. 字节码中的执行逻辑通常位于静态代码块中,这是此类gadget的标准做法

  3. 对于加密的序列化数据(如Shiro),需要先解密才能使用方法三

  4. 在实际分析中,可能需要结合多种方法才能完整提取和分析bytecode

扩展阅读

  1. 使ysoserial支持执行任意代码
  2. Java序列化协议规范
  3. ysoserial中bytecodes相关问题
从TemplatesImpl类Gadget中提取bytecode的三种方法 前言 在Java反序列化漏洞利用中,TemplatesImpl类是一个常用的gadget组件,出现在多个反序列化利用链中(如CommonsCollections2-4、CommonsBeanutils1、Jdk7u21及变种JRE8u20等)。这类gadget的核心原理是通过反序列化触发TemplatesImpl类的 newTransformer 或 getOutputProperties 方法,最终调用 defineTransletClasses 方法,将 _bytecodes 字段中存储的字节码重新在JVM中定义为类,并在实例化时执行其中的静态代码块或无参构造方法中的代码。 方法一:使用IDEA调试提取bytecode 准备工作 安装IDEA开发环境 部署目标环境(如shiro的samples-web.war) 准备Xray高级版(用于触发Shiro扫描) 操作步骤 在IDEA中打开目标项目 在 TemplatesImpl 类的内部类 TransletClassLoader 的 defineClass 方法上设置断点 启动调试模式 使用Xray执行扫描命令: (注意URL结尾必须加斜杠) 当断点触发时,在IDEA的调试表达式窗口中执行以下代码: 使用反编译工具(如JD-GUI或Luyten)查看保存的class文件 方法二:使用Java Agent动态修改类 实现原理 通过Java Agent技术,在运行时修改 TemplatesImpl$TransletClassLoader 类的 defineClass 方法,添加字节码导出功能。 示例代码 使用说明 将上述代码编译为Java Agent 在JVM启动参数中添加Agent: 当 defineClass 方法被调用时,会自动将字节码保存为随机文件名的.class文件 方法三:直接解析Java序列化数据 实现原理 通过分析Java序列化数据的二进制格式,直接从中提取 TemplatesImpl 类的 _bytecodes 字段值。 工具准备 可以使用修改版的SerializationDumper工具(基于NickstaDB的实现) 关键修改点 添加识别 TemplatesImpl 类的逻辑 添加提取 _bytecodes 字段的功能 添加保存字节码的功能 操作步骤 获取目标序列化数据(如Shiro rememberMe cookie) 使用修改后的SerializationDumper解析数据 工具会自动识别并导出 _bytecodes 字段中的字节码 总结对比 | 方法 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | IDEA调试 | 直观、无需额外工具 | 需要调试环境、手动操作 | 研究分析、调试场景 | | Java Agent | 自动化、可批量处理 | 需要Agent部署 | 生产环境监控、自动化分析 | | 序列化解析 | 无需运行环境 | 需要处理加密数据 | 离线分析、加密数据研究 | 注意事项 ysoserial生成的payload通常包含两个类: 实际执行的恶意类 一个无用的Foo类(用于满足某些条件) 字节码中的执行逻辑通常位于静态代码块中,这是此类gadget的标准做法 对于加密的序列化数据(如Shiro),需要先解密才能使用方法三 在实际分析中,可能需要结合多种方法才能完整提取和分析bytecode 扩展阅读 使ysoserial支持执行任意代码 Java序列化协议规范 ysoserial中bytecodes相关问题