The cloud is everything. Organizations have either moved completely to the cloud, have a hybrid approach, or are actively planning a cloud strategy. Penetration testers have always had to provide their services anywhere the client’s environment takes them. This often leads to finding vital information and credentials for their cloud provider of choice. With Amazon Web Services (AWS) being the number one player, finding AWS keys has become very common. But how does one utilize that recon information to further their attacks? Pivoting into these machines or querying the exposed services would make for a much more thorough assessment, but what type of access is available once there? That’s why we created an AWS Attack Library (WeirdAAL).
WeirdAAL has two goals related to the AWS keys you find, procure, or need to test. First, answer the “what can I do with this AWS key pair” from a blackbox perspective. Secondly, be a repository of useful functions, both offensive and defensive, to interact with AWS Services. This article is meant to be a basic tutorial to get you started.
Background on WeirdAAL
With fancy web GUIs, APIs and scripting, cloud providers have made it incredibly easy to spin up new virtual machines. So much so that it has allowed for organizations to massively increase their DevOps capabilities, often without the proper controls in place to manage this new attack surface. Ken Johnson and I have given a few talks [1][2][3] around common DevOps mistakes that can be made. Each of these talks contained sections on how AWS keys can become compromised.
The problem with finding yourself with an AWS key pair is that it can be quite difficult to have a full accounting of what AWS services the key pair has access to without privileges for the client’s Identity and Access Management (IAM) system. During a penetration test (especially black box), you’ll most certainly not have this level of access, therefore answering the “what can I do with this key” question becomes important. WeirdAAL is designed to answer this question.
The Basics of WeirdAAL
Boto3, the AWS SDK for Python, currently supports 136 AWS services. WeirdAAL uses python3 and the boto3 library to ask each service the “do I have permissions to interact with this service” question against functions that take no arguments. Of the 136 services, approximately 125 have at least one of these types of functions.
Getting started is fairly straightforward. Clone the repository, create your python3 virtual environment and install the requirements. Once things are installed, copy the env.sample file to .env and populate it with the AWS key pair you’re testing. The file expects the same format as a normal .aws/credentials file.
Figure 1: sample AWS key in .env file
WeirdAAL overwrites the local AWS_SHARED_CREDENTIALS_FILE environment variable with the contents of the .env file. By using the .aws/credentials file format and boto3, WeirdAAL also natively supports all types of AWS key pairs including key pairs with STS tokens.
After you have set the key, it’s fairly easy to get going. WeirdAAL has two command line requirements: –m for the module you want to run and –t for the target name. Multiple keys can exist under the same target.
$ python3 weirdAAL.py usage: weirdAAL.py [-h] -m MODULE -t TARGET [-a ARGUMENTS] [-l] [-v] weirdAAL.py: error: the following arguments are required: -m/--module, -t/--target
There are currently 28 modules from which to choose, and all are listed in the Wiki section of the GitHub repo. Some modules take arguments, and those can be passed with the –a flag. The first module you’ll want to run is the recon_all module. This module will attempt to interact with those aforementioned AWS services and attempt to enumerate what services the key has access to.
Examples
If the key pair is invalid, WeirdAAL will let you know.
$ python3 weirdAAL.py -m recon_all -t demo The AWS Access Keys are not valid/active Check the above error message and fix to use weirdAAL
If the key is a root key, you’ll have access to everything. If you have IAM access, WeirdAAL will also attempt to check the Multi-Factor Authentication (MFA) status on accounts, whether they have IAM console access, and if it looks like those accounts can be reset or not (if you want to get heavy handed).
$ python3 weirdAAL.py -m recon_all -t demo Account Id: 54889XXXXXXX Root Key!!! [or IAM access] Printing Account Summary { 'AccessKeysPerUserQuota': 2, 'AccountAccessKeysPresent': 1, 'AccountMFAEnabled': 0, 'AccountSigningCertificatesPresent': 1, 'AssumeRolePolicySizeQuota': 2048, 'AttachedPoliciesPerGroupQuota': 10, 'AttachedPoliciesPerRoleQuota': 10, 'AttachedPoliciesPerUserQuota': 10, 'GroupPolicySizeQuota': 5120, 'Groups': 1, 'GroupsPerUserQuota': 10, 'GroupsQuota': 300, 'InstanceProfiles': 3, 'InstanceProfilesQuota': 1000, 'MFADevices': 0, 'MFADevicesInUse': 0, 'Policies': 1, 'PoliciesQuota': 1500, 'PolicySizeQuota': 6144, 'PolicyVersionsInUse': 20, 'PolicyVersionsInUseQuota': 10000, 'Providers': 0, 'RolePolicySizeQuota': 10240, 'Roles': 12, 'RolesQuota': 1000, 'ServerCertificates': 0, 'ServerCertificatesQuota': 20, 'SigningCertificatesPerUserQuota': 2, 'UserPolicySizeQuota': 2048, 'Users': 5, 'UsersQuota': 5000, 'VersionsPerPolicyQuota': 5} Printing Users [ { 'Arn': 'arn:aws:iam::5488XXXXXXXX:user/bin', 'CreateDate': datetime.datetime(2018, 5, 27, 19, 43, 53, tzinfo=tzutc()), 'PasswordLastUsed': datetime.datetime(2018, 5, 27, 19, 44, 48, tzinfo=tzutc()), 'Path': '/', 'UserId': 'AIDA-REMOVED', 'UserName': 'bin'}, { 'Arn': 'arn:aws:iam::54889XXXXXXX:user/s3', 'CreateDate': datetime.datetime(2018, 2, 3, 1, 5, 26, tzinfo=tzutc()), 'PasswordLastUsed': datetime.datetime(2018, 6, 2, 3, 46, 8, tzinfo=tzutc()), 'Path': '/', 'UserId': 'AIDA-REMOVED', 'UserName': 's3'}] Checking for console access User bin likely has console access and the password can be reset :-) Checking for MFA on account [] User s3 likely has console access and the password can be reset :-) Checking for MFA on account [] ### Enumerating ACM Permissions ### ListCertificates IS allowed [+] acm Actions allowed are [+] ['ListCertificates'] ### Enumerating AWS Certificate Manager Private Certificate Authority (ACM-PCA) Permissions ### ListCertificateAuthorities IS allowed [+] acm-pca Actions allowed are [+] ['ListCertificateAuthorities'] … SNIP
Generally you’ll find accounts that have access to a handful of services like this one:
$ python3 weirdAAL.py -m recon_all -t demo Account Id: 1928XXXXXXXXX AKIAIG7-REMOVED : Is NOT a root key ### Enumerating ACM Permissions ### An error occurred (AccessDeniedException) when calling the ListCertificates operation: User: arn:aws:iam::1928XXXXXXXXX:user/python is not authorized to perform: acm:ListCertificates [-] No acm actions allowed [-] ### Enumerating AWS Certificate Manager Private Certificate Authority (ACM-PCA) Permissions ### An error occurred (AccessDeniedException) when calling the ListCertificateAuthorities operation: User: arn:aws:iam::1928XXXXXXXXX:user/python is not authorized to perform: acm-pca:ListCertificateAuthorities [-] No acm-pca actions allowed [-] … SNIP … ### Enumerating Autoscaling Permissions ### DescribeAccountLimits IS allowed DescribeAdjustmentTypes IS allowed DescribeAutoScalingInstances IS allowed DescribeAutoScalingGroups IS allowed DescribeLaunchConfigurations IS allowed DescribeScheduledActions IS allowed DescribeTags IS allowed DescribeTerminationPolicyTypes IS allowed DescribePolicies IS allowed [+] autoscaling Actions allowed are [+] ['DescribeAccountLimits', 'DescribeAdjustmentTypes', 'DescribeAutoScalingInstances', 'DescribeAutoScalingGroups', 'DescribeLaunchConfigurations', 'DescribeScheduledActions', 'DescribeTags', 'DescribeTerminationPolicyTypes', 'DescribePolicies'] …SNIP… ### Enumerating DynamoDB Permissions ### ListTables IS allowed DescribeLimits IS allowed ListBackups IS allowed ListGlobalTables IS allowed [+] dynamodb Actions allowed are [+] ['ListTables', 'DescribeLimits', 'ListBackups', 'ListGlobalTables'] ### Enumerating DynamoDBStreamsPermissions ### ListStreams IS allowed [+] dynamodbstreams Actions allowed are [+] ['ListStreams'] …SNIP… ### Enumerating Amazon WorkMail Permissions ### An error occurred (AccessDeniedException) when calling the ListOrganizations operation: User: arn:aws:iam::1928XXXXXXXXX:user/python is not authorized to perform: workmail:ListOrganizations [-] No workmail actions allowed [-]
Once recon_all is complete, you can list the identified services with the list_services_by_key module.
$ python3 weirdAAL.py -m list_services_by_key -t demo Services enumerated for AKIAIG7-REMOVED autoscaling:DescribeAccountLimits autoscaling:DescribeAdjustmentTypes autoscaling:DescribeAutoScalingInstances autoscaling:DescribeAutoScalingGroups autoscaling:DescribeLaunchConfigurations autoscaling:DescribeScheduledActions autoscaling:DescribeTags autoscaling:DescribeTerminationPolicyTypes autoscaling:DescribePolicies cloudwatch:ListMetrics cloudwatch:DescribeAlarmHistory cloudwatch:DescribeAlarms datapipeline:ListPipelines dynamodb:ListTables dynamodb:DescribeLimits dynamodb:ListBackups dynamodb:ListGlobalTables dynamodbstreams:ListStreams ec2:DescribeInstances ec2:DescribeInstanceStatus ec2:DescribeImages ec2:CreateImage ec2:DescribeVolumes ec2:CreateVolume ec2:DescribeSnapshots ec2:DescribeAccountAttributes ec2:DescribeAddresses ---SNIP--- elasticbeanstalk:DescribeApplications elasticbeanstalk:DescribeApplicationVersions elasticbeanstalk:DescribeEnvironments elasticbeanstalk:DescribeEvents elb:DescribeLoadBalancers elb:DescribeAccountLimits elbv2:DescribeLoadBalancers elbv2:DescribeAccountLimits elbv2:DescribeTargetGroups emr:ListClusters emr:ListSecurityConfigurations iam:ListRoles lambda:ListFunctions lambda:GetAccountSettings lambda:ListEventSourceMappings lex-models:GetBots lex-models:GetIntents opsworks:DescribeStacks rds:DescribeDBInstances rds:DescribeDBSecurityGroups rds:DescribeDBSnapshots rds:DescribeDBClusters rds:DescribeDBClusterSnapshots rds:DescribeAccountAttributes rds:DescribeEvents rds:DescribeReservedDBInstances route53:ListGeoLocations s3:ListBuckets sns:ListSubscriptions sns:ListTopics sts:GetCallerIdentity
Getting Creative
At this point, you can start to pivot and enumerate more services using the additional WeirdAAL modules. In this case the account has EC2 privileges, DynamoDB, RDS, S3, etc. permissions, and you’d want to start running those additional modules against the various services to see what data or access those services can provide to you. For example we might check out the S3 portion of the wiki to see what functionality exists.
Listing buckets seems like a good place to start:
$ python3 weirdAAL.py -m s3_list_buckets –t demo #### Trying to list s3 bucketsfor AKIAIG7-REMOVED #### 1234cloudtrail1234 bucketwithpolicy1234 config-bucket-192854696198 subdomain-takeover-poc
Further peeking into one of the buckets:
$ python3 weirdAAL.py -m s3_list_bucket_contents -a "subdomain-takeover-poc" -t demo #### Attempting to list s3 bucket contents for subdomain-takeover-poc #### index.html subdomain-takeover-POC.html upload.txt
We might even want to download a file:
$ python3 weirdAAL.py -m s3_download_file -a 'subdomain-takeover-poc','upload.txt' -t demo file downloaded to: /Users/CG/Documents/pentest/weirdAAL-updated/loot/upload.txt lookupfailed-2:weirdAAL-updated CG$ more loot/upload.txt hello from the internet
At this point, you might be thinking why is this better than the AWS CLI? Excellent question! Because WeirdAAL uses python and boto3, doing things across multiple regions or multiple instances becomes much easier than piping awscli output to other things.
To back up this claim, I’d suggest you check out the ec2_get_console_output_all and ec2_get_console_output_all_region modules to get an idea of what you can do when you need to run a command against all instances in a region or all instances against all regions.
Example output is below:
Figure 2: Running the get_console_output_all_region module against all instances in a specific region
If you are unsure what modules exist you can check out the WeirdAAL Wiki.
All the modules are documented to include sample command line usage including the potential arguments required. Similar to the following screenshots:
Figure 3: EC2 module documentation
Figure 4: EC2 module documentation showing modules that require arguments
Use It
After consuming the content of this new article, hopefully it was enough to pique your interest. Once again, you can check out WeirdAAL at the GitHub Repository. Issues, comments and suggestions are welcome.
The most recent presentation on WeirdAAL that shows many more examples and awesome Weird Al memes can be found on SlideShare.
We’d also love to hear your feedback on the article and ways in which WeirdAAL has helped you during your own pen tests. Please add your comments below and also consider contributing to the project.
Chris Gates, Sr Security Engineer, has been breaking things professionally for over a decade via Network & Web Application Penetration Testing, Red Teaming & Adversarial Simulation. These days Chris splits his time being both a breaker and fixer. Chris is the author of Metta, a tool for adversarial simulation and contributes to other open source projects. In the past he has spoken at the United States Military Academy, BlackHat, DefCon, Wild West Hacking Fest, Toorcon, Brucon, Troopers, SOURCE Boston, Derbycon, LasCon, HashDays, HackCon, Bsides ATL, IT Defense, OWASP AppSec DC, and Devops Days. Chris is also a cofounder of NoVAHackers. Blog: carnal0wnage.attackresearch.com Twitter: @carnal0wnage Talks: https://www.slideshare.net/chrisgates/
Tagged: aws, cloud, gates, highlight, pentest, python, tutorial, weirdaal