-
Notifications
You must be signed in to change notification settings - Fork 694
[New Rule] AWS SES Identity Verified Then Deleted #6658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
bryans3c
merged 19 commits into
main
from
new-rule/aws-ses-identity-verified-then-deleted
Aug 31, 2026
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
8fc90c4
[New Rule] AWS SES Email Identity Verified Then Deleted
bryans3c 17bb109
[New Rule] AWS SES Email Identity Verified Then Deleted
bryans3c e55a941
[New Rule] AWS SES Email Identity Verified Then Deleted
bryans3c 7362a03
Potential fix for pull request finding
bryans3c 86aacae
Potential fix for pull request finding
bryans3c 54782f8
Potential fix for pull request finding
bryans3c 253c98e
Update resource_development_ses_identity_verified_then_deleted.toml
bryans3c 3d30a38
Update resource_development_ses_identity_verified_then_deleted.toml
bryans3c d165881
Update resource_development_ses_identity_verified_then_deleted.toml
bryans3c 0e78958
Update rules/integrations/aws/resource_development_ses_identity_verif…
bryans3c 1047391
Update rules/integrations/aws/resource_development_ses_identity_verif…
bryans3c 49b9897
Modify SES identity verification rule parameters
bryans3c f662848
Potential fix for pull request finding
bryans3c 182b69a
Update resource_development_ses_identity_verified_then_deleted.toml
bryans3c 6c9572f
Remove first_verify and last_delete fields
bryans3c c1cd725
Update resource_development_ses_identity_verified_then_deleted.toml
bryans3c c3f41dd
Refactor SES identity verification and deletion logic
bryans3c ad2b78b
Update resource_development_ses_identity_verified_then_deleted.toml
bryans3c 9c5de8b
Merge branch 'main' into new-rule/aws-ses-identity-verified-then-deleted
bryans3c File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
139 changes: 139 additions & 0 deletions
139
rules/integrations/aws/resource_development_ses_identity_verified_then_deleted.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| [metadata] | ||
| creation_date = "2026/08/31" | ||
| integration = ["aws"] | ||
| maturity = "production" | ||
| updated_date = "2026/08/31" | ||
|
|
||
| [rule] | ||
| author = ["Elastic"] | ||
| description = """ | ||
| Detects an SES email identity being verified and subsequently deleted within a 30-minute window, | ||
| performed by the same AWS identity. Amazon SES requires email addresses and domains | ||
| to be verified before they can be used as senders. An adversary who obtains SES credentials | ||
| may verify a domain or address they control, use it to send phishing or spam email, then delete | ||
| the identity to remove evidence of the sending domain from the account's verified identity list. | ||
| This verify-use-delete pattern is a recognized attacker technique for SES abuse. | ||
| """ | ||
| false_positives = [ | ||
| """ | ||
| Testing workflows that verify a sandbox email address and then clean it up may trigger this | ||
| rule. Confirm that the email identity verified and deleted corresponds to a planned test | ||
| rather than a production or attacker-controlled domain. | ||
| """, | ||
| ] | ||
| from = "now-60m" | ||
| interval = "30m" | ||
| language = "esql" | ||
| license = "Elastic License v2" | ||
| name = "AWS SES Email Identity Verified Then Deleted" | ||
| note = """## Triage and analysis | ||
|
|
||
| ### Investigating AWS SES Email Identity Verified Then Deleted | ||
|
|
||
| Amazon SES requires that email addresses and domains be verified (via DNS record or a verification email) before they can be used as `From:` addresses. An adversary who obtains SES write credentials can verify a domain they control, send bulk email from that domain using the victim account's sending quota and reputation, then delete the identity to hide the sending domain from security reviews. | ||
|
|
||
| The verify-then-delete sequence is the evidence-destruction component of the SES phishing technique: it removes the compromised identity from `ListIdentities` output, making post-incident attribution harder. | ||
|
|
||
| This is an ES|QL rule that aggregates SES verification and deletion events per calling identity within 30-minute windows and alerts when the same identity performed both, with the verification preceding the deletion. | ||
|
|
||
| ### Possible investigation steps | ||
|
|
||
| - Identify the caller from `aws.cloudtrail.user_identity.arn` and the aggregated `user_names` column. | ||
| - Pivot to the raw CloudTrail events for this ARN in the `first_verify` to `last_delete` time range to determine the verified identity from the `VerifyEmailIdentity` or `VerifyDomainIdentity` request parameters and the deleted identity from the `DeleteIdentity` request parameters. | ||
| - Query SES `SendEmail` / `SendRawEmail` CloudTrail events (if CloudTrail management events are being collected) or SES sending statistics between the verification and deletion timestamps to determine whether email was sent from the verified identity. | ||
| - Check your email service provider's delivery logs for any email sourced from the SES identity. | ||
| - Review all SES actions taken by this identity in the surrounding time window. | ||
|
|
||
| ### Response and remediation | ||
|
|
||
| - If unauthorized email was sent, notify affected recipients and file an SES abuse report. | ||
| - Rotate all IAM credentials that had SES write access during the incident window. | ||
| - Enable SES sending quotas and alerts to detect unusual send volume in real time. | ||
| - Restrict `ses:VerifyEmailIdentity`, `ses:VerifyDomainIdentity`, and `ses:DeleteIdentity` to a dedicated SES-management role via IAM policy. | ||
| """ | ||
| references = [ | ||
| "https://docs.aws.amazon.com/ses/latest/APIReference/API_VerifyEmailIdentity.html", | ||
| "https://docs.aws.amazon.com/ses/latest/APIReference/API_DeleteIdentity.html", | ||
| "https://permiso.io/blog/s/aws-ses-pionage-detecting-ses-abuse/", | ||
| ] | ||
| risk_score = 47 | ||
| rule_id = "8e4bde35-125d-4eb3-9a2e-d7e77a053a08" | ||
| setup = "The AWS integration must be ingesting management events into `logs-aws.cloudtrail-*`. SES management APIs are logged by default." | ||
| severity = "medium" | ||
| tags = [ | ||
| "Domain: Cloud", | ||
| "Platform: AWS", | ||
| "Data Source: AWS CloudTrail", | ||
| "Service: AWS SES", | ||
| "Rule Type: ESQL", | ||
| "Tactic: Resource Development", | ||
| "Tactic: Defense Evasion", | ||
| "Resources: Investigation Guide", | ||
| ] | ||
| timestamp_override = "event.ingested" | ||
| type = "esql" | ||
|
|
||
| query = ''' | ||
| from logs-aws.cloudtrail-* metadata _id, _version, _index | ||
| | where data_stream.dataset == "aws.cloudtrail" | ||
| and event.provider == "ses.amazonaws.com" | ||
| and event.action in ("VerifyEmailIdentity", "VerifyDomainIdentity", "VerifyEmailAddress", "VerifyDomainDkim", "DeleteIdentity") | ||
| and event.outcome == "success" | ||
| and aws.cloudtrail.user_identity.arn is not null | ||
| | eval Esql.ses_verify_flag = case(event.action != "DeleteIdentity", 1, 0), | ||
| Esql.ses_delete_flag = case(event.action == "DeleteIdentity", 1, 0) | ||
| | stats Esql.ses_verify_count = sum(Esql.ses_verify_flag), | ||
| Esql.ses_delete_count = sum(Esql.ses_delete_flag), | ||
| Esql.ses_verify_timestamp_min = min(case(Esql.ses_verify_flag == 1, @timestamp)), | ||
| Esql.ses_delete_timestamp_max = max(case(Esql.ses_delete_flag == 1, @timestamp)), | ||
| Esql.event_action_values = values(event.action), | ||
| Esql_priv.user_name_values = values(user.name), | ||
| Esql.cloud_account_id_values = values(cloud.account.id) | ||
| by aws.cloudtrail.user_identity.arn | ||
| | where Esql.ses_verify_count > 0 and Esql.ses_delete_count > 0 | ||
| and Esql.ses_verify_timestamp_min < Esql.ses_delete_timestamp_max | ||
| and date_diff("minutes", Esql.ses_verify_timestamp_min, Esql.ses_delete_timestamp_max) <= 30 | ||
| | keep aws.cloudtrail.user_identity.arn, Esql.ses_verify_count, Esql.ses_delete_count, Esql.ses_verify_timestamp_min, Esql.ses_delete_timestamp_max, Esql.event_action_values, Esql_priv.user_name_values, Esql.cloud_account_id_values | ||
| ''' | ||
|
|
||
|
|
||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1583" | ||
| name = "Acquire Infrastructure" | ||
| reference = "https://attack.mitre.org/techniques/T1583/" | ||
|
|
||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1583.001" | ||
| name = "Domains" | ||
| reference = "https://attack.mitre.org/techniques/T1583/001/" | ||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0042" | ||
| name = "Resource Development" | ||
| reference = "https://attack.mitre.org/tactics/TA0042/" | ||
|
Copilot marked this conversation as resolved.
|
||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1070" | ||
| name = "Indicator Removal" | ||
| reference = "https://attack.mitre.org/techniques/T1070/" | ||
|
|
||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0005" | ||
| name = "Defense Evasion" | ||
| reference = "https://attack.mitre.org/tactics/TA0005/" | ||
|
|
||
| [rule.investigation_fields] | ||
| field_names = [ | ||
| "aws.cloudtrail.user_identity.arn", | ||
| "Esql.ses_verify_count", | ||
| "Esql.ses_delete_count", | ||
| "Esql.ses_verify_timestamp_min", | ||
| "Esql.ses_delete_timestamp_max", | ||
| "Esql.event_action_values", | ||
| "Esql_priv.user_name_values", | ||
| "Esql.cloud_account_id_values", | ||
| ] | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.