FalconFriday — Detecting realistic AWS cloud-attacks using Azure Sentinel — 0xFF1C

On January 28th, Christophe Tafani-Dereeper released the open source Stratus Red team attack simulation tool. At FalconForce, we are very pleased to see attack simulation tools being published, especially when they simulate realistic cloud-based attacks like this one. Since Christophe released these attack simulations as open source we decided to also release the associated Azure Sentinel detection content we developed to detect the simulated attacks as open source. These detections are available on our FalconFriday Github repository.

This blog post describes how these rules were created and provides some background on the rules and on how an attack simulation tool can be used to facilitate the construction of detection content.

We managed to produce detection content that covers 19 of the 21 AWS attacks that can be simulated using Stratus Red team. Below is a summary linking each of the attacks in Stratus Red team to the relevant detection rule in the FalconFriday or Azure Sentinel repository. Note that some of these detection rules cover multiple simulated attacks using a single rule.

For the following attacks we were unable to come up with a reliable detection, since it turned out to be hard to distinguish legitimate usage and attacks.

  • aws.persistence.iam-create-admin-use
  • aws.persistence.iam-backdoor-user

Do you have detections for these two persistence attacks?

Should you know reliable detections for these two attacks or for new attacks added to Stratus Red team, we would be happy to hear them! Please contribute your (suggestions for) detection(s) via a pull request on our FalconFriday GitHub repository. We will select the best solution, make it available to the community and award you with some nice FalconForce swag! 🙂

Attacks supported by Stratus Red team

In Stratus Red team, the list command can be used to obtain the list of supported attacks. Below is an overview of the 21 attacks supported in the version we analyzed for this blog post.

Numbered list of attacks supported by Stratus Red team.

Each attack in the tool can be in a number of states. Cold means that no infrastructure has been created for the attack. A warm up can be performed to create the necessary infrastructure components to allow the attack to be performed. Once the attack is warmed up it can be detonated to execute the actual attack.

Attack states for Stratus Red team, source https://github.com/DataDog/stratus-red-team/blob/main/docs/user-guide/state-machine.png

Attack preparation

To run these attacks in a controlled manner, we used a fresh AWS account and extracted the list of tests to a text file called techniques.txt and then ran the warmup command on all these techniques to prepare the necessary infrastructure:

% stratus list | grep 'aws.' | awk '{ print $2 }' > techniques.txt
% stratus warmup $(cat techniques.txt)

Detonating all the attacks

To be able to investigate each attack separately, we used a simple batch script to detonate the attacks one by one. Each time waiting until the next full minute to detonate the next attack. This way, we get a nice overview of the times for each attack, allowing us to investigate the logs for each attack separately.

for x in $(cat techniques.txt); do 
  echo sleeping
  sleep $((60 - $(date +%s) % 60))
  echo "$(date) - Detonating $x"
  ./stratus detonate "$x"

Building detections

The main source for monitoring these attacks on AWS is the built-in Cloud Trail logging. In our test environment, we ingest these logs into Microsoft Sentinel for analysis.

Knowing when each attack was detonated, we can find the associated events by looking at the binned version of the TimeGenerated field. For example:

| where TimeGenerated >= ago(1d)
| order by TimeGenerated desc
| where bin(TimeGenerated,1m) == todatetime('2022-01-31T10:27:00Z')
| where not(UserIdentityArn contains "Sentinel")
| where not(UserIdentityType contains "AWSService")

Ingestion delays for AWSCloudTrail

One important thing to be aware of when creating Azure Sentinel content for AWSCloudTrail is the ingestion delay. Cloud Trail logs go through multiple steps before they are ingested into Azure Sentinel, causing significant delays. In our test environment this delay averaged about 20 minutes as can be seen in the graph below.

Delay in minutes for AWSCloudTrail events in the FalconForce test environment.

In case you want to investigate the ingestion delay in your own environment, you can use this query which was used to generate the graph above.

| where TimeGenerated >= ago(7d)
| extend Delay_in_minutes=
  datetime_diff('minute', ingestion_time(), TimeGenerated)
| summarize EventCount=count() by Delay_in_minutes
| where EventCount > 10 // Discard outliers.
| order by Delay_in_minutes
| render barchart

