DNS重绑定攻击漏洞分析与修复方案

本文详细分析了SSRF过滤器中存在的DNS重绑定攻击漏洞,探讨了不同Ruby版本中的安全修复方案,包括uri.hostname替换和ipaddr参数的使用,提供了完整的概念验证代码和修复建议。

DNS重绑定攻击漏洞报告

漏洞概述

在SSRF过滤器中存在DNS重绑定漏洞。该库验证主机名的IP地址,但随后将主机名传递给Net::HTTP.start(),后者会执行自己的DNS查询。攻击者可以控制DNS服务器,在验证期间返回安全的公共IP,然后在Net::HTTP稍后解析时返回127.0.0.1。

技术细节

漏洞代码

1
2
Net::HTTP.start(uri.hostname, uri.port, **http_options) do |http|
# 当前使用uri.hostname会触发新的DNS查询!

攻击原理

攻击者设置evil.com的DNS以交替响应:

  • 第一次查询(验证期间)返回8.8.8.8
  • 第二次查询(Net::HTTP内部查找)返回127.0.0.1

结果:SsrfFilter.get('http://evil.com:6379')绕过所有保护并访问本地主机上的内部服务。

修复方案

建议修复

直接连接到验证的IP而不是主机名:

  • Net::HTTP.start(uri.hostname, ...)改为Net::HTTP.start(validated_ip, ...)
  • 手动设置Host头:headers['Host'] = uri.hostname
  • 使用ssl_hostname: uri.hostname进行正确的TLS证书验证

版本对比分析

v1.1.2(安全)

1
2
hostname = uri.hostname
uri.hostname = ip  # 这行代码被移除,需要恢复

Net::HTTP直接接收验证过的IP地址,防止DNS重绑定攻击。

v1.3.0(存在回归漏洞)

移除了uri.hostname = ip行,仅添加了ipaddr: ip到选项。Net::HTTP接收主机名而不是IP,允许DNS重绑定。

Ruby版本影响

Ruby 2.6.10

  • ipaddr参数被完全忽略
  • v1.1.2仍然安全,因为它使用uri.hostname = ip方法

Ruby 3.3.0

  • ipaddr参数正常工作并防止DNS解析
  • v1.3.0传递原始主机名给Net::HTTP,完全依赖ipaddr参数进行保护

概念验证代码

提供了完整的测试脚本,演示:

  1. v1.1.2的安全行为
  2. 当前主分支的漏洞行为
  3. ipaddr选项不防止DNS解析的证据

防御建议

采用深度防御方法:

  • 恢复v1.1.2中的uri.hostname = ip
  • ipaddr参数结合使用
  • 提供两个独立的保护层

影响评估

该漏洞允许攻击者通过DNS重绑定绕过SSRF保护,访问内部服务,严重性评级为关键(10.0)。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计