Detection rules › Kusto
Solorigate Named Pipe
Identifies a match across various data feeds for named pipe IOCs related to the Solorigate incident. For the sysmon events required for this detection, logging for Named Pipe Events needs to be configured in Sysmon config (Event ID 17 and Event ID 18) Reference: https://techcommunity.microsoft.com/t5/azure-sentinel/solarwinds-post-compromise-hunting-with-azure-sentinel/ba-p/1995095
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | |
| Stealth |
Telemetry coverage
Rule body
id: 11b4c19d-2a79-4da3-af38-b067e1273dee
name: Solorigate Named Pipe
description: |
'Identifies a match across various data feeds for named pipe IOCs related to the Solorigate incident.
For the sysmon events required for this detection, logging for Named Pipe Events needs to be configured in Sysmon config (Event ID 17 and Event ID 18)
Reference: https://techcommunity.microsoft.com/t5/azure-sentinel/solarwinds-post-compromise-hunting-with-azure-sentinel/ba-p/1995095'
severity: High
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsForwardedEvents
dataTypes:
- WindowsEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
- PrivilegeEscalation
relevantTechniques:
- T1055
tags:
- Solorigate
- NOBELIUM
query: |
(union isfuzzy=true
(Event
| where Source == "Microsoft-Windows-Sysmon"
| where EventID in (17,18)
| where EventData has '583da945-62af-10e8-4902-a8f205c72b2e'
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId)
| extend PipeName = column_ifexists("PipeName", "")
| extend Account = User
| extend AccountName = tostring(split(User, @"\")[1]), AccountNTDomain = tostring(split(User, @"\")[0])
),
(
SecurityEvent
| where EventID == '5145'
// %%4418 looks for presence of CreatePipeInstance value
| where AccessList has '%%4418'
| where RelativeTargetName has '583da945-62af-10e8-4902-a8f205c72b2e'
| extend AccountName = SubjectUserName, AccountNTDomain = SubjectDomainName
),
(
WindowsEvent
| where EventID == '5145' and EventData has '%%4418' and EventData has '583da945-62af-10e8-4902-a8f205c72b2e'
// %%4418 looks for presence of CreatePipeInstance value
| extend AccessList= tostring(EventData.AccessList)
| where AccessList has '%%4418'
| extend RelativeTargetName= tostring(EventData.RelativeTargetName)
| where RelativeTargetName has '583da945-62af-10e8-4902-a8f205c72b2e'
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountName = tostring(EventData.SubjectUserName), AccountNTDomain = tostring(EventData.SubjectDomainName)
)
)
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| project-away DomainIndex
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Account
- identifier: Name
columnName: AccountName
- identifier: NTDomain
columnName: AccountNTDomain
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: NTDomain
columnName: HostNameDomain
version: 1.2.5
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - 0-day Vulnerability" ]
Stages and Predicates
union isfuzzy=true (3 sources)
Each leg below queries one source; the rule matches if any leg does. Sources: Event, SecurityEvent, WindowsEvent
Leg 1: Event
Event
| where Source == "Microsoft-Windows-Sysmon"
| where EventID in (17,18)
| where EventData has '583da945-62af-10e8-4902-a8f205c72b2e'
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId)
| extend PipeName = column_ifexists("PipeName", "")
| extend Account = User
| extend AccountName = tostring(split(User, @"\")[1]), AccountNTDomain = tostring(split(User, @"\")[0])
Leg 2: SecurityEvent
SecurityEvent
| where EventID == '5145'
| where AccessList has '%%4418'
| where RelativeTargetName has '583da945-62af-10e8-4902-a8f205c72b2e'
| extend AccountName = SubjectUserName, AccountNTDomain = SubjectDomainName
Leg 3: WindowsEvent
WindowsEvent
| where EventID == '5145' and EventData has '%%4418' and EventData has '583da945-62af-10e8-4902-a8f205c72b2e'
| extend AccessList= tostring(EventData.AccessList)
| where AccessList has '%%4418'
| extend RelativeTargetName= tostring(EventData.RelativeTargetName)
| where RelativeTargetName has '583da945-62af-10e8-4902-a8f205c72b2e'
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountName = tostring(EventData.SubjectUserName), AccountNTDomain = tostring(EventData.SubjectDomainName)
Applied to the combined result
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| project-away DomainIndex
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AccessList | match |
| field:"AccessList" kind:match value:"%%4418" |
EventData | match |
| field:"EventData" kind:match |
EventID | eq |
| field:"EventID" kind:eq value:"5145" |
EventID | in |
| field:"EventID" kind:in |
RelativeTargetName | match |
| field:"RelativeTargetName" kind:match value:"583da945-62af-10e8-4902-a8f205c72b2e" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EventData | extend |
Key | extend |
Value | extend |
PipeName | extend |
Account | extend |
AccountNTDomain | extend |
AccountName | extend |
AccessList | extend |
RelativeTargetName | extend |
HostName | extend |
HostNameDomain | extend |