Detection rules › Kusto

Solorigate Defender Detections

Severity
high
Time window
1d
Group by
CompromisedEntity, DeviceName
Author
Microsoft Security Research
Source
github.com/Azure/Azure-Sentinel

'Surfaces any Defender Alert for Solorigate Events. In Microsoft Sentinel the SecurityAlerts table includes only the Device Name of the affected device, this query joins the DeviceInfo table to clearly connect other information such as Device group, ip, logged on users etc. This way, the Microsoft Sentinel user can have all the pertinent device info in one view for all the the Solarigate Defender alerts.'

MITRE ATT&CK coverage

TacticTechniques
Initial AccessT1195 Supply Chain Compromise

Rule body kusto

id: e70fa6e0-796a-4e85-9420-98b17b0bb749
name: Solorigate Defender Detections
description: |
  'Surfaces any Defender Alert for Solorigate Events. In Microsoft Sentinel the SecurityAlerts table includes only the Device Name of the affected device, this query joins the DeviceInfo table to clearly connect other information such as
   Device group, ip, logged on users etc. This way, the Microsoft Sentinel user can have all the pertinent device info in one view for all the the Solarigate Defender alerts.'
severity: High
requiredDataConnectors:
  - connectorId: MicrosoftDefenderAdvancedThreatProtection
    dataTypes:
      - SecurityAlert (MDATP)
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceInfo
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1195
tags:
  - Solorigate
  - NOBELIUM
query: |
  DeviceInfo
  | extend DeviceName = tolower(DeviceName)
  | join (SecurityAlert
  | where ProviderName =~ "MDATP"
  | extend ThreatName = tostring(parse_json(ExtendedProperties).ThreatName)
  | where ThreatName has "Solorigate"
  ) on $left.DeviceName == $right.CompromisedEntity
  | project TimeGenerated, DisplayName, ThreatName, CompromisedEntity, PublicIP, MachineGroup, AlertSeverity, Description, LoggedOnUsers, DeviceId, TenantId
  | extend HostName = tostring(split(CompromisedEntity, ".")[0]), DomainIndex = toint(indexof(CompromisedEntity, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(CompromisedEntity, DomainIndex + 1), CompromisedEntity)
  | project-away DomainIndex
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: CompromisedEntity
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: PublicIP
version: 1.0.5
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Research
    support:
        tier: Community
    categories:
        domains: [ "Security - 0-day Vulnerability" ]

Stages and Predicates

Stage 1: source

DeviceInfo

Stage 2: extend

| extend DeviceName = tolower(DeviceName)

Stage 3: join

| join (SecurityAlert
| where ProviderName =~ "MDATP"
| extend ThreatName = tostring(parse_json(ExtendedProperties).ThreatName)
| where ThreatName has "Solorigate"
) on $left.DeviceName == $right.CompromisedEntity

Stage 4: project

| project TimeGenerated, DisplayName, ThreatName, CompromisedEntity, PublicIP, MachineGroup, AlertSeverity, Description, LoggedOnUsers, DeviceId, TenantId

Stage 5: extend

| extend HostName = tostring(split(CompromisedEntity, ".")[0]), DomainIndex = toint(indexof(CompromisedEntity, '.'))

Stage 6: extend

| extend HostNameDomain = iff(DomainIndex != -1, substring(CompromisedEntity, DomainIndex + 1), CompromisedEntity)
HostNameDomain =
ifDomainIndex != -1substring(CompromisedEntity, (DomainIndex + 1))
elseCompromisedEntity

Stage 7: project-away

| project-away DomainIndex

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.

FieldKindValues
ProviderNameeq
  • MDATP corpus 13 (kusto 13)
ThreatNamematch
  • Solorigate transforms: term

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.

FieldSource
AlertSeverityproject
CompromisedEntityproject
Descriptionproject
DeviceIdproject
DisplayNameproject
LoggedOnUsersproject
MachineGroupproject
PublicIPproject
TenantIdproject
ThreatNameproject
TimeGeneratedproject
HostNameextend
HostNameDomainextend