When filtering events on the TimeGenerated field, this can lead to a significant number of events being missed — since any data that has not yet been ingested will not be analyzed. To work around this limitation, the queries we present here for AWSCloudTrail use a filter on ingestion_time() — which represents the time the event was ingested into Azure Sentinel rather than the TimeGenerated field which represents the time when the actual event took place. Keep an eye out for a future blog-post on how to deal with ingestion delays and other related issues.

Detections for credential access

The first three attacks simulate an attacker obtaining a large number of sensitive values in a short time period. Below is an overview of the attacks and which related event will be triggered in Cloud Trail.

  • aws.credential-access.ec2-get-password-data — GetPasswordData
  • aws.credential-access.secretsmanager-retrieve-secrets — GetSecretValue
  • aws.credential-access.ssm-retrieve-securestring-parameters — Decrypt

We can build a detection rule which covers these three attacks by looking at the number of requests made for these events. In the case of Decrypt we limit this to decryption of SSM parameters by checking that the ARN starts with arn:aws:ssm. The time period and access threshold in the rule can be tweaked based on the environment. By default, it will look at more than 10 secrets accessed in a 10 minute timeframe.

The query can be found in our FalconFriday GitHub repository.

The last remaining attack in the credential access category is aws.credential-access.ec2-steal-instance-credentials. This attack consists of two steps. First, the instance credentials of an EC2 instance are compromised by running a shell script via SSM. This exposes the instance credentials to an attacker, allowing the attacker to take the second step: call the AWS API using these credentials from their own machine.

One way to recognize such an attack, is to look at instance credentials being used from a different public IP address than where they are normally used from. Instance credentials can be recognized in the Cloud Trail logs by looking at the UserIdentityPrincipalid. In case of instance credentials, this will contain “:i-<instance-id>”.

By running a query over a larger period of time, for example, 24 hours, a baseline of the most commonly used IP address for each instance credential can be obtained. This can then be filtered for outliers, where a different IP address is used. Using the make_bag and pack query functions in the Kusto query language, we can construct a list of actions being performed per IP address. This will provide output like the following for analysts performing investigation.

Example query output, providing additional context to analysts.

The query can be found in our FalconFriday GitHub repository.

These two rules combined provide detection in our lab for all Stratus Red team attacks in the credential access area.

Detections for defense evasion

The Stratus Red team tool provides 6 attacks related to the defense evasion tactic. Most of these attacks can be detected using a single event in the Cloud Trail logging. Below is an overview of the attacks and which related event will be triggered in Cloud Trail.

  • aws.defense-evasion.cloudtrail-delete — DeleteTrail
  • aws.defense-evasion.cloudtrail-event-selectors — PutEventSelectors
  • aws.defense-evasion.cloudtrail-lifecycle-rule — PutBucketLifecycle
  • aws.defense-evasion.cloudtrail-stop — StopLogging
  • aws.defense-evasion.organizations-leave — LeaveOrganization
  • aws.defense-evasion.vpc-remove-flow-logs — DeleteFlowLogs

Most of these events are available in a standard rule published in the Azure Sentinel Github Repository. The rule can be updated to include the PutEventSelectors, PutBucketLifecycle and LeaveOrganization events.

Note that the PutBucketLifecycle event may be prone to false positives, as this applies to adding a bucket lifecycle to any S3 bucket and not only buckets related to Cloud Trail logging. One way to deal with this issue is to include the naming convention used for logging-related buckets in the alert rule — assuming such a naming convention exists.

The rule published in the Azure Sentinel Github Repository can be updated by modifying the first line of the query to include the additional events as highlighted in bold below:

let EventNameList = dynamic(["UpdateTrail","DeleteTrail","StopLogging","DeleteFlowLogs","DeleteEventBus","PutEventSelectors","PutBucketLifecycle","LeaveOrganization"]);

Detections for discovery

The Stratus Red team tool provides a single attack related to discovery: aws.discovery.ec2-enumerate-from-instance. This attack uses instance credentials to enumerate data in AWS. As discussed in the section related to credential access, one way to recognize instance credentials being used from the Cloud Trail logging is to look for “:i-<instance_id>” in the UserIdentityPrincipalid field.

An alert can be created for a discovery event issued from an instance credential. In this case, the following discovery events are monitored: ListRoles, GetAccountAuthorizationDetails and ListUsers.

The query can be found in our FalconFriday GitHub repository.

Detections for exfiltration

