Detection rules › Kusto
AWSCloudTrail - Successful API executed from a Tor exit node
Identifies successful AWS CloudTrail API activity originating from an IP address identified as a TOR exit node in the external TOR list hosted at https://firewalliplists.gypthecat.com/lists/kusto/kusto-tor-exit.csv.zip. The rule alerts only when CloudTrail indicates the request completed successfully with no ErrorCode and no ErrorMessage, and the source IP is present in the TOR exit node list.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Execution |
Rule body
id: 0adab960-5565-4978-ba6d-044553e4acc4
name: AWSCloudTrail - Successful API executed from a Tor exit node
description: |
Identifies successful AWS CloudTrail API activity originating from an IP address identified as a TOR exit node in
the external TOR list hosted at https://firewalliplists.gypthecat.com/lists/kusto/kusto-tor-exit.csv.zip. The rule alerts
only when CloudTrail indicates the request completed successfully with no ErrorCode and no ErrorMessage, and the source
IP is present in the TOR exit node list.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AWS
dataTypes:
- AWSCloudTrail
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
relevantTechniques:
- T1204
query: |
let TorNodes = (
externaldata (TorIP:string)
[h@'https://firewalliplists.gypthecat.com/lists/kusto/kusto-tor-exit.csv.zip']
with (ignoreFirstRecord=true));
AWSCloudTrail
| where SourceIpAddress in (TorNodes) and isempty(ErrorCode) and isempty(ErrorMessage)
| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")
| project TimeGenerated, SourceIpAddress, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName, UserIdentityPrincipalid, EventName, EventSource, AWSRegion, RecipientAccountId
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- identifier: CloudAppAccountId
columnName: RecipientAccountId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIpAddress
customDetails:
UserIdentityArn: UserIdentityArn
EventName: EventName
EventSource: EventSource
AWSRegion: AWSRegion
alertDetailsOverride:
alertDisplayNameFormat: 'Successful AWS API call from TOR exit node: {{AccountName}} from {{SourceIpAddress}}'
alertDescriptionFormat: 'A successful AWS API call was observed from TOR exit node IP {{SourceIpAddress}} for account {{AccountName}}.'
version: 1.0.2
kind: Scheduled
Stages and Predicates
Let binding: TorNodes
let TorNodes = (
externaldata (TorIP:string)
[h@'https://firewalliplists.gypthecat.com/lists/kusto/kusto-tor-exit.csv.zip']
with (ignoreFirstRecord=true));
Stage 1: source
AWSCloudTrail
Stage 2: where
| where SourceIpAddress in (TorNodes) and isempty(ErrorCode) and isempty(ErrorMessage)
Stage 3: extend (4 consecutive steps)
| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")
Stage 4: project
| project TimeGenerated, SourceIpAddress, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName, UserIdentityPrincipalid, EventName, EventSource, AWSRegion, RecipientAccountId
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ErrorCode | is_null | field:"aws::errorCode" kind:is_null | |
ErrorMessage | is_null | field:"aws::errorMessage" kind:is_null | |
SourceIpAddress | in |
| field:"aws::sourceIPAddress" kind:in value:"TorNodes" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AWSRegion | project |
AccountName | project |
AccountUPNSuffix | project |
EventName | project |
EventSource | project |
RecipientAccountId | project |
SourceIpAddress | project |
TimeGenerated | project |
UserIdentityArn | project |
UserIdentityPrincipalid | project |
UserIdentityUserName | project |