The AWS Command Line Interface (AWS CLI) can be used to access AWS resources through a command line utility. To setup the AWS CLI environment, notably the configuration of credentials, the aws configure command may be used.
The aws configure will ask for the following information, that will be stored (in clear-text) in the config and credentials files (by default in a .aws folder in the current's user home directory):
The following commands can be used to retrieve basic information about the AWS account:
# Retrieves information about the IAM entity usage (number of users, groups, roles, etc.).awsiamget-credential-report# Lists the IAM users, with their creation date and password last used timestamp.awsiamlist-users# Lists the users'access keys, with their status and creation date.awsiamlist-access-keys# Lists the IAM groups (collection of IAM users that can be associated with specific permissions).awsiamlist-groups# Retrieves the groups associated with a given user.awsiamlist-groups-for-user--user-name"<USERNAME>"# Lists the IAM roles (an IAM identity that can be associated with specific permissions. An IAM role can be assumed can users allowed to do so).
awsiamlist-roles# Lists all the IAM policies (an IAM policy grants IAM identities - users, groups, or roles - to resources. Permissions in the policies determine whether an IAM principal (user or role) request is allowed or denied.)
awsiamlist-policies# Lists all the IAM policy names and ARN.awsiamlist-policies--query'Policies[*].[PolicyName, Arn]'--outputtext# Lists the metadata of the specified IAM policy.awsiamlist-policies--query'Policies[?PolicyName==`<POLICY_NAME>`]'# Retrieves the IAM policies associated with the specified user / group / role.# Inline IAM policies embedded in the specified IAM user.awsiamlist-user-policies--user-name"<USERNAME>"# IAM policies attached to the specified IAM user.awsiamlist-group-policies--group-name"<GROUPNAME>"awsiamlist-role-policies--role-name"<ROLENAME>"# Lists all the IAM users, groups, and roles that the specified policy is attached to.# Example policy ARN: arn:aws:iam::aws:policy/service-role/AWSApplicationMigrationReplicationServerPolicyawsiamlist-entities-for-policy--policy-arn"<POLICY_ARN>"# Lists the version associated with an IAM policy.awsiamlist-policy-versions--policy-arn"<POLICY_ARN>"# Retrieves the permissions associated with an IAM policy (and policy version).awsiamget-policy-version--policy-arn"<POLICY_ARN>"--version-id"<v1 | POLICY_VERSION_ID>"# Lists the S3 buckets in the account.awss3ls# Retrieves more detailed (compared to s3 ls) information on a bucket (and bucket files).awss3apilist-objects--bucket<BUCKET_NAME># Download / upload files from / to a S3 bucket.# Source / destination for s3://<BUCKET> or local path.awss3cp [--recursive] <SOURCE><DEST>
Automated enumeration with ScoutSuite
Scout Suite leverage the API provided by AWS (as well as other possible Cloud providers) to automatically enumerate the configuration of the account. It can be used to quickly gather information on the attack surface of the AWS account across all regions.
A number of log sources are available in AWS that can be useful for incident response purposes:
AWS logs collection
Multi-regions CloudTrail logs export
The awsCloudTrailDownload.py Python script can be used to download the CloudTrail logs across all regions.
pythonawsCloudTrailDownload.py
Automated logs export with Invictus-AWS
The Invictus-AWS Python script can be used to retrieve information about the environment (service usage and configuration) and export logs from a number of sources (CloudTrail, CloudWatch, S3 Access Logs, ...) to an S3 bucket. Invictus-AWS is region bound.
# Configures the required API access.
aws configure
# Exports the configuration and logs from the specified region (such as "us-east-1").
python3 invictus-aws.py --region=<REGION>
# Downlaods locally the exported / collected elements from invictus-aws.py.
aws s3 cp --recursive s3://<INVICTUS_BUCKET> <EXPORT_FOLDER>
awslogs <get | groups | streams> [--aws-region "<AWS_REGION>"] [--aws-access-key-id "<ACCESS_KEY_ID>"] [--aws-secret-access-key "<ACCESS_KEY_SECRET>"]
# Lists the existing logs groups.awslogsgroups# Lists the streams in the specified log group.awslogsstreams<LOG_GROUP># Retrieves the logs in all or the specified log group / stream.# The start / end filtering support multiple filtering options: DD/MM/YYYY HH:mm, <INT><m | h | d | w>.awslogsget<ALL|LOG_GROUP> <ALL|LOG_GROUP_STREAM> -s<START>-e<END>
CloudTrail logs analysis
CloudTrail key fields
CloudTrail notable API / events
CloudTrail logs manual analysis with jq
The jq utility supports querying JSON formatted data and can be used to select and filter events from CloudTrail exported logs.
The following queries illustrate how jq can be used to select, order, and filter events from CloudTrail JSON logs:
# The following queries assume that the exported events are placed in a top-level "Records" field.# Select the specified fields (eventTime, eventName, awsRegion, sourceIPAddress, and userIdentity).jq'.Records[] | {eventTime, eventName, awsRegion, sourceIPAddress, userIdentity}'<JSON_FILE|*># Sorts events by their timestamp.jq'.Records | sort_by(.eventTime)[]'<JSON_FILE|*># Select events between two timestamps.jq ".Records | sort_by(.eventTime)[] | select(.eventTime | . == null or (fromdateiso8601 > $(TZ=UTC date -d"YYYY-MM-DDTHH:MM" +%s) and fromdateiso8601 < $(TZ=UTC date -d"YYYY-MM-DDTHH:MM" +%s)))" <JSON_FILE | *>
# Select the event that modified the account state.jq'.Records[] | select(.readOnly == false)'<JSON_FILE|*># Select the specified event linked to the specified source IP address.jq'.Records[] | select(.sourceIPAddress == <IP>)'<JSON_FILE|*># Select the events that contains the "Get" or "List" keyword.jq'.Records[] | select(.eventName | match("Get|List"))'# Select the events conducted by a given principal.jq'.Records | sort_by(.eventTime)[] | select(.userIdentity.principalId | match("<USERNAME>")?)'*# Count the occurrence by source IP address in a collection of CloudTrail export files.echo'def counter(stream): reduce stream as $s ({}; .[$s|tostring] += 1);counter(.Records[].sourceIPAddress)| to_entries[]| {sourceIPAddress: (.key), Count: .value, file: input_filename}'>ip_count.jqjq-fip_count.jq*