Detection rules › Kusto
Email access via active sync
This query detects attempts to add attacker devices as allowed IDs for active sync using the Set-CASMailbox command. This technique was seen in relation to Solorigate attack but the results can indicate potential malicious activity used in different attacks. - Note that this query can be changed to use the KQL "has_all" operator, which hasn't yet been documented officially, but will be soon. In short, "has_all" will only match when the referenced field has all strings in the list. - Refer to Set-CASMailbox syntax: https://docs.microsoft.com/powershell/module/exchange/set-casmailbox?view=exchange-ps
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | T1068 Exploitation for Privilege Escalation, T1078 Valid Accounts |
Event coverage
| Provider | Event | Title |
|---|---|---|
| Sysmon | Event ID 1 | Process creation |
| Security-Auditing | Event ID 4688 | A new process has been created. |
Rule body kusto
id: 2f561e20-d97b-4b13-b02d-18b34af6e87c
name: Email access via active sync
description: |
This query detects attempts to add attacker devices as allowed IDs for active sync using the Set-CASMailbox command.
This technique was seen in relation to Solorigate attack but the results can indicate potential malicious activity used in different attacks.
- Note that this query can be changed to use the KQL "has_all" operator, which hasn't yet been documented officially, but will be soon.
In short, "has_all" will only match when the referenced field has all strings in the list.
- Refer to Set-CASMailbox syntax: https://docs.microsoft.com/powershell/module/exchange/set-casmailbox?view=exchange-ps
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvents
- connectorId: WindowsForwardedEvents
dataTypes:
- WindowsEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1068
- T1078
tags:
- Solorigate
- NOBELIUM
query: |
let timeframe = 1d;
let cmdList = dynamic(["Set-CASMailbox","ActiveSyncAllowedDeviceIDs","add"]);
(union isfuzzy=true
(
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4688
| where CommandLine has_all (cmdList)
| project Type, TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, Process, ParentProcessName, CommandLine
| extend timestamp = TimeGenerated, AccountEntity = Account, HostEntity = Computer
),
( WindowsEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4688
| where EventData has_all (cmdList)
| extend CommandLine = tostring(EventData.CommandLine)
| where CommandLine has_all (cmdList)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend SubjectUserName = tostring(EventData.SubjectUserName)
| extend SubjectDomainName = tostring(EventData.SubjectDomainName)
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend Process=tostring(split(NewProcessName, '\\')[-1])
| extend ParentProcessName = tostring(EventData.ParentProcessName)
| project Type, TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, Process, ParentProcessName, CommandLine
| extend timestamp = TimeGenerated, AccountEntity = Account, HostEntity = Computer
),
(
DeviceProcessEvents
| where TimeGenerated >= ago(timeframe)
| where InitiatingProcessCommandLine has_all (cmdList)
| project Type, TimeGenerated, DeviceName, AccountName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessParentFileName, InitiatingProcessCommandLine
| extend timestamp = TimeGenerated, AccountDomain = InitiatingProcessAccountDomain, AccountName = InitiatingProcessAccountName, HostEntity = DeviceName
),
(
Event
| where TimeGenerated > ago(timeframe)
| where Source == "Microsoft-Windows-Sysmon"
| where EventID == 1
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
| where TimeGenerated >= ago(timeframe)
| where CommandLine has_all (cmdList)
| extend Type = strcat(Type, ": ", Source)
| project Type, TimeGenerated, Computer, User, Process, ParentImage, CommandLine
| extend timestamp = TimeGenerated, AccountEntity = User, HostEntity = Computer
)
)
| extend HostName = tostring(split(HostEntity, ".")[0]), DomainIndex = toint(indexof(HostEntity, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(HostEntity, DomainIndex + 1), HostEntity)
| extend AccountName = tostring(split(AccountEntity, @'\')[1]), AccountDomain = tostring(split(AccountEntity, @'\')[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountEntity
- identifier: Name
columnName: AccountName
- identifier: NTDomain
columnName: AccountDomain
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostEntity
- identifier: HostName
columnName: HostName
- identifier: NTDomain
columnName: HostNameDomain
version: 1.2.1
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Threat Protection" ]
Stages and Predicates
Stage 0: let
let timeframe = 1d;
let cmdList = dynamic(["Set-CASMailbox","ActiveSyncAllowedDeviceIDs","add"]);
Stage 1: union
union isfuzzy=true
Stage 2: source
SecurityEvent
Stage 3: where time_window=86400s
| where TimeGenerated >= ago(timeframe)
Stage 4: where
| where EventID == 4688
Stage 5: where
| where CommandLine has_all (cmdList)
Stage 6: project
| project Type, TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, Process, ParentProcessName, CommandLine
Stage 7: extend
| extend timestamp = TimeGenerated, AccountEntity = Account, HostEntity = Computer
Stage 8: source
WindowsEvent
Stage 9: where time_window=86400s
| where TimeGenerated >= ago(timeframe)
Stage 10: where
| where EventID == 4688
Stage 11: where
| where EventData has_all (cmdList)
Stage 12: extend
| extend CommandLine = tostring(EventData.CommandLine)
Stage 13: where
| where CommandLine has_all (cmdList)
Stage 14: extend
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
Stage 15: extend
| extend SubjectUserName = tostring(EventData.SubjectUserName)
Stage 16: extend
| extend SubjectDomainName = tostring(EventData.SubjectDomainName)
Stage 17: extend
| extend NewProcessName = tostring(EventData.NewProcessName)
Stage 18: extend
| extend Process=tostring(split(NewProcessName, '\\')[-1])
Stage 19: extend
| extend ParentProcessName = tostring(EventData.ParentProcessName)
Stage 20: project
| project Type, TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, Process, ParentProcessName, CommandLine
Stage 21: extend
| extend timestamp = TimeGenerated, AccountEntity = Account, HostEntity = Computer
Stage 22: source
DeviceProcessEvents
Stage 23: where time_window=86400s
| where TimeGenerated >= ago(timeframe)
Stage 24: where
| where InitiatingProcessCommandLine has_all (cmdList)
Stage 25: project
| project Type, TimeGenerated, DeviceName, AccountName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessParentFileName, InitiatingProcessCommandLine
Stage 26: extend
| extend timestamp = TimeGenerated, AccountDomain = InitiatingProcessAccountDomain, AccountName = InitiatingProcessAccountName, HostEntity = DeviceName
Stage 27: source
Event
Stage 28: where time_window=86400s
| where TimeGenerated > ago(timeframe)
Stage 29: where
| where Source == "Microsoft-Windows-Sysmon"
Stage 30: where
| where EventID == 1
Stage 31: extend
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
Stage 32: mv-expand
| mv-expand bagexpansion=array EventData
Stage 33: evaluate
| evaluate bag_unpack(EventData)
Stage 34: extend
| extend Key=tostring(['@Name']), Value=['#text']
Stage 35: evaluate
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
Stage 36: where time_window=86400s
| where TimeGenerated >= ago(timeframe)
Stage 37: where
| where CommandLine has_all (cmdList)
Stage 38: extend
| extend Type = strcat(Type, ": ", Source)
Stage 39: project
| project Type, TimeGenerated, Computer, User, Process, ParentImage, CommandLine
Stage 40: extend
| extend timestamp = TimeGenerated, AccountEntity = User, HostEntity = Computer
Stage 41: extend
| extend HostName = tostring(split(HostEntity, ".")[0]), DomainIndex = toint(indexof(HostEntity, '.'))
Stage 42: extend
| extend HostNameDomain = iff(DomainIndex != -1, substring(HostEntity, DomainIndex + 1), HostEntity)
Stage 43: extend
| extend AccountName = tostring(split(AccountEntity, @'\')[1]), AccountDomain = tostring(split(AccountEntity, @'\')[0])
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
CommandLine | match |
|
EventData | match |
|
EventID | eq |
|
InitiatingProcessCommandLine | match |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
CommandLine | project |
Computer | project |
ParentImage | project |
Process | project |
TimeGenerated | project |
Type | project |
User | project |
AccountEntity | extend |
HostEntity | extend |
timestamp | extend |
DomainIndex | extend |
HostName | extend |
HostNameDomain | extend |
AccountDomain | extend |
AccountName | extend |