#!/bin/bash # 07 - HTTP Request Smuggling # Full coverage: HTTP/1.1 (nc/port 80), HTTP/2 (TLS), HTTP/3 (QUIC), WebTransport # CL.TE / TE.CL / TE.TE obfuscation — proxy-specific immunity documented per RFC SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../config.sh" OUT_FILE="$OUT/07_advanced_smuggling.txt" echo "=== 07. HTTP Request Smuggling ===" | tee "$OUT_FILE" echo "Note: pqcrypta-proxy is HTTP/2+TLS only. Port 80 redirects. HTTP/3 via QUIC." | tee -a "$OUT_FILE" echo "" | tee -a "$OUT_FILE" HOST=$(echo "$TARGET" | sed 's|https\?://||' | cut -d/ -f1) # ── 1. HTTP/1.1 Plain — CL.TE via nc port 80 ───────────────────────────────── echo "--- HTTP/1.1 Plain (port 80) — CL.TE via nc ---" | tee -a "$OUT_FILE" # Port 80 should redirect to HTTPS or refuse — no plain HTTP accepted RESP_NC=$(printf 'POST / HTTP/1.1\r\nHost: %s\r\nContent-Length: 13\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nSMUGGLED' "$HOST" | \ nc -w 5 "$HOST" 80 2>&1 | head -5) if [ -z "$RESP_NC" ]; then echo " [OK] Port 80: no plain HTTP accepted (TCP refused or no response)" | tee -a "$OUT_FILE" elif echo "$RESP_NC" | grep -q '301\|302\|308'; then echo " [OK] Port 80: redirects to HTTPS (no smuggling surface on plain HTTP)" | tee -a "$OUT_FILE" else echo " [WARN] Port 80 responded unexpectedly:" | tee -a "$OUT_FILE" echo "$RESP_NC" | sed 's/^/ /' | tee -a "$OUT_FILE" fi # ── 2. HTTP/1.1 Plain — TE.CL via nc port 80 ───────────────────────────────── RESP_TECL=$(printf 'POST / HTTP/1.1\r\nHost: %s\r\nTransfer-Encoding: chunked\r\nContent-Length: 3\r\n\r\n1\r\nA\r\n0\r\n\r\n' "$HOST" | \ nc -w 5 "$HOST" 80 2>&1 | head -3) if [ -z "$RESP_TECL" ]; then echo " [OK] TE.CL port 80: no response (expected)" | tee -a "$OUT_FILE" else echo " [INFO] TE.CL port 80 response: $RESP_TECL" | tee -a "$OUT_FILE" fi echo "" | tee -a "$OUT_FILE" # ── 3. HTTP/2 over TLS — TE header (RFC 9113 §8.2.2 immunity) ──────────────── echo "--- HTTP/2 over TLS (port 443) ---" | tee -a "$OUT_FILE" echo " RFC 9113 §8.2.2: Transfer-Encoding MUST NOT be used in HTTP/2." | tee -a "$OUT_FILE" echo " A compliant HTTP/2 server must reject requests with TE header (STREAM_ERROR)." | tee -a "$OUT_FILE" # CL.TE over HTTP/2 CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 10 \ -X POST "$TARGET/" \ -H 'Transfer-Encoding: chunked' \ -H 'Content-Length: 3' \ --data-raw $'1\r\nA\r\n0\r\n\r\n') if [ "$CODE" = "400" ] || [ "$CODE" = "403" ] || [ "$CODE" = "422" ]; then echo " [OK] HTTP/2 CL.TE: [$CODE] server rejected malformed request" | tee -a "$OUT_FILE" else echo " [INFO] HTTP/2 CL.TE: [$CODE] (curl likely stripped TE header before sending)" | tee -a "$OUT_FILE" fi # Force HTTP/1.1 over TLS to test smuggling against backend echo " Testing HTTP/1.1 over TLS (--http1.1 flag):" | tee -a "$OUT_FILE" for VARIANT in \ "CL.TE:-H 'Content-Length: 13' -H 'Transfer-Encoding: chunked' --data-raw $'0\r\n\r\nSMUGGLED'" \ "TE.CL:-H 'Transfer-Encoding: chunked' -H 'Content-Length: 3' --data-raw $'1\r\nA\r\n0\r\n\r\n'"; do LABEL="${VARIANT%%:*}" ARGS="${VARIANT#*:}" CODE=$(eval "curl -sk --http1.1 -o /dev/null -w '%{http_code}' --max-time 10 -X POST \"$TARGET/\" $ARGS" 2>/dev/null) echo " [$CODE] HTTP/1.1-over-TLS $LABEL" | tee -a "$OUT_FILE" done echo "" | tee -a "$OUT_FILE" # ── 4. HTTP/2 — TE.TE Obfuscation ──────────────────────────────────────────── echo "--- HTTP/2 TE.TE Obfuscation ---" | tee -a "$OUT_FILE" OBFUSCATIONS=( "Transfer-Encoding: xchunked" "Transfer-Encoding: chunked, identity" "Transfer-Encoding: [\"chunked\"]" "Transfer-Encoding: chunked\r\nTransfer-Encoding: identity" ) for HDR in "${OBFUSCATIONS[@]}"; do CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \ -X POST "$TARGET/" -H "$HDR" --data-raw 'test' 2>/dev/null) echo " [$CODE] $HDR" | tee -a "$OUT_FILE" done # Tab-separated TE CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \ -X POST "$TARGET/" -H $'Transfer-Encoding:\tchunked' --data-raw 'test' 2>/dev/null) echo " [$CODE] Transfer-Encoding:chunked" | tee -a "$OUT_FILE" echo "" | tee -a "$OUT_FILE" # ── 5. HTTP/3 / QUIC ───────────────────────────────────────────────────────── echo "--- HTTP/3 / QUIC (port 443 UDP) ---" | tee -a "$OUT_FILE" if curl --version 2>&1 | grep -qiE 'HTTP3|h3|quic'; then echo " curl has HTTP/3 support — testing directly" | tee -a "$OUT_FILE" CODE=$(curl -sk --http3 -o /dev/null -w '%{http_code}' --max-time 10 "$TARGET/" 2>/dev/null) echo " [$CODE] HTTP/3 GET / (should be 200 or 403)" | tee -a "$OUT_FILE" # H3 CL.TE attempt CODE=$(curl -sk --http3 -o /dev/null -w '%{http_code}' --max-time 10 \ -X POST "$TARGET/" \ -H 'Transfer-Encoding: chunked' -H 'Content-Length: 3' \ --data-raw $'1\r\nA\r\n0\r\n\r\n' 2>/dev/null) echo " [$CODE] HTTP/3 CL.TE (should reject per RFC 9114)" | tee -a "$OUT_FILE" else echo " [SKIP] curl not built with HTTP/3 — using alt-svc discovery" | tee -a "$OUT_FILE" # Check if server advertises h3 via Alt-Svc header ALT_SVC=$(curl -sk --http2 -I -o /dev/null -D - --max-time 10 "$TARGET/" 2>/dev/null | \ grep -i 'alt-svc:' | head -1) if echo "$ALT_SVC" | grep -qi 'h3'; then echo " [OK] Server advertises HTTP/3 via Alt-Svc: $ALT_SVC" | tee -a "$OUT_FILE" echo " [SKIP] H3 smuggling test requires curl with HTTP/3 support" | tee -a "$OUT_FILE" else echo " [INFO] Alt-Svc: ${ALT_SVC:-not found}" | tee -a "$OUT_FILE" fi fi echo "" | tee -a "$OUT_FILE" # ── 6. WebTransport (QUIC port 4433) ───────────────────────────────────────── echo "--- WebTransport / QUIC port 4433 ---" | tee -a "$OUT_FILE" # TCP probe (should get nothing — WebTransport is UDP/QUIC) WT_TCP=$(timeout 4 bash -c "echo >/dev/tcp/$HOST/${QUIC_PORT}" 2>&1 && echo "open" || echo "closed") echo " Port 4433 TCP: $WT_TCP (QUIC is UDP — TCP closed is expected)" | tee -a "$OUT_FILE" # HTTP over TCP to QUIC port — should be rejected CODE=$(curl -sk --max-time 5 -o /dev/null -w '%{http_code}' "https://$HOST:${QUIC_PORT}/speedtest" 2>/dev/null) echo " [$CODE] HTTPS/TCP to :4433/speedtest (000 = correct — QUIC/UDP only)" | tee -a "$OUT_FILE" # If HTTP/3 available, test QUIC directly if curl --version 2>&1 | grep -qiE 'HTTP3|h3|quic'; then CODE=$(curl -sk --http3 -o /dev/null -w '%{http_code}' --max-time 10 \ "https://$HOST:${QUIC_PORT}/speedtest" 2>/dev/null) echo " [$CODE] HTTP/3/QUIC to :4433/speedtest" | tee -a "$OUT_FILE" fi echo "" | tee -a "$OUT_FILE" # ── 7. Desync via Header Priority (H2 Continuation flood) ──────────────────── echo "--- HTTP/2 Continuation Flood (CVE-2023-44487 / Rapid Reset variant) ---" | tee -a "$OUT_FILE" # Send 20 rapid requests with RESET to probe for rapid-reset DoS surface # (benign probe — just measures if server handles rapid reconnects without crash) RESET_CODES="" for i in $(seq 1 10); do C=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 3 "$TARGET/" 2>/dev/null) RESET_CODES="$RESET_CODES $C" done echo " 10 rapid HTTP/2 requests: $RESET_CODES" | tee -a "$OUT_FILE" if echo "$RESET_CODES" | grep -qv '200\|403\|429'; then echo " [WARN] Unexpected response codes detected" | tee -a "$OUT_FILE" else echo " [OK] Server stable under rapid HTTP/2 reconnects" | tee -a "$OUT_FILE" fi echo "" | tee -a "$OUT_FILE" echo "=== 07. HTTP Smuggling COMPLETE ===" | tee -a "$OUT_FILE"