The Stratus Red team tool provides 5 attacks related to exfiltration. Four of these attacks are related to sharing resources with an external AWS account. For each of these, an event is logged in Cloud Trail with the Event Name mentioned below:

  • aws.exfiltration.ec2-share-ami — ModifyImageAttribute
  • aws.exfiltration.ec2-share-ebs-snapshot — ModifySnapshotAttribute
  • aws.exfiltration.rds-share-snapshot — ModifyDBSnapshotAttribute
  • aws.exfiltration.s3-backdoor-bucket-policy — PutBucketPolicy

For each of these events, the account that the resource is shared with needs to be parsed from the Cloud Trail event. The field in which this account name is located and the format in which it is stored is different for each event type. Therefore, we use a separate sub-query for each event type that extracts the shared account in the AddedAccount property.

Once all these added accounts have been obtained, the results are combined using union and the query checks whether the account that was added is on a list of known and trusted AWS accounts. This list of trusted AWS accounts can be configured in the query. This allows tuning the query to an environment and prevents false positive alerts in case resources are shared with another trusted account.

Note: one of the persistence-related attacks can also be detected using this same logic, and is therefore also included in this query:

  • aws.persistence.lambda-backdoor-function — lambda.amazonaws.com AddPermission*

The query can be found in our FalconFriday GitHub repository.

The last attack related to the exfiltration tactic is aws.exfiltration.ec2-security-group-open-port-22-ingress, which modifies a security group to allow inbound traffic from the entire internet.

To detect this attack, the AuthorizeSecurityGroupIngress event can be monitored. The allowed IP ranges can be extracted from the ipPermissions and cidrIp parameters in the request. If these are too broad, for example, all public IPs, an alert is raised.

The query can be found in our FalconFriday GitHub repository.

Detections for persistence

The first persistence attack aws.persistence.iam-backdoor-role updates a role, adding an “assume role policy” with an external user account.

While the Stratus Red team tool only performs this to an existing role, the same attack could be performed by creating a new role. Therefore, the detection rule covers both the CreateRole and UpdateAssumeRolePolicy events.

The rule parses the policy document, looking for external AWS accounts. At the end we can verify whether the account that was added is on a list of known and trusted AWS accounts that can be configured in the query. This allows tuning the query to an environment and prevents false positive alerts in case resources are shared with another trusted account.

The query can be found in our FalconFriday GitHub repository.

The second persistence attack is aws.persistence.iam-create-user-login-profile. This attack calls the CreateLoginProfile function which adds a password that can be used on the AWS console to an existing user that did not have console access before and could only be used via the API.

In most organizations, such conversions from API-only users to full console users are rare and therefore a simple way to monitor for this attack is to just look for any CreateLoginProfile events.

The query can be found in our FalconFriday GitHub repository.

Note: the persistence attack aws.persistence.lambda-backdoor-function is detected via the logic for the exfiltration attacks.

The remaining two attacks: aws.persistence.iam-backdoor-user and aws.persistence.iam-create-admin-user are both so generic that it’s hard to write an accurate detection for them.

Closing remarks

Stratus Red team is an awesome tool to test your defenses in AWS on a regular basis. We hope this blog post provides you a head start in defending against these AWS attacks.

Knowledge center

Other articles

BloodHound — Calculating AD metrics 0x02

BloodHound — Calculating AD metrics 0x02

[dsm_breadcrumbs show_home_icon="off" separator_icon="K||divi||400" admin_label="Supreme Breadcrumbs" _builder_version="4.18.0" _module_preset="default" items_font="||||||||" items_text_color="rgba(255,255,255,0.6)" custom_css_main_element="color:...

BloodHound — Calculating AD metrics 0x01

BloodHound — Calculating AD metrics 0x01

[dsm_breadcrumbs show_home_icon="off" separator_icon="K||divi||400" admin_label="Supreme Breadcrumbs" _builder_version="4.18.0" _module_preset="default" items_font="||||||||" items_text_color="rgba(255,255,255,0.6)" custom_css_main_element="color:...

Together. Secure. Today.

Stay in the loop and sign up to our newsletter

FalconForce realizes ambitions by working closely with its customers in a methodical manner, improving their security in the digital domain.

Energieweg 3
3542 DZ Utrecht
The Netherlands

FalconForce B.V.
[email protected]
(+31) 85 044 93 34

KVK 76682307
BTW NL860745314B01