| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
|
| 6 |
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 7 |
source "$SCRIPT_DIR/../config.sh" |
| 8 |
OUT_FILE="$OUT/07_advanced_smuggling.txt" |
| 9 |
echo "=== 07. HTTP Request Smuggling ===" | tee "$OUT_FILE" |
| 10 |
echo "Note: pqcrypta-proxy is HTTP/2+TLS only. Port 80 redirects. HTTP/3 via QUIC." | tee -a "$OUT_FILE" |
| 11 |
echo "" | tee -a "$OUT_FILE" |
| 12 |
|
| 13 |
HOST=$(echo "$TARGET" | sed 's|https\?://||' | cut -d/ -f1) |
| 14 |
|
| 15 |
| 16 |
echo "--- HTTP/1.1 Plain (port 80) โ CL.TE via nc ---" | tee -a "$OUT_FILE" |
| 17 |
| 18 |
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" | \ |
| 19 |
nc -w 5 "$HOST" 80 2>&1 | head -5) |
| 20 |
if [ -z "$RESP_NC" ]; then |
| 21 |
echo " [OK] Port 80: no plain HTTP accepted (TCP refused or no response)" | tee -a "$OUT_FILE" |
| 22 |
elif echo "$RESP_NC" | grep -q '301\|302\|308'; then |
| 23 |
echo " [OK] Port 80: redirects to HTTPS (no smuggling surface on plain HTTP)" | tee -a "$OUT_FILE" |
| 24 |
else |
| 25 |
echo " [WARN] Port 80 responded unexpectedly:" | tee -a "$OUT_FILE" |
| 26 |
echo "$RESP_NC" | sed 's/^/ /' | tee -a "$OUT_FILE" |
| 27 |
fi |
| 28 |
|
| 29 |
| 30 |
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" | \ |
| 31 |
nc -w 5 "$HOST" 80 2>&1 | head -3) |
| 32 |
if [ -z "$RESP_TECL" ]; then |
| 33 |
echo " [OK] TE.CL port 80: no response (expected)" | tee -a "$OUT_FILE" |
| 34 |
else |
| 35 |
echo " [INFO] TE.CL port 80 response: $RESP_TECL" | tee -a "$OUT_FILE" |
| 36 |
fi |
| 37 |
echo "" | tee -a "$OUT_FILE" |
| 38 |
|
| 39 |
| 40 |
echo "--- HTTP/2 over TLS (port 443) ---" | tee -a "$OUT_FILE" |
| 41 |
echo " RFC 9113 ยง8.2.2: Transfer-Encoding MUST NOT be used in HTTP/2." | tee -a "$OUT_FILE" |
| 42 |
echo " A compliant HTTP/2 server must reject requests with TE header (STREAM_ERROR)." | tee -a "$OUT_FILE" |
| 43 |
|
| 44 |
| 45 |
CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 10 \ |
| 46 |
-X POST "$TARGET/" \ |
| 47 |
-H 'Transfer-Encoding: chunked' \ |
| 48 |
-H 'Content-Length: 3' \ |
| 49 |
--data-raw $'1\r\nA\r\n0\r\n\r\n') |
| 50 |
if [ "$CODE" = "400" ] || [ "$CODE" = "403" ] || [ "$CODE" = "422" ]; then |
| 51 |
echo " [OK] HTTP/2 CL.TE: [$CODE] server rejected malformed request" | tee -a "$OUT_FILE" |
| 52 |
else |
| 53 |
echo " [INFO] HTTP/2 CL.TE: [$CODE] (curl likely stripped TE header before sending)" | tee -a "$OUT_FILE" |
| 54 |
fi |
| 55 |
|
| 56 |
| 57 |
echo " Testing HTTP/1.1 over TLS (--http1.1 flag):" | tee -a "$OUT_FILE" |
| 58 |
for VARIANT in \ |
| 59 |
"CL.TE:-H 'Content-Length: 13' -H 'Transfer-Encoding: chunked' --data-raw $'0\r\n\r\nSMUGGLED'" \ |
| 60 |
"TE.CL:-H 'Transfer-Encoding: chunked' -H 'Content-Length: 3' --data-raw $'1\r\nA\r\n0\r\n\r\n'"; do |
| 61 |
LABEL="${VARIANT%%:*}" |
| 62 |
ARGS="${VARIANT#*:}" |
| 63 |
CODE=$(eval "curl -sk --http1.1 -o /dev/null -w '%{http_code}' --max-time 10 -X POST \"$TARGET/\" $ARGS" 2>/dev/null) |
| 64 |
echo " [$CODE] HTTP/1.1-over-TLS $LABEL" | tee -a "$OUT_FILE" |
| 65 |
done |
| 66 |
echo "" | tee -a "$OUT_FILE" |
| 67 |
|
| 68 |
| 69 |
echo "--- HTTP/2 TE.TE Obfuscation ---" | tee -a "$OUT_FILE" |
| 70 |
OBFUSCATIONS=( |
| 71 |
"Transfer-Encoding: xchunked" |
| 72 |
"Transfer-Encoding: chunked, identity" |
| 73 |
"Transfer-Encoding: [\"chunked\"]" |
| 74 |
"Transfer-Encoding: chunked\r\nTransfer-Encoding: identity" |
| 75 |
) |
| 76 |
for HDR in "${OBFUSCATIONS[@]}"; do |
| 77 |
CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \ |
| 78 |
-X POST "$TARGET/" -H "$HDR" --data-raw 'test' 2>/dev/null) |
| 79 |
echo " [$CODE] $HDR" | tee -a "$OUT_FILE" |
| 80 |
done |
| 81 |
| 82 |
CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \ |
| 83 |
-X POST "$TARGET/" -H $'Transfer-Encoding:\tchunked' --data-raw 'test' 2>/dev/null) |
| 84 |
echo " [$CODE] Transfer-Encoding:<tab>chunked" | tee -a "$OUT_FILE" |
| 85 |
echo "" | tee -a "$OUT_FILE" |
| 86 |
|
| 87 |
| 88 |
echo "--- HTTP/3 / QUIC (port 443 UDP) ---" | tee -a "$OUT_FILE" |
| 89 |
if curl --version 2>&1 | grep -qiE 'HTTP3|h3|quic'; then |
| 90 |
echo " curl has HTTP/3 support โ testing directly" | tee -a "$OUT_FILE" |
| 91 |
CODE=$(curl -sk --http3 -o /dev/null -w '%{http_code}' --max-time 10 "$TARGET/" 2>/dev/null) |
| 92 |
echo " [$CODE] HTTP/3 GET / (should be 200 or 403)" | tee -a "$OUT_FILE" |
| 93 |
|
| 94 |
| 95 |
CODE=$(curl -sk --http3 -o /dev/null -w '%{http_code}' --max-time 10 \ |
| 96 |
-X POST "$TARGET/" \ |
| 97 |
-H 'Transfer-Encoding: chunked' -H 'Content-Length: 3' \ |
| 98 |
--data-raw $'1\r\nA\r\n0\r\n\r\n' 2>/dev/null) |
| 99 |
echo " [$CODE] HTTP/3 CL.TE (should reject per RFC 9114)" | tee -a "$OUT_FILE" |
| 100 |
else |
| 101 |
echo " [SKIP] curl not built with HTTP/3 โ using alt-svc discovery" | tee -a "$OUT_FILE" |
| 102 |
| 103 |
ALT_SVC=$(curl -sk --http2 -I -o /dev/null -D - --max-time 10 "$TARGET/" 2>/dev/null | \ |
| 104 |
grep -i 'alt-svc:' | head -1) |
| 105 |
if echo "$ALT_SVC" | grep -qi 'h3'; then |
| 106 |
echo " [OK] Server advertises HTTP/3 via Alt-Svc: $ALT_SVC" | tee -a "$OUT_FILE" |
| 107 |
echo " [SKIP] H3 smuggling test requires curl with HTTP/3 support" | tee -a "$OUT_FILE" |
| 108 |
else |
| 109 |
echo " [INFO] Alt-Svc: ${ALT_SVC:-not found}" | tee -a "$OUT_FILE" |
| 110 |
fi |
| 111 |
fi |
| 112 |
echo "" | tee -a "$OUT_FILE" |
| 113 |
|
| 114 |
| 115 |
echo "--- WebTransport / QUIC port 4433 ---" | tee -a "$OUT_FILE" |
| 116 |
| 117 |
WT_TCP=$(timeout 4 bash -c "echo >/dev/tcp/$HOST/${QUIC_PORT}" 2>&1 && echo "open" || echo "closed") |
| 118 |
echo " Port 4433 TCP: $WT_TCP (QUIC is UDP โ TCP closed is expected)" | tee -a "$OUT_FILE" |
| 119 |
|
| 120 |
| 121 |
CODE=$(curl -sk --max-time 5 -o /dev/null -w '%{http_code}' "https://$HOST:${QUIC_PORT}/speedtest" 2>/dev/null) |
| 122 |
echo " [$CODE] HTTPS/TCP to :4433/speedtest (000 = correct โ QUIC/UDP only)" | tee -a "$OUT_FILE" |
| 123 |
|
| 124 |
| 125 |
if curl --version 2>&1 | grep -qiE 'HTTP3|h3|quic'; then |
| 126 |
CODE=$(curl -sk --http3 -o /dev/null -w '%{http_code}' --max-time 10 \ |
| 127 |
"https://$HOST:${QUIC_PORT}/speedtest" 2>/dev/null) |
| 128 |
echo " [$CODE] HTTP/3/QUIC to :4433/speedtest" | tee -a "$OUT_FILE" |
| 129 |
fi |
| 130 |
echo "" | tee -a "$OUT_FILE" |
| 131 |
|
| 132 |
| 133 |
echo "--- HTTP/2 Continuation Flood (CVE-2023-44487 / Rapid Reset variant) ---" | tee -a "$OUT_FILE" |
| 134 |
| 135 |
| 136 |
RESET_CODES="" |
| 137 |
for i in $(seq 1 10); do |
| 138 |
C=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 3 "$TARGET/" 2>/dev/null) |
| 139 |
RESET_CODES="$RESET_CODES $C" |
| 140 |
done |
| 141 |
echo " 10 rapid HTTP/2 requests: $RESET_CODES" | tee -a "$OUT_FILE" |
| 142 |
if echo "$RESET_CODES" | grep -qv '200\|403\|429'; then |
| 143 |
echo " [WARN] Unexpected response codes detected" | tee -a "$OUT_FILE" |
| 144 |
else |
| 145 |
echo " [OK] Server stable under rapid HTTP/2 reconnects" | tee -a "$OUT_FILE" |
| 146 |
fi |
| 147 |
echo "" | tee -a "$OUT_FILE" |
| 148 |
|
| 149 |
echo "=== 07. HTTP Smuggling COMPLETE ===" | tee -a "$OUT_FILE" |
| 150 |
|