Detection rules › Kusto

Aqua Blizzard AV hits - Feb 2022

Status
available
Severity
high
Time window
6h
Source
github.com/Azure/Azure-Sentinel

'Identifies a match in the Security Alert table for MDATP hits related to the Aqua Blizzard actor'

MITRE ATT&CK coverage

TacticTechniques
PersistenceT1137 Office Application Startup

Rule body kusto

id: 18dbdc22-b69f-4109-9e39-723d9465f45f
name: Aqua Blizzard AV hits - Feb 2022
description: | 
  'Identifies a match in the Security Alert table for MDATP hits related to the Aqua Blizzard actor'
severity: High 
status: Available
requiredDataConnectors: 
  - connectorId: MicrosoftDefenderAdvancedThreatProtection
    dataTypes:
      - SecurityAlert (MDATP)
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics: 
  - Persistence
relevantTechniques:
  - T1137
tags:
  - Aqua Blizzard
query: |
  let iocs = externaldata(DateAdded:string,IoC:string,Type:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/ActiniumIOC.csv"] with (format="csv", ignoreFirstRecord=True);
  let AVHits = (iocs | where Type =~ "AVDetection"| project IoC);
  SecurityAlert
  | where ProviderName == 'MDATP'
  | extend ThreatName_ = tostring(parse_json(ExtendedProperties).ThreatName)
  | where ThreatName_ has_any (AVHits)
  | extend Directory = tostring(parse_json(Entities)[0].Directory), SHA256 = tostring(parse_json(tostring(parse_json(Entities)[0].FileHashes))[2].Value), FileName = tostring(parse_json(Entities)[0].Name), Hostname = tostring(parse_json(Entities)[6].FQDN)| extend AccountName = tostring(parse_json(tostring(parse_json(Entities)[6].LoggedOnUsers))[0].AccountName)
  | project TimeGenerated, AlertName, ThreatName_, ProviderName, AlertSeverity, Description, RemediationSteps, ExtendedProperties, Entities, FileName,SHA256, Directory, Hostname, AccountName
  | extend FileHash = SHA256, FileHashType = "SHA256"
  | extend Name = tostring(split(AccountName, "@")[0]), AccountUPNSuffix = tostring(split(AccountName, "@")[1])
  | extend Host = tostring(split(Hostname, ".")[0]), DomainIndex = toint(indexof(Hostname, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Hostname, DomainIndex + 1), Hostname)
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountName
      - identifier: Name
        columnName: Name
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Hostname
      - identifier: HostName
        columnName: Name
      - identifier: NTDomain
        columnName: HostNameDomain
  - entityType: FileHash
    fieldMappings:
      - identifier: Algorithm
        columnName: FileHashType
      - identifier: Value
        columnName: FileHash
version: 1.0.2
kind: Scheduled

Stages and Predicates

Let binding: iocs

let iocs = externaldata(DateAdded:string,IoC:string,Type:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/ActiniumIOC.csv"] with (format="csv", ignoreFirstRecord=True);

Let binding: AVHits

let AVHits = (iocs | where Type =~ "AVDetection"| project IoC);

Derived from iocs.

Stage 1: source

SecurityAlert

Stage 2: where

| where ProviderName == 'MDATP'

Stage 3: extend

| extend ThreatName_ = tostring(parse_json(ExtendedProperties).ThreatName)

Stage 4: where

| where ThreatName_ has_any (AVHits)

References AVHits (defined above).

Stage 5: extend

| extend Directory = tostring(parse_json(Entities)[0].Directory), SHA256 = tostring(parse_json(tostring(parse_json(Entities)[0].FileHashes))[2].Value), FileName = tostring(parse_json(Entities)[0].Name), Hostname = tostring(parse_json(Entities)[6].FQDN)

Stage 6: extend

| extend AccountName = tostring(parse_json(tostring(parse_json(Entities)[6].LoggedOnUsers))[0].AccountName)

Stage 7: project

| project TimeGenerated, AlertName, ThreatName_, ProviderName, AlertSeverity, Description, RemediationSteps, ExtendedProperties, Entities, FileName,SHA256, Directory, Hostname, AccountName

Stage 8: extend (4 consecutive steps)

| extend FileHash = SHA256, FileHashType = "SHA256"
| extend Name = tostring(split(AccountName, "@")[0]), AccountUPNSuffix = tostring(split(AccountName, "@")[1])
| extend Host = tostring(split(Hostname, ".")[0]), DomainIndex = toint(indexof(Hostname, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Hostname, DomainIndex + 1), Hostname)

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 transforms: cased corpus 13 (kusto 13)
ThreatName_match
  • AVHits

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
AccountNameproject
AlertNameproject
AlertSeverityproject
Descriptionproject
Directoryproject
Entitiesproject
ExtendedPropertiesproject
FileNameproject
Hostnameproject
ProviderNameproject
RemediationStepsproject
SHA256project
ThreatName_project
TimeGeneratedproject
FileHashextend
FileHashTypeextend
AccountUPNSuffixextend
Nameextend
DomainIndexextend
Hostextend
HostNameDomainextend