Enumerate Secrets in AWS
Tips and tricks for discovering secrets in AWS
Secrets Enumeration
Plaintext or hard-coded secrets can be found in many resources throughout AWS if there is poor hygiene in the management of secrets.
CloudFormation
CloudFormation is an AWS infrastructure-as-code solution written in JSON or YAML
# provides details of the stacks including parameter key/values
aws --region us-east-1 cloudformation describe-stacks
# view the source code for a specific stack
aws --region us-east-1 cloudformation get-template --stack-name execution | jq -r '.TemplateBody'
EC2 Instances
User-data
Secrets can end up hard-coded in EC2 user-data and can easily be discovered either with the action
ec2:DescribeInstanceAttribute
or by querying the IMDS service
AWS CLI
# using the aws cli
aws --region us-west-2 ec2 describe-instance-attribute --attribute userData --instance-id i-0aa2215a0322ec638 | jq -r '.UserData.Value' | base64 --decode
# output
echo "aws_access_key_id = AKIAZxxxxxxxxxx" >> ~/ec2-user/.aws/credentials
echo "aws_secret_access_key = T2a4SjDnqsPUxxxxxxx" >> ~/ec2-user/.aws/credentials
IMDSv1
# querying IMDSv1 (code execution on the instance is required)
curl http://169.254.169.254/latest/user-data
# output
echo "aws_access_key_id = AKIAZxxxxxxxxxx" >> ~/ec2-user/.aws/credentials
echo "aws_secret_access_key = T2a4SjDnqsPUxxxxxxx" >> ~/ec2-user/.aws/credentials
IMDSv2
Version 2 of IMDS requires obtaining a token first
# querying IMDSv2 (code execution on the instance is required)
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/user-data
# output
echo "aws_access_key_id = AKIAZxxxxxxxxxx" >> ~/ec2-user/.aws/credentials
echo "aws_secret_access_key = T2a4SjDnqsPUxxxxxxx" >> ~/ec2-user/.aws/credentials
EC2 Launch Templates
EC2 Launch Templates allow for defining consistent configurations (Security Groups, IMDS, Instance types, User Data, etc.) for any EC2 that uses the template
So User Data can also be found in the templates
# find launch templates
aws --region us-west-2 ec2 describe-launch-templates
{
"LaunchTemplates": [
{
"LaunchTemplateId": "lt-12k4n9f933873nkdn",
"LaunchTemplateName": "my-ec2-template",
"CreateTime": "2025-1-03T11:32:25+00:00",
"CreatedBy": "arn:aws:iam::111111111111:dev_user",
"DefaultVersionNumber": 1,
"LatestVersionNumber": 1
}
]
}
# view the launch template
aws --region us-west-2 ec2 describe-launch-template-versions --launch-template-id lt-12k4n9f933873nkdn --versions 1
{
"LaunchTemplateVersions": [
{
"LaunchTemplateId": "lt-12k4n9f933873nkdn",
"LaunchTemplateName": "my-ec2-template",
"VersionNumber": 1,
"VersionDescription": "my-ec2-template",
"CreateTime": "2025-1-03T11:32:25+00:00",
"CreatedBy": "arn:aws:iam::111111111111:dev_user",
"DefaultVersion": true,
"LaunchTemplateData": {
"UserData": "ZWNobyAiYXdzX2FjY2Vzc19rZXlfaWQgPSBBS0lBWnh4eHh4eHh4eHgiID4+IH4vZWMyLXVzZXIvLmF3cy9jcmVkZW50aWFscwplY2hvICJhd3Nfc2VjcmV0X2FjY2Vzc19rZXkgPSBUMmE0U2pEbnFzUFV4eHh4eHh4IiA+PiB+L2VjMi11c2VyLy5hd3MvY3JlZGVudGlhbHM="
}
}
# decode the user data
aws --region us-west-2 ec2 describe-launch-template-versions --launch-template-id lt-12k4n9f933873nkdn --versions 1 | jq -r '.LaunchTemplateVersions[].LaunchTemplateData.UserData' | base64 --decode
# output
echo "aws_access_key_id = AKIAZxxxxxxxxxx" >> ~/ec2-user/.aws/credentials
echo "aws_secret_access_key = T2a4SjDnqsPUxxxxxxx" >> ~/ec2-user/.aws/credentials
EBS Snapshots
EBS Snapshots are backups of EC2 instances and may have secrets and credentials stored on them
See also EBS Snapshots
EBS snapshots are regional so make sure to check each region
# find snapshots in your account
aws --region us-west-2 ec2 describe-snapshots --owner-ids self
Lambda
Environment Variables
Environment variables are commonly used for storing data used by the lambda function
# list all functions and return their env vars
aws --region us-east-1 lambda list-functions | jq -r '.Functions[].Environment.Variables'
{
"ACCESS_KEY_ID": "AKIA.....",
"SECRET_ACCESS_KEY": "SetQ...."
}
{
"RDS_HOST": "mydatabase.sflwnf3l22n3.us-east-1.rds.amazonaws.com",
"RDS_PASSWORD": "superSecret",
"RDS_USER": "root"
}
Functions
The code of the function may also contain information
# download a function's code
aws --region us-east-1 lambda get-function --function-name myfunction --query 'Code.Location' --output text | xargs curl -o lambda_func.zip
unzip lambda_func.zip
RDS Snapshots
RDS Snapshots are backups of RDS instances and may contain valuable data
See also RDS Snapshots
RDS snapshots are regional so make sure to check each region
# find snapshots in your account
aws rds describe-db-snapshots --region us-west-2
Secrets Manager
# list secrets
aws --region us-west-2 secretsmanager list-secrets
{
"SecretList": [
{
"ARN": "arn:aws:secretsmanager:us-west-2:111111111111:secret:production_database_password-BOcLnM",
"Name": "production_database_password",
"LastChangedDate": "2025-01-03T18:43:58.802000-07:00",
"Tags": [],
"SecretVersionsToStages": {
"2ad27539-26a6-40fc-b412-774e749e6d80": [
"AWSCURRENT"
]
},
"CreatedDate": "2025-01-03T18:43:58.491000-07:00"
}
]
}
# get secret (can only decrypt if you have permission to the kms key)
aws --region us-west-2 secretsmanager get-secret-value --secret-id production_database_password
{
"ARN": "arn:aws:secretsmanager:us-west-2:111111111111:secret:production_database_password-BOcLnM",
"Name": "production_database_password",
"VersionId": "2ad27539-26a6-40fc-b412-774e749e6d80",
"SecretString": "{\"database_password\":\"l;3lj2l3nr23nrlnslfio3\"}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2025-01-03T18:43:58.798000-07:00"
}
SSM
Documents
SSM Documents allow you to run automations and commands on EC2s and may contain sensitive data
See also SSM Documents
# find ssm documents in your account
aws ssm list-documents | jq -r '.DocumentIdentifiers[] | select(.Owner | contains("111111111111")) | (.Name)'
Parameters
You can reference Systems Manager parameters in your scripts, commands, SSM documents, and configuration and automation workflows
# list ssm parameters
aws --region us-west-2 ssm describe-parameters
{
"Parameters": [
{
"Name": "uninstall_key",
"ARN": "arn:aws:ssm:us-west-2:111111111111:parameter/uninstall_key",
"Type": "SecureString",
"KeyId": "alias/aws/ssm",
"LastModifiedDate": "2025-01-03T18:36:21.900000-07:00",
"LastModifiedUser": "arn:aws:iam::111111111111:user/dev_user",
"Description": "key used to uninstall our EDR",
"Version": 1,
"Tier": "Standard",
"Policies": [],
"DataType": "text"
}
]
}
# get parameter (can only decrypt if you have permission to the kms key)
aws --region us-west-2 ssm get-parameter --name uninstall_key --with-decryption
{
"Parameter": {
"Name": "uninstall_key",
"Type": "SecureString",
"Value": "34n34n393nndg0sng4",
"Version": 1,
"LastModifiedDate": "2025-01-03T18:36:21.900000-07:00",
"ARN": "arn:aws:ssm:us-west-2:111111111111:parameter/uninstall_key",
"DataType": "text"
}
}
Terraform State
While not an AWS resource, Terraform State files are commonly stored in AWS S3 buckets
If the data is not encrypted and/or you have access to decrypt the data, Terraform State files often contain secrets, credentials, and information about the cloud environment
# example of downloading terraform state from file
aws s3 cp s3://myterraformstatebucket/prod/prod-account-a/terraform.tfstate .
# output state to json to see sensitive values
terraform show -json | jq
{
"format_version": "1.0",
"terraform_version": "1.5.7",
"values": {
"root_module": {
"resources": [
{
"address": "aws_iam_access_key.admin",
"mode": "managed",
"type": "aws_iam_access_key",
"name": "admin",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"create_date": "2025-01-04T01:17:57Z",
"encrypted_secret": null,
"encrypted_ses_smtp_password_v4": null,
"id": "AKIA[...]",
"key_fingerprint": null,
"pgp_key": null,
"secret": "dfY0XUrA[...]",
"ses_smtp_password_v4": "BBPzJ[...]",
"status": "Active",
"user": "admin"
},
"sensitive_values": {
"secret": true,
"ses_smtp_password_v4": true
}
}
]
}
}
}
# you can also just read the state file since it's json
cat terraform.tfstate | jq
Last updated
Was this helpful?