[New Hunt] Adding Hunting Queries for AWS SNS exfiltration and data collection (#4458)

* new hunting queries for SNS

* added KEEP to all queries; adjusted description in SNS rule
This commit is contained in:
Terrance DeJesus
2025-02-20 10:53:36 -05:00
committed by GitHub
parent ec4523a6a9
commit 0b98462cfe
11 changed files with 373 additions and 15 deletions
@@ -0,0 +1,48 @@
# SNS Direct-to-Phone Messaging Spike
---
## Metadata
- **Author:** Elastic
- **Description:** This hunting query gathers evidence of potential abuse of the SNS service to send direct-to-phone text messages. Adversaries may use this technique to send smishing messages or deliver other types of malicious content directly to users' phones.
- **UUID:** `21e4d0ee-e955-11ef-8c29-f661ea17fbce`
- **Integration:** [aws.cloudtrail](https://docs.elastic.co/integrations/aws/cloudtrail)
- **Language:** `[ES|QL]`
- **Source File:** [SNS Direct-to-Phone Messaging Spike](../queries/sns_direct_to_phone_messaging_spike.toml)
## Query
```sql
from logs-aws.cloudtrail-*
| WHERE @timestamp > now() - 7 day
| EVAL target_time_window = DATE_TRUNC(10 seconds, @timestamp)
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "Publish" AND
event.outcome == "success" AND
aws.cloudtrail.request_parameters LIKE "*phoneNumber*"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| STATS sms_message_count = COUNT(*) by target_time_window, cloud.account.id, aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name
| WHERE sms_message_count > 30
```
## Notes
- AWS removes phone numbers in logs, so deeper analysis via CloudWatch logs may be necessary.
- While investigating in CloudWatch, the message context is also sanitized. It would be ideal to investigate the message for any suspicious URL links being embedded in the text messages.
- You can also review AWS SNS delivery logs (if enabled) for message metadata.
- If messages are not using a topic-based subscription, it suggests direct targeting.
- The source of these requests is important, if you notice them from an EC2 instance, that is rather odd or Lambda may be an expected serverless code
- Review if `aws.cloudtrail.user_identity.access_key_id` exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.
- If direct SMS messages are common in your environment, you can adjust the threshold accordingly.
## MITRE ATT&CK Techniques
- [T1660](https://attack.mitre.org/techniques/T1660)
## License
- `Elastic License v2`
@@ -0,0 +1,45 @@
# SNS Topic Subscription with Email by Rare User
---
## Metadata
- **Author:** Elastic
- **Description:** This hunting query gathered evidence of an SNS topic subscribed to by an email address of a user who does not typically perform this action. Adversaries may subscribe to SNS topics to collect sensitive information or exfiltrate data via an external email address.
- **UUID:** `fb752e42-e952-11ef-85e7-f661ea17fbce`
- **Integration:** [aws.cloudtrail](https://docs.elastic.co/integrations/aws/cloudtrail)
- **Language:** `[ES|QL]`
- **Source File:** [SNS Topic Subscription with Email by Rare User](../queries/sns_email_subscription_by_rare_user.toml)
## Query
```sql
from logs-aws.cloudtrail-*
| where @timestamp > now() - 7 day
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "Subscribe"
| DISSECT aws.cloudtrail.request_parameters "%{?protocol_key}=%{protocol}, %{?endpoint_key}=%{redacted}, %{?return_arn}=%{return_bool}, %{?topic_arn_key}=%{topic_arn}}"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| WHERE protocol == "email"
| STATS regional_topic_subscription_count = COUNT(*) by aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name
| WHERE regional_topic_subscription_count == 1
| SORT regional_topic_subscription_count ASC
```
## Notes
- If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.
- Ignoring the topic ARN during aggregation is important to identify first occurrence anomalies of subscribing to SNS topic with an email.
- Another query may be required with the user identity arn as an inclusion filter to identify which topic they subscribed to.
## MITRE ATT&CK Techniques
- [T1567](https://attack.mitre.org/techniques/T1567)
- [T1530](https://attack.mitre.org/techniques/T1530)
## License
- `Elastic License v2`
@@ -0,0 +1,45 @@
# SNS Topic Created by Rare User
---
## Metadata
- **Author:** Elastic
- **Description:** This hunting query gathers evidence of an SNS topic created by a user who does not typically perform this action. Adversaries may create SNS topics to stage capabilities for data exfiltration or other malicious activities.
- **UUID:** `80955fb2-e952-11ef-b7cc-f661ea17fbce`
- **Integration:** [aws.cloudtrail](https://docs.elastic.co/integrations/aws/cloudtrail)
- **Language:** `[ES|QL]`
- **Source File:** [SNS Topic Created by Rare User](../queries/sns_topic_created_by_rare_user.toml)
## Query
```sql
from logs-aws.cloudtrail-*
| WHERE @timestamp > now() - 7 day
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "CreateTopic"
and aws.cloudtrail.user_identity.type == "AssumedRole"
| DISSECT aws.cloudtrail.request_parameters "{%{?topic_name_key}=%{topic_name}}"
| DISSECT aws.cloudtrail.user_identity.arn "%{?}:assumed-role/%{assumed_role_name}/%{entity}"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| WHERE STARTS_WITH(entity, "i-")
| STATS regional_topic_created_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, cloud.region, user_agent_name
| SORT regional_topic_created_count ASC
```
## Notes
- It is unusual for credentials from an assumed role for an EC2 instance to be creating SNS topics randomly.
- If a user identity access key (`aws.cloudtrail.user_identity.access_key_id`) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.
- Pivot into `Publish` API actions being called to this specific topic to identify which AWS resource is publishing messages. With access to the topic, you could further investigate the subscribers list to identify unauthorized subscribers.
## MITRE ATT&CK Techniques
- [T1608](https://attack.mitre.org/techniques/T1608)
## License
- `Elastic License v2`
@@ -0,0 +1,46 @@
# SNS Topic Message Published by Rare User
---
## Metadata
- **Author:** Elastic
- **Description:** This hunting query gathers evidence of an SNS topic message published by a user who does not typically perform this action. Adversaries may publish messages to SNS topics to stage capabilities for data exfiltration or other malicious activities.
- **UUID:** `db405900-e955-11ef-8c29-f661ea17fbce`
- **Integration:** [aws.cloudtrail](https://docs.elastic.co/integrations/aws/cloudtrail)
- **Language:** `[ES|QL]`
- **Source File:** [SNS Topic Message Published by Rare User](../queries/sns_topic_message_published_by_rare_user.toml)
## Query
```sql
from logs-aws.cloudtrail-*
| where @timestamp > now() - 7 day
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "Publish"
and aws.cloudtrail.user_identity.type == "AssumedRole"
| DISSECT aws.cloudtrail.request_parameters "{%{?message_key}=%{message}, %{?topic_key}=%{topic_arn}}"
| DISSECT aws.cloudtrail.user_identity.arn "%{?}:assumed-role/%{assumed_role_name}/%{entity}"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| WHERE STARTS_WITH(entity, "i-")
| STATS regional_topic_publish_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, topic_arn, cloud.region, user_agent_name
| SORT regional_topic_publish_count ASC
```
## Notes
- If a user identity access key (`aws.cloudtrail.user_identity.access_key_id`) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.
- If you notice Terraform, Pulumi, etc. it may be related to testing environments, maintenance or more.
- Python SDKs that are not AWS, may indicate custom tooling or scripts being leveraged.
## MITRE ATT&CK Techniques
- [T1567](https://attack.mitre.org/techniques/T1567)
- [T1566.003](https://attack.mitre.org/techniques/T1566/003)
## License
- `Elastic License v2`
@@ -0,0 +1,36 @@
[hunt]
author = "Elastic"
description = """
This hunting query gathers evidence of potential abuse of the SNS service to send direct-to-phone text messages. Adversaries may use this technique to send smishing messages or deliver other types of malicious content directly to users' phones.
"""
integration = ["aws.cloudtrail"]
uuid = "21e4d0ee-e955-11ef-8c29-f661ea17fbce"
name = "SNS Direct-to-Phone Messaging Spike"
language = ["ES|QL"]
license = "Elastic License v2"
notes = [
"AWS removes phone numbers in logs, so deeper analysis via CloudWatch logs may be necessary.",
"While investigating in CloudWatch, the message context is also sanitized. It would be ideal to investigate the message for any suspicious URL links being embedded in the text messages.",
"You can also review AWS SNS delivery logs (if enabled) for message metadata.",
"If messages are not using a topic-based subscription, it suggests direct targeting.",
"The source of these requests is important, if you notice them from an EC2 instance, that is rather odd or Lambda may be an expected serverless code",
"Review if `aws.cloudtrail.user_identity.access_key_id` exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.",
"If direct SMS messages are common in your environment, you can adjust the threshold accordingly.",
]
mitre = ["T1660"]
query = ['''
from logs-aws.cloudtrail-*
| WHERE @timestamp > now() - 7 day
| EVAL target_time_window = DATE_TRUNC(10 seconds, @timestamp)
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "Publish" AND
event.outcome == "success" AND
aws.cloudtrail.request_parameters LIKE "*phoneNumber*"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| KEEP target_time_window, cloud.account.id, aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name
| STATS sms_message_count = COUNT(*) by target_time_window, cloud.account.id, aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name
| WHERE sms_message_count > 30
''']
@@ -0,0 +1,31 @@
[hunt]
author = "Elastic"
description = """
This hunting query gathered evidence of an SNS topic subscribed to by an email address of a user who does not typically perform this action. Adversaries may subscribe to SNS topics to collect sensitive information or exfiltrate data via an external email address.
"""
integration = ["aws.cloudtrail"]
uuid = "fb752e42-e952-11ef-85e7-f661ea17fbce"
name = "SNS Topic Subscription with Email by Rare User"
language = ["ES|QL"]
license = "Elastic License v2"
notes = [
"If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.",
"Ignoring the topic ARN during aggregation is important to identify first occurrence anomalies of subscribing to SNS topic with an email.",
"Another query may be required with the user identity arn as an inclusion filter to identify which topic they subscribed to."
]
mitre = ["T1567","T1530"]
query = ['''
from logs-aws.cloudtrail-*
| where @timestamp > now() - 7 day
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "Subscribe"
| DISSECT aws.cloudtrail.request_parameters "%{?protocol_key}=%{protocol}, %{?endpoint_key}=%{redacted}, %{?return_arn}=%{return_bool}, %{?topic_arn_key}=%{topic_arn}}"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| WHERE protocol == "email"
| KEEP cloud.region, source.address, aws.cloudtrail.user_identity.arn, user_agent_name
| STATS regional_topic_subscription_count = COUNT(*) by aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name
| WHERE regional_topic_subscription_count == 1
| SORT regional_topic_subscription_count ASC
''']
@@ -0,0 +1,32 @@
[hunt]
author = "Elastic"
description = """
This hunting query gathers evidence of an SNS topic created by a user who does not typically perform this action. Adversaries may create SNS topics to stage capabilities for data exfiltration or other malicious activities.
"""
integration = ["aws.cloudtrail"]
uuid = "80955fb2-e952-11ef-b7cc-f661ea17fbce"
name = "SNS Topic Created by Rare User"
language = ["ES|QL"]
license = "Elastic License v2"
notes = [
"It is unusual for credentials from an assumed role for an EC2 instance to be creating SNS topics randomly.",
"If a user identity access key (`aws.cloudtrail.user_identity.access_key_id`) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.",
"Pivot into `Publish` API actions being called to this specific topic to identify which AWS resource is publishing messages. With access to the topic, you could further investigate the subscribers list to identify unauthorized subscribers."
]
mitre = ["T1608"]
query = ['''
from logs-aws.cloudtrail-*
| WHERE @timestamp > now() - 7 day
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "CreateTopic"
and aws.cloudtrail.user_identity.type == "AssumedRole"
| DISSECT aws.cloudtrail.request_parameters "{%{?topic_name_key}=%{topic_name}}"
| DISSECT aws.cloudtrail.user_identity.arn "%{?}:assumed-role/%{assumed_role_name}/%{entity}"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| WHERE STARTS_WITH(entity, "i-")
| KEEP cloud.account.id, entity, assumed_role_name, cloud.region, user_agent_name
| STATS regional_topic_created_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, cloud.region, user_agent_name
| SORT regional_topic_created_count ASC
''']
@@ -0,0 +1,32 @@
[hunt]
author = "Elastic"
description = """
This hunting query gathers evidence of an SNS topic message published by a user who does not typically perform this action. Adversaries may publish messages to SNS topics to stage capabilities for data exfiltration or other malicious activities.
"""
integration = ["aws.cloudtrail"]
uuid = "db405900-e955-11ef-8c29-f661ea17fbce"
name = "SNS Topic Message Published by Rare User"
language = ["ES|QL"]
license = "Elastic License v2"
notes = [
"If a user identity access key (`aws.cloudtrail.user_identity.access_key_id`) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.",
"If you notice Terraform, Pulumi, etc. it may be related to testing environments, maintenance or more.",
"Python SDKs that are not AWS, may indicate custom tooling or scripts being leveraged."
]
mitre = ["T1567","T1566.003"]
query = ['''
from logs-aws.cloudtrail-*
| where @timestamp > now() - 7 day
| WHERE
event.dataset == "aws.cloudtrail" AND
event.provider == "sns.amazonaws.com" AND
event.action == "Publish"
and aws.cloudtrail.user_identity.type == "AssumedRole"
| DISSECT aws.cloudtrail.request_parameters "{%{?message_key}=%{message}, %{?topic_key}=%{topic_arn}}"
| DISSECT aws.cloudtrail.user_identity.arn "%{?}:assumed-role/%{assumed_role_name}/%{entity}"
| DISSECT user_agent.original "%{user_agent_name} %{?user_agent_remainder}"
| WHERE STARTS_WITH(entity, "i-")
| KEEP cloud.account.id, entity, assumed_role_name, topic_arn, cloud.region, user_agent_name
| STATS regional_topic_publish_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, topic_arn, cloud.region, user_agent_name
| SORT regional_topic_publish_count ASC
''']
+4
View File
@@ -17,6 +17,10 @@ Here are the queries currently available:
- [Lambda Add Permissions for Write Actions to Function](./aws/docs/lambda_add_permissions_for_write_actions_to_function.md) (ES|QL)
- [Multiple Service Logging Deleted or Stopped](./aws/docs/multiple_service_logging_deleted_or_stopped.md) (ES|QL)
- [S3 Public Bucket Rapid Object Access Attempts](./aws/docs/s3_public_bucket_rapid_object_access_attempts.md) (ES|QL)
- [SNS Direct-to-Phone Messaging Spike](./aws/docs/sns_direct_to_phone_messaging_spike.md) (ES|QL)
- [SNS Topic Created by Rare User](./aws/docs/sns_topic_created_by_rare_user.md) (ES|QL)
- [SNS Topic Message Published by Rare User](./aws/docs/sns_topic_message_published_by_rare_user.md) (ES|QL)
- [SNS Topic Subscription with Email by Rare User](./aws/docs/sns_email_subscription_by_rare_user.md) (ES|QL)
- [SSM Rare SendCommand Code Execution by EC2 Instance](./aws/docs/ssm_rare_sendcommand_code_execution.md) (ES|QL)
- [SSM SendCommand API Used by EC2 Instance](./aws/docs/ssm_sendcommand_api_used_by_ec2_instance.md) (ES|QL)
- [SSM Start Remote Session to EC2 Instance](./aws/docs/ssm_start_remote_session_to_ec2_instance.md) (ES|QL)
+22
View File
@@ -439,6 +439,28 @@ aws:
path: ./aws/queries/iam_unusual_default_aviatrix_role_activity.toml
mitre:
- T1078.004
80955fb2-e952-11ef-b7cc-f661ea17fbce:
name: SNS Topic Created by Rare User
path: ./aws/queries/sns_topic_created_by_rare_user.toml
mitre:
- T1608
db405900-e955-11ef-8c29-f661ea17fbce:
name: SNS Topic Message Published by Rare User
path: ./aws/queries/sns_topic_message_published_by_rare_user.toml
mitre:
- T1567
- T1566.003
21e4d0ee-e955-11ef-8c29-f661ea17fbce:
name: SNS Direct-to-Phone Messaging Spike
path: ./aws/queries/sns_direct_to_phone_messaging_spike.toml
mitre:
- T1660
fb752e42-e952-11ef-85e7-f661ea17fbce:
name: SNS Topic Subscription with Email by Rare User
path: ./aws/queries/sns_email_subscription_by_rare_user.toml
mitre:
- T1567
- T1530
windows:
44e6adc6-e183-4bfa-b06d-db41669641fa:
name: Rundll32 Execution Aggregated by Command Line
@@ -2,7 +2,7 @@
creation_date = "2024/11/01"
integration = ["aws"]
maturity = "production"
updated_date = "2025/01/10"
updated_date = "2025/02/12"
[rule]
author = ["Elastic"]
@@ -28,6 +28,8 @@ note = """## Triage and analysis
This rule identifies when an SNS topic is subscribed to by an email address of a user who does not typically perform this action. While subscribing to SNS topics is a common practice, adversaries may exploit this feature to collect sensitive information or exfiltrate data via an external email address.
This is a [New Terms](https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule) rule that only flags when this behavior is observed for the first time on a host in the last 14 days.
#### Possible Investigation Steps
- **Identify the Actor**: Review the `aws.cloudtrail.user_identity.arn` field to identify the user who requested the subscription. Verify if this actor typically performs such actions and has the necessary permissions. It may be unusual for this activity to originate from certain user types, such as an assumed role or federated user.
@@ -81,6 +83,32 @@ event.dataset: "aws.cloudtrail"
and aws.cloudtrail.request_parameters: *protocol=email*
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1567"
name = "Exfiltration Over Web Service"
reference = "https://attack.mitre.org/techniques/T1567/"
[rule.threat.tactic]
id = "TA0010"
name = "Exfiltration"
reference = "https://attack.mitre.org/tactics/TA0010/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1530"
name = "Data from Cloud Storage"
reference = "https://attack.mitre.org/techniques/T1530/"
[rule.threat.tactic]
id = "TA0009"
name = "Collection"
reference = "https://attack.mitre.org/tactics/TA0009/"
[rule.investigation_fields]
field_names = [
"@timestamp",
@@ -95,25 +123,14 @@ field_names = [
"aws.cloudtrail.flattened.request_parameters.protocol",
"aws.cloudtrail.flattened.request_parameters.topicArn",
"aws.cloudtrail.flattened.response_elements.subscriptionArn",
"aws.cloudtrail.request_parameters"
"aws.cloudtrail.request_parameters",
]
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1567"
name = "Exfiltration Over Web Service"
reference = "https://attack.mitre.org/techniques/T1567/"
[rule.threat.tactic]
id = "TA0010"
name = "Exfiltration"
reference = "https://attack.mitre.org/tactics/TA0010/"
[rule.new_terms]
field = "new_terms_fields"
value = ["aws.cloudtrail.user_identity.arn"]
[[rule.new_terms.history_window_start]]
field = "history_window_start"
value = "now-14d"