| 1 |
| 2 |
| 3 |
| 4 |
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 5 |
source "$SCRIPT_DIR/../config.sh" |
| 6 |
OUT="$OUT/cloud_infrastructure" |
| 7 |
mkdir -p "$OUT" |
| 8 |
|
| 9 |
echo '=== CLOUD & INFRASTRUCTURE SECURITY ===' | tee "$OUT/summary.txt" |
| 10 |
|
| 11 |
BROWSER="$BROWSER_UA" |
| 12 |
DOMAIN="${TARGET_HOST}" |
| 13 |
|
| 14 |
| 15 |
echo '' | tee -a "$OUT/summary.txt" |
| 16 |
echo '--- Cloud Metadata via SSRF ---' | tee -a "$OUT/summary.txt" |
| 17 |
METADATA_URLS=( |
| 18 |
"http://169.254.169.254/latest/meta-data/" |
| 19 |
"http://169.254.169.254/latest/meta-data/iam/security-credentials/" |
| 20 |
"http://metadata.google.internal/computeMetadata/v1/" |
| 21 |
"http://169.254.169.254/metadata/instance?api-version=2021-02-01" |
| 22 |
"http://100.100.100.200/latest/meta-data/" |
| 23 |
) |
| 24 |
for meta_url in "${METADATA_URLS[@]}"; do |
| 25 |
enc=$(printf '%s' "$meta_url" | python3 -c "import sys,urllib.parse; print(urllib.parse.quote(sys.stdin.read().strip()))") |
| 26 |
for param in "url" "redirect" "callback" "webhook" "target" "endpoint" "fetch"; do |
| 27 |
resp=$(curl -sk -o "$OUT/meta_resp.tmp" -w '%{http_code}' --max-time 8 -A "$BROWSER" \ |
| 28 |
"$API_TARGET/encrypt?$param=$enc") |
| 29 |
grep -qi 'ami-id\|instance-id\|security-credentials\|computeMetadata\|access_key' "$OUT/meta_resp.tmp" && \ |
| 30 |
echo " [!!!] CLOUD METADATA SSRF via ?$param: $meta_url" | tee -a "$OUT/summary.txt" |
| 31 |
done |
| 32 |
done |
| 33 |
echo " Cloud metadata SSRF sweep complete" | tee -a "$OUT/summary.txt" |
| 34 |
|
| 35 |
| 36 |
echo '' | tee -a "$OUT/summary.txt" |
| 37 |
echo '--- S3 Bucket Enumeration ---' | tee -a "$OUT/summary.txt" |
| 38 |
BUCKET_NAMES=( |
| 39 |
"pqcrypta" "pqcrypta-assets" "pqcrypta-backup" "pqcrypta-logs" |
| 40 |
"pqcrypta-uploads" "pqcrypta-static" "pqcrypta-prod" "pqcrypta-dev" |
| 41 |
"pqcrypta-data" "pqcrypta-keys" "pqcrypta-config" |
| 42 |
"philibert" "philibert-assets" "philibert-backup" |
| 43 |
"pqc-assets" "pqc-backup" "pqc-uploads" |
| 44 |
) |
| 45 |
for bucket in "${BUCKET_NAMES[@]}"; do |
| 46 |
resp=$(curl -sk -o "$OUT/s3_check.tmp" -w '%{http_code}' --max-time 8 \ |
| 47 |
"https://$bucket.s3.amazonaws.com/") |
| 48 |
case "$resp" in |
| 49 |
200) echo " [!!!] S3 BUCKET PUBLIC: $bucket" | tee -a "$OUT/summary.txt" ;; |
| 50 |
403) echo " [PASS] $bucket โ exists but access denied (403)" | tee -a "$OUT/summary.txt" ;; |
| 51 |
404) echo " [INFO] $bucket โ not found (404)" ;; |
| 52 |
*) echo " [INFO] $bucket โ $resp" ;; |
| 53 |
esac |
| 54 |
done |
| 55 |
|
| 56 |
| 57 |
echo '' | tee -a "$OUT/summary.txt" |
| 58 |
echo '--- Exposed Cloud Credentials ---' | tee -a "$OUT/summary.txt" |
| 59 |
CRED_PATHS=( |
| 60 |
"/.aws/credentials" "/.aws/config" |
| 61 |
"/.gcloud/credentials.json" "/.gcloud/application_default_credentials.json" |
| 62 |
"/service-account.json" "/credentials.json" "/serviceaccount.json" |
| 63 |
"/.azure/credentials" "/azure-credentials.json" |
| 64 |
"/.kube/config" "/kubeconfig" "/kube-config.yaml" |
| 65 |
"/terraform.tfstate" "/terraform.tfstate.backup" |
| 66 |
"/.vault-token" "/vault-token" |
| 67 |
) |
| 68 |
for path in "${CRED_PATHS[@]}"; do |
| 69 |
resp=$(curl -sk -o "$OUT/cred_check.tmp" -w '%{http_code}' --max-time 8 -A "$BROWSER" "$TARGET$path") |
| 70 |
if [ "$resp" = "200" ]; then |
| 71 |
size=$(wc -c < "$OUT/cred_check.tmp") |
| 72 |
echo " [!!!] CREDENTIAL FILE EXPOSED: $path ($size bytes)" | tee -a "$OUT/summary.txt" |
| 73 |
else |
| 74 |
echo " [PASS] $path โ $resp" |
| 75 |
fi |
| 76 |
done |
| 77 |
|
| 78 |
| 79 |
echo '' | tee -a "$OUT/summary.txt" |
| 80 |
echo '--- Kubernetes API Exposure ---' | tee -a "$OUT/summary.txt" |
| 81 |
K8S_PATHS=( |
| 82 |
"/api/v1/namespaces" "/api/v1/pods" "/api/v1/secrets" |
| 83 |
"/apis/apps/v1/deployments" "/.well-known/kubeconfig" |
| 84 |
) |
| 85 |
for path in "${K8S_PATHS[@]}"; do |
| 86 |
resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER" "$TARGET$path") |
| 87 |
[ "$resp" = "200" ] && echo " [!!!] K8s API EXPOSED: $path" || echo " [PASS] $path โ $resp" | tee -a "$OUT/summary.txt" |
| 88 |
done |
| 89 |
| 90 |
for port in 6443 8443 10250 10255 2379 2380; do |
| 91 |
resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 5 "https://${TARGET_HOST}:$port/") |
| 92 |
[ "$resp" = "200" ] && echo " [!!!] K8s port OPEN: $port" || echo " [PASS] port $port โ $resp" | tee -a "$OUT/summary.txt" |
| 93 |
done |
| 94 |
|
| 95 |
| 96 |
echo '' | tee -a "$OUT/summary.txt" |
| 97 |
echo '--- Environment Variable Leakage ---' | tee -a "$OUT/summary.txt" |
| 98 |
for ep in "/env" "/environment" "/config" "/settings" "/debug/env" "/api/env" "/info" "/actuator/env"; do |
| 99 |
resp=$(curl -sk -o "$OUT/env_check.tmp" -w '%{http_code}' --max-time 8 -A "$BROWSER" "$API_TARGET$ep") |
| 100 |
if [ "$resp" = "200" ]; then |
| 101 |
grep -qi 'DATABASE_URL\|SECRET_KEY\|AWS_\|PRIVATE_KEY\|PASSWORD\|TOKEN' "$OUT/env_check.tmp" && \ |
| 102 |
echo " [!!!] SENSITIVE ENV VARS EXPOSED at $ep" || echo " [WARN] $ep is open (200) โ check content" | tee -a "$OUT/summary.txt" |
| 103 |
else |
| 104 |
echo " [PASS] $ep โ $resp" |
| 105 |
fi |
| 106 |
done |
| 107 |
|
| 108 |
| 109 |
echo '' | tee -a "$OUT/summary.txt" |
| 110 |
echo '--- DNS Security Records ---' | tee -a "$OUT/summary.txt" |
| 111 |
dig +short TXT "_dmarc.$DOMAIN" | grep -qi 'v=DMARC1' && echo " [PASS] DMARC present" || echo " [WARN] DMARC missing" | tee -a "$OUT/summary.txt" |
| 112 |
dig +short TXT "$DOMAIN" | grep -qi 'v=spf1' && echo " [PASS] SPF present" || echo " [WARN] SPF missing" | tee -a "$OUT/summary.txt" |
| 113 |
dig +short CAA "$DOMAIN" | grep -q '.' && echo " [PASS] CAA record present: $(dig +short CAA $DOMAIN)" || echo " [WARN] No CAA record" | tee -a "$OUT/summary.txt" |
| 114 |
dig +short DNSKEY "$DOMAIN" | grep -q '.' && echo " [PASS] DNSSEC enabled" || echo " [INFO] DNSSEC not detected (may be at registrar)" | tee -a "$OUT/summary.txt" |
| 115 |
|
| 116 |
| 117 |
echo '' | tee -a "$OUT/summary.txt" |
| 118 |
echo '--- Security.txt Presence ---' | tee -a "$OUT/summary.txt" |
| 119 |
for secpath in "/.well-known/security.txt" "/security.txt"; do |
| 120 |
resp=$(curl -sk -o "$OUT/security_txt.tmp" -w '%{http_code}' --max-time 8 -A "$BROWSER" "$TARGET$secpath") |
| 121 |
if [ "$resp" = "200" ]; then |
| 122 |
echo " [PASS] security.txt found at $secpath" | tee -a "$OUT/summary.txt" |
| 123 |
grep -iE 'Contact:|Expires:|Policy:' "$OUT/security_txt.tmp" | tee -a "$OUT/summary.txt" |
| 124 |
else |
| 125 |
echo " [INFO] $secpath โ $resp (no security.txt)" | tee -a "$OUT/summary.txt" |
| 126 |
fi |
| 127 |
done |
| 128 |
|
| 129 |
cat "$OUT/summary.txt" |
| 130 |
|