Detection rules › Kusto

Mercury - Domain, Hash and IP IOCs - August 2022

Severity
high
Time window
12h
Author
Ajeet Prakash
Source
github.com/Azure/Azure-Sentinel

Identifies a match across various data feeds for domains, hashes and IP IOC related to Mercury Reference: https://www.microsoft.com/security/blog/2022/08/25/mercury-leveraging-log4j-2-vulnerabilities-in-unpatched-systems-to-target-israeli-organizations/

MITRE ATT&CK coverage

TacticTechniques
Command & Control

Telemetry coverage

Rule body

id: ae10c588-7ff7-486c-9920-ab8b0bdb6ede
name: Mercury - Domain, Hash and IP IOCs - August 2022
description: | 
  'Identifies a match across various data feeds for domains, hashes and IP IOC related to Mercury
   Reference:  https://www.microsoft.com/security/blog/2022/08/25/mercury-leveraging-log4j-2-vulnerabilities-in-unpatched-systems-to-target-israeli-organizations/'
severity: High 
requiredDataConnectors: 
  - connectorId: DNS
    dataTypes:
      - DnsEvents
  - connectorId: AzureMonitor(VMInsights)
    dataTypes:
      - VMConnection
  - connectorId: F5
    dataTypes:
      - CommonSecurityLog
  - connectorId: CiscoASA
    dataTypes: 
      - CommonSecurityLog
  - connectorId: PaloAltoNetworks
    dataTypes: 
      - CommonSecurityLog
  - connectorId: Fortinet
    dataTypes: 
      - CommonSecurityLog
  - connectorId: CheckPoint
    dataTypes: 
      - CommonSecurityLog
  - connectorId: CEF
    dataTypes: 
      - CommonSecurityLog               
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceNetworkEvents
      - DeviceFileEvents
      - DeviceImageLoadEvents
  - connectorId: Office365
    dataTypes:
      - OfficeActivity
  - connectorId: AzureFirewall
    dataTypes: 
      - AzureDiagnostics
      - AZFWApplicationRule
      - AZFWDnsQuery
  - connectorId: WindowsFirewall
    dataTypes:
      - WindowsFirewall      
queryFrequency: 12h 
queryPeriod: 12h 
triggerOperator: gt 
triggerThreshold: 0 
tactics: 
  - CommandAndControl
relevantTechniques:
  - T1071
tags:
  - Mercury
  - Schema: ASIMFileEvent
    SchemaVersion: 0.1.0
query: |
  let iocs = externaldata(DateAdded:string,IoC:string,Type:string,TLP:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Mercury_August2022.csv"] with (format="csv", ignoreFirstRecord=True);
  let sha256Hashes = (iocs | where Type =~ "sha256" | project IoC);
  let IPList = (iocs | where Type =~ "ip"| project IoC);
  let domains = (iocs | where Type =~ "domainname"| project IoC);
  let IPRegex = '[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}';
  (union isfuzzy=true
  (CommonSecurityLog
  | where SourceIP in (IPList) or DestinationIP in (IPList) or DestinationHostName has_any (domains) or RequestURL has_any (domains) or Message has_any (IPList)
  | parse Message with * '(' DNSName ')' * 
  | project TimeGenerated, SourceIP, DestinationIP, Message, SourceUserID, RequestURL, DNSName, Type
  | extend MessageIP = extract(IPRegex, 0, Message), RequestIP = extract(IPRegex, 0, RequestURL)
  | extend IPMatch = case(SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", MessageIP in (IPList), "Message", RequestURL has_any (domains), "RequestUrl", "NoMatch")
  | extend IPAddress = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, IPMatch == "Message", MessageIP, "NoMatch")
  | extend AccountName = tostring(split(SourceUserID, "@")[0]), AccountUPNSuffix = tostring(split(SourceUserID, "@")[1])
  ),
  (DnsEvents
  | where IPAddresses in (IPList) or Name in~ (domains)
  | project TimeGenerated, Computer, IPAddresses, Name, ClientIP, Type
  | extend IPAddress = IPAddresses, DNSName = Name, Computer
  ),
  (VMConnection
  | where SourceIp in (IPList) or DestinationIp in (IPList) or RemoteDnsCanonicalNames has_any (domains)
  | parse RemoteDnsCanonicalNames with * '["' DNSName '"]' *
  | project TimeGenerated, Computer, Direction, ProcessName, SourceIp, DestinationIp, DestinationPort, RemoteDnsQuestions, DNSName,BytesSent, BytesReceived, RemoteCountry, Type
  | extend IPMatch = case( SourceIp in (IPList), "SourceIP", DestinationIp in (IPList), "DestinationIP", "None") 
  | extend IPAddress = case(IPMatch == "SourceIP", SourceIp, IPMatch == "DestinationIP", DestinationIp, "NoMatch"), File = ProcessName
  ),
  (Event
  | where Source == "Microsoft-Windows-Sysmon"
  | where EventID == 3
  | extend EvData = parse_xml(EventData)
  | extend EventDetail = EvData.DataItem.EventData.Data
  | extend SourceIP = tostring(EventDetail.[9].["#text"]), DestinationIP = tostring(EventDetail.[14].["#text"]), Image = tostring(EventDetail.[4].["#text"])
  | where SourceIP in (IPList) or DestinationIP in (IPList)
  | project TimeGenerated, SourceIP, DestinationIP, Image, UserName, Computer, Type
  | extend IPMatch = case( SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", "None")
  | extend AccountNT = UserName, File = tostring(split(Image, '\\', -1)[-1]), IPAddress = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, "None")
  ), 
  (OfficeActivity
  | where ClientIP in (IPList) 
  | project TimeGenerated, UserAgent, Operation, RecordType, UserId, ClientIP, Type
  | extend IPAddress = ClientIP, AccountUPN = UserId, AccountUPNName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
  ),
  (DeviceNetworkEvents
  | where RemoteUrl has_any (domains) or RemoteIP in (IPList) or InitiatingProcessSHA256 in (sha256Hashes)
  | project TimeGenerated, ActionType, DeviceId, Computer = DeviceName, InitiatingProcessSHA256, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessCommandLine, InitiatingProcessFolderPath, InitiatingProcessId, InitiatingProcessParentFileName, InitiatingProcessFileName, RemoteIP, RemoteUrl, RemotePort, LocalIP, Type
  | extend IPAddress = RemoteIP, FileHash = InitiatingProcessSHA256
  | extend AccountUPN = InitiatingProcessAccountName, AccountUPNName = tostring(split(InitiatingProcessAccountName, "@")[0]), AccountUPNSuffix = tostring(split(InitiatingProcessAccountName, "@")[1])
  ),
  (WindowsFirewall
  | where SourceIP in (IPList) or DestinationIP in (IPList) 
  | project TimeGenerated, Computer, CommunicationDirection, SourceIP, DestinationIP, SourcePort, DestinationPort, Type
  | extend IPMatch = case( SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", "None")
  | extend IPAddress = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, "None")
  ),
  (AzureDiagnostics 
  | where ResourceType == "AZUREFIREWALLS"
  | where Category == "AzureFirewallApplicationRule"
  | parse msg_s with Protocol 'request from ' SourceHost ':' SourcePort 'to ' DestinationHost ':' DestinationPort '. Action:' Action
  | where isnotempty(DestinationHost)
  | where DestinationHost has_any (IPList) or DestinationHost has_any (domains) 
  | extend DNSName = DestinationHost, IPAddress = SourceHost
  ),
  (AzureDiagnostics
  | where ResourceType == "AZUREFIREWALLS"
  | where Category == "AzureFirewallNetworkRule"
  | where msg_s has_any (IPList)
  | parse msg_s with Protocol " request from " SourceIP ":" SourcePortInt:int " to " TargetIP ":" TargetPortInt:int *
  | parse kind=regex flags=U msg_s with * ". Action\\: " Action1a "\\."
  | parse msg_s with * ". Policy: " Policy ". Rule Collection Group: " RuleCollectionGroup "." *
  | parse msg_s with * " Rule Collection: "  RuleCollection ". Rule: " Rule 
  | extend IPAddress = SourceIP
  ),
  (AzureDiagnostics
  | where ResourceType == "AZUREFIREWALLS"
  | where Category == "AzureFirewallDnsProxy"
  | where msg_s has_any (domains)
  | parse msg_s with "DNS Request: " SourceIP ":" SourcePortInt:int " - " QueryID:int " " RequestType " " RequestClass " " hostname ". " protocol " " details
  | extend
      ResponseDuration = extract("[0-9]*.?[0-9]+s$", 0, msg_s),
      SourcePort = tostring(SourcePortInt),
      QueryID = tostring(QueryID)
  | project TimeGenerated,SourceIP,hostname,RequestType,ResponseDuration,details,msg_s
  | extend IPAddress = SourceIP
  ),
  (AZFWApplicationRule
  | where Fqdn has_any (domains) or Fqdn has_any (IPList)
  | extend IPAddress = SourceIp
  ),
  (AZFWDnsQuery
  | where isnotempty(QueryName)
  | where QueryName has_any (domains)
  | extend DNSName = QueryName, IPAddress = SourceIp
  ),
  (AZFWNetworkRule
  | where DestinationIp has_any (IPList)
  | extend IPAddress = SourceIp
  ),
  (CommonSecurityLog
  | where FileHash in (sha256Hashes)
  | project TimeGenerated, Message, SourceUserID, FileHash, Type
  | extend Algorithm = "SHA256", FileHash = tostring(FileHash), AccountUPN = SourceUserID, AccountUPNName = tostring(split(SourceUserID, "@")[0]), AccountUPNSuffix = tostring(split(SourceUserID, "@")[1])
  ),
  (imFileEvent
  | where TargetFileSHA256 has_any (sha256Hashes)
  | extend AccountNT = ActorUsername, Computer = DvcHostname, IPAddress = SrcIpAddr, CommandLine = ActingProcessCommandLine, FileHash = TargetFileSHA256
  | project Type, TimeGenerated, Computer, AccountNT, IPAddress, CommandLine, FileHash, Algorithm = "SHA256"
  ),
  (DeviceFileEvents
  | where SHA256 has_any (sha256Hashes)
  | project TimeGenerated, ActionType, DeviceId, Computer = DeviceName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessCommandLine, InitiatingProcessFolderPath, InitiatingProcessId, InitiatingProcessParentFileName, InitiatingProcessFileName, InitiatingProcessSHA256, Type
  | extend Algorithm = "SHA256", FileHash = tostring(InitiatingProcessSHA256), CommandLine = InitiatingProcessCommandLine,Image = InitiatingProcessFolderPath
  | extend AccountUPN = InitiatingProcessAccountName, AccountUPNName = tostring(split(InitiatingProcessAccountName, "@")[0]), AccountUPNSuffix = tostring(split(InitiatingProcessAccountName, "@")[1])
  ),
  (DeviceImageLoadEvents
  | where SHA256 has_any (sha256Hashes)
  | project TimeGenerated, ActionType, DeviceId, Computer = DeviceName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessCommandLine, InitiatingProcessFolderPath, InitiatingProcessId, InitiatingProcessParentFileName, InitiatingProcessFileName, InitiatingProcessSHA256, Type
  | extend Algorithm = "SHA256", FileHash = tostring(InitiatingProcessSHA256), CommandLine = InitiatingProcessCommandLine,Image = InitiatingProcessFolderPath
  | extend AccountUPN = InitiatingProcessAccountName, AccountUPNName = tostring(split(InitiatingProcessAccountName, "@")[0]), AccountUPNSuffix = tostring(split(InitiatingProcessAccountName, "@")[1])
  ),
  (Event
  | where Source =~ "Microsoft-Windows-Sysmon"
  | where EventID == 1
  | extend EvData = parse_xml(EventData)
  | extend EventDetail = EvData.DataItem.EventData.Data
  | extend Image = EventDetail.[4].["#text"], CommandLine = EventDetail.[10].["#text"], Hashes = tostring(EventDetail.[17].["#text"])
  | extend Hashes = extract_all(@"(?P<key>\w+)=(?P<value>[a-zA-Z0-9]+)", dynamic(["key","value"]), Hashes)
  | extend Hashes = column_ifexists("Hashes", dynamic(["", ""])), CommandLine = column_ifexists("CommandLine", "")
  | mv-expand Hashes
  | where Hashes[0] =~ "SHA256" and Hashes[1] has_any (sha256Hashes) 
  | project TimeGenerated, EventDetail, AccountNT = UserName, Computer, Type, Source, Hashes, CommandLine, Image
  | extend Type = strcat(Type, ": ", Source), FileHash = tostring(Hashes[1]), Algorithm = tostring(Hashes[0])
  )
  )
  | extend AccountNTName = tostring(split(AccountNT, "\\")[1]), AccountNTDomain = tostring(split(AccountNT, "\\")[0])
  | 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: AccountUPN
      - identifier: Name
        columnName: AccountUPNName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountNT
      - identifier: Name
        columnName: AccountNTName
      - identifier: UPNSuffix
        columnName: AccountNTDomain
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Computer
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPAddress
  - entityType: FileHash
    fieldMappings:
      - identifier: Algorithm
        columnName: Algorithm
      - identifier: Value
        columnName: FileHash
version: 1.1.1
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Ajeet Prakash
    support:
        tier: Community
    categories:
        domains: [ "Security - Threat Intelligence" ]

Stages and Predicates

Stage 0: let

let iocs = externaldata(DateAdded:string,IoC:string,Type:string,TLP:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Mercury_August2022.csv"] with (format="csv", ignoreFirstRecord=True);
let sha256Hashes = (iocs | where Type =~ "sha256" | project IoC);
let IPList = (iocs | where Type =~ "ip"| project IoC);
let domains = (iocs | where Type =~ "domainname"| project IoC);
let IPRegex = '[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}';

Stage 1: union

union of 18 branches

Stage 2: source

CommonSecurityLog

Stage 3: where

| where SourceIP in (IPList) or DestinationIP in (IPList) or DestinationHostName has_any (domains) or RequestURL has_any (domains) or Message has_any (IPList)

Stage 4: parse

| parse Message with * '(' DNSName ')' *

Stage 5: project

| project TimeGenerated, SourceIP, DestinationIP, Message, SourceUserID, RequestURL, DNSName, Type

Stage 6: extend (4 consecutive steps)

| extend MessageIP = extract(IPRegex, 0, Message), RequestIP = extract(IPRegex, 0, RequestURL)
| extend IPMatch = case(SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", MessageIP in (IPList), "Message", RequestURL has_any (domains), "RequestUrl", "NoMatch")
| extend IPAddress = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, IPMatch == "Message", MessageIP, "NoMatch")
| extend AccountName = tostring(split(SourceUserID, "@")[0]), AccountUPNSuffix = tostring(split(SourceUserID, "@")[1])

Stage 7: source

DnsEvents

Stage 8: where

| where IPAddresses in (IPList) or Name in~ (domains)

Stage 9: project

| project TimeGenerated, Computer, IPAddresses, Name, ClientIP, Type

Stage 10: extend

| extend IPAddress = IPAddresses, DNSName = Name, Computer

Stage 11: source

VMConnection

Stage 12: where

| where SourceIp in (IPList) or DestinationIp in (IPList) or RemoteDnsCanonicalNames has_any (domains)

Stage 13: parse

| parse RemoteDnsCanonicalNames with * '["' DNSName '"]' *

Stage 14: project

| project TimeGenerated, Computer, Direction, ProcessName, SourceIp, DestinationIp, DestinationPort, RemoteDnsQuestions, DNSName,BytesSent, BytesReceived, RemoteCountry, Type

Stage 15: extend

| extend IPMatch = case( SourceIp in (IPList), "SourceIP", DestinationIp in (IPList), "DestinationIP", "None")
IPMatch =
ifSourceIp in ("IPList")"SourceIP"
elifDestinationIp in ("IPList")"DestinationIP"
else"None"

Stage 16: extend

| extend IPAddress = case(IPMatch == "SourceIP", SourceIp, IPMatch == "DestinationIP", DestinationIp, "NoMatch"), File = ProcessName
IPAddress =
ifIPMatch == "SourceIP"SourceIp
elifIPMatch == "DestinationIP"DestinationIp
else"NoMatch"

Stage 17: source

Event

Stage 18: where

| where Source == "Microsoft-Windows-Sysmon"

Stage 19: where

| where EventID == 3

Stage 20: extend (3 consecutive steps)

| extend EvData = parse_xml(EventData)
| extend EventDetail = EvData.DataItem.EventData.Data
| extend SourceIP = tostring(EventDetail.[9].["#text"]), DestinationIP = tostring(EventDetail.[14].["#text"]), Image = tostring(EventDetail.[4].["#text"])

Stage 21: where

| where SourceIP in (IPList) or DestinationIP in (IPList)

Stage 22: project

| project TimeGenerated, SourceIP, DestinationIP, Image, UserName, Computer, Type

Stage 23: extend

| extend IPMatch = case( SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", "None")
IPMatch =
ifSourceIP in ("IPList")"SourceIP"
elifDestinationIP in ("IPList")"DestinationIP"
else"None"

Stage 24: extend

| extend AccountNT = UserName, File = tostring(split(Image, '\\', -1)[-1]), IPAddress = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, "None")
IPAddress =
ifIPMatch == "SourceIP"SourceIP
elifIPMatch == "DestinationIP"DestinationIP
else"None"

Stage 25: source

OfficeActivity

Stage 26: where

| where ClientIP in (IPList)

Stage 27: project

| project TimeGenerated, UserAgent, Operation, RecordType, UserId, ClientIP, Type

Stage 28: extend

| extend IPAddress = ClientIP, AccountUPN = UserId, AccountUPNName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])

Stage 29: source

DeviceNetworkEvents

Stage 30: where

| where RemoteUrl has_any (domains) or RemoteIP in (IPList) or InitiatingProcessSHA256 in (sha256Hashes)

Stage 31: project

| project TimeGenerated, ActionType, DeviceId, Computer = DeviceName, InitiatingProcessSHA256, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessCommandLine, InitiatingProcessFolderPath, InitiatingProcessId, InitiatingProcessParentFileName, InitiatingProcessFileName, RemoteIP, RemoteUrl, RemotePort, LocalIP, Type

Stage 32: extend

| extend IPAddress = RemoteIP, FileHash = InitiatingProcessSHA256

Stage 33: extend

| extend AccountUPN = InitiatingProcessAccountName, AccountUPNName = tostring(split(InitiatingProcessAccountName, "@")[0]), AccountUPNSuffix = tostring(split(InitiatingProcessAccountName, "@")[1])

Stage 34: source

WindowsFirewall

Stage 35: where

| where SourceIP in (IPList) or DestinationIP in (IPList)

Stage 36: project

| project TimeGenerated, Computer, CommunicationDirection, SourceIP, DestinationIP, SourcePort, DestinationPort, Type

Stage 37: extend

| extend IPMatch = case( SourceIP in (IPList), "SourceIP", DestinationIP in (IPList), "DestinationIP", "None")
IPMatch =
ifSourceIP in ("IPList")"SourceIP"
elifDestinationIP in ("IPList")"DestinationIP"
else"None"

Stage 38: extend

| extend IPAddress = case(IPMatch == "SourceIP", SourceIP, IPMatch == "DestinationIP", DestinationIP, "None")
IPAddress =
ifIPMatch == "SourceIP"SourceIP
elifIPMatch == "DestinationIP"DestinationIP
else"None"

Stage 39: source

AzureDiagnostics

Stage 40: where

| where ResourceType == "AZUREFIREWALLS"

Stage 41: where

| where Category == "AzureFirewallApplicationRule"

Stage 42: parse

| parse msg_s with Protocol 'request from ' SourceHost ':' SourcePort 'to ' DestinationHost ':' DestinationPort '. Action:' Action

Stage 43: where

| where isnotempty(DestinationHost)

Stage 44: where

| where DestinationHost has_any (IPList) or DestinationHost has_any (domains)

Stage 45: extend

| extend DNSName = DestinationHost, IPAddress = SourceHost

Stage 46: source

AzureDiagnostics

Stage 47: where

| where ResourceType == "AZUREFIREWALLS"

Stage 48: where

| where Category == "AzureFirewallNetworkRule"

Stage 49: where

| where msg_s has_any (IPList)

Stage 50: parse

| parse msg_s with Protocol " request from " SourceIP ":" SourcePortInt:int " to " TargetIP ":" TargetPortInt:int *

Stage 51: parse

| parse kind=regex flags=U msg_s with * ". Action\\: " Action1a "\\."

Stage 52: parse

| parse msg_s with * ". Policy: " Policy ". Rule Collection Group: " RuleCollectionGroup "." *

Stage 53: parse

| parse msg_s with * " Rule Collection: "  RuleCollection ". Rule: " Rule

Stage 54: extend

| extend IPAddress = SourceIP

Stage 55: source

AzureDiagnostics

Stage 56: where

| where ResourceType == "AZUREFIREWALLS"

Stage 57: where

| where Category == "AzureFirewallDnsProxy"

Stage 58: where

| where msg_s has_any (domains)

Stage 59: parse

| parse msg_s with "DNS Request: " SourceIP ":" SourcePortInt:int " - " QueryID:int " " RequestType " " RequestClass " " hostname ". " protocol " " details

Stage 60: extend

| extend
    ResponseDuration = extract("[0-9]*.?[0-9]+s$", 0, msg_s),
    SourcePort = tostring(SourcePortInt),
    QueryID = tostring(QueryID)

Stage 61: project

| project TimeGenerated,SourceIP,hostname,RequestType,ResponseDuration,details,msg_s

Stage 62: extend

| extend IPAddress = SourceIP

Stage 63: source

AZFWApplicationRule

Stage 64: where

| where Fqdn has_any (domains) or Fqdn has_any (IPList)

Stage 65: extend

| extend IPAddress = SourceIp

Stage 66: source

AZFWDnsQuery

Stage 67: where

| where isnotempty(QueryName)

Stage 68: where

| where QueryName has_any (domains)

Stage 69: extend

| extend DNSName = QueryName, IPAddress = SourceIp

Stage 70: source

AZFWNetworkRule

Stage 71: where

| where DestinationIp has_any (IPList)

Stage 72: extend

| extend IPAddress = SourceIp

Stage 73: source

CommonSecurityLog

Stage 74: where

| where FileHash in (sha256Hashes)

Stage 75: project

| project TimeGenerated, Message, SourceUserID, FileHash, Type

Stage 76: extend

| extend Algorithm = "SHA256", FileHash = tostring(FileHash), AccountUPN = SourceUserID, AccountUPNName = tostring(split(SourceUserID, "@")[0]), AccountUPNSuffix = tostring(split(SourceUserID, "@")[1])

Stage 77: source

imFileEvent

Stage 78: where

| where TargetFileSHA256 has_any (sha256Hashes)

Stage 79: extend

| extend AccountNT = ActorUsername, Computer = DvcHostname, IPAddress = SrcIpAddr, CommandLine = ActingProcessCommandLine, FileHash = TargetFileSHA256

Stage 80: project

| project Type, TimeGenerated, Computer, AccountNT, IPAddress, CommandLine, FileHash, Algorithm = "SHA256"

Stage 81: source

DeviceFileEvents

Stage 82: where

| where SHA256 has_any (sha256Hashes)

Stage 83: project

| project TimeGenerated, ActionType, DeviceId, Computer = DeviceName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessCommandLine, InitiatingProcessFolderPath, InitiatingProcessId, InitiatingProcessParentFileName, InitiatingProcessFileName, InitiatingProcessSHA256, Type

Stage 84: extend

| extend Algorithm = "SHA256", FileHash = tostring(InitiatingProcessSHA256), CommandLine = InitiatingProcessCommandLine,Image = InitiatingProcessFolderPath

Stage 85: extend

| extend AccountUPN = InitiatingProcessAccountName, AccountUPNName = tostring(split(InitiatingProcessAccountName, "@")[0]), AccountUPNSuffix = tostring(split(InitiatingProcessAccountName, "@")[1])

Stage 86: source

DeviceImageLoadEvents

Stage 87: where

| where SHA256 has_any (sha256Hashes)

Stage 88: project

| project TimeGenerated, ActionType, DeviceId, Computer = DeviceName, InitiatingProcessAccountDomain, InitiatingProcessAccountName, InitiatingProcessCommandLine, InitiatingProcessFolderPath, InitiatingProcessId, InitiatingProcessParentFileName, InitiatingProcessFileName, InitiatingProcessSHA256, Type

Stage 89: extend

| extend Algorithm = "SHA256", FileHash = tostring(InitiatingProcessSHA256), CommandLine = InitiatingProcessCommandLine,Image = InitiatingProcessFolderPath

Stage 90: extend

| extend AccountUPN = InitiatingProcessAccountName, AccountUPNName = tostring(split(InitiatingProcessAccountName, "@")[0]), AccountUPNSuffix = tostring(split(InitiatingProcessAccountName, "@")[1])

Stage 91: source

Event

Stage 92: where

| where Source =~ "Microsoft-Windows-Sysmon"

Stage 93: where

| where EventID == 1

Stage 94: extend (5 consecutive steps)

| extend EvData = parse_xml(EventData)
| extend EventDetail = EvData.DataItem.EventData.Data
| extend Image = EventDetail.[4].["#text"], CommandLine = EventDetail.[10].["#text"], Hashes = tostring(EventDetail.[17].["#text"])
| extend Hashes = extract_all(@"(?P<key>\w+)=(?P<value>[a-zA-Z0-9]+)", dynamic(["key","value"]), Hashes)
| extend Hashes = column_ifexists("Hashes", dynamic(["", ""])), CommandLine = column_ifexists("CommandLine", "")

Stage 95: mv-expand

| mv-expand Hashes

Stage 96: where

| where Hashes[0] =~ "SHA256" and Hashes[1] has_any (sha256Hashes)

Stage 97: project

| project TimeGenerated, EventDetail, AccountNT = UserName, Computer, Type, Source, Hashes, CommandLine, Image

Stage 98: extend (4 consecutive steps)

| extend Type = strcat(Type, ": ", Source), FileHash = tostring(Hashes[1]), Algorithm = tostring(Hashes[0])

Stage 99: project-away

project-away DomainIndex

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Categoryeq
  • AzureFirewallApplicationRule corpus 3 (kusto 3)
  • AzureFirewallDnsProxy corpus 2 (kusto 2)
  • AzureFirewallNetworkRule
field:"Category" kind:eq
ClientIPin
  • IPList corpus 2 (kusto 2)
field:"ClientIP" kind:in value:"IPList"
DestinationHostis_not_null
  • (no value, null check)
field:"DestinationHost" kind:is_not_null
DestinationHostmatch
  • IPList transforms: term
  • domains transforms: term corpus 2 (kusto 2)
field:"DestinationHost" kind:match
DestinationHostNamematch
  • domains transforms: term corpus 2 (kusto 2)
field:"DestinationHostName" kind:match value:"domains"
DestinationIPin
  • IPList corpus 2 (kusto 2)
field:"DestinationIP" kind:in value:"IPList"
DestinationIpin
  • IPList corpus 2 (kusto 2)
field:"dest_ip" kind:in value:"IPList"
DestinationIpmatch
  • IPList transforms: term corpus 2 (kusto 2)
field:"dest_ip" kind:match value:"IPList"
EventIDeq
  • 1 corpus 242 (splunk 226, kusto 15, elastic 1)
  • 3 corpus 25 (splunk 15, kusto 8, chronicle 2)
field:"EventID" kind:eq
FileHashin
  • sha256Hashes
field:"FileHash" kind:in value:"sha256Hashes"
Fqdnmatch
  • IPList transforms: term
  • domains transforms: term
field:"Fqdn" kind:match
Hashes[0]eq
  • SHA256 corpus 3 (kusto 3)
field:"Hashes[0]" kind:eq value:"SHA256"
Hashes[1]match
  • sha256Hashes transforms: term corpus 2 (kusto 2)
field:"Hashes[1]" kind:match value:"sha256Hashes"
IPAddressesin
  • IPList corpus 2 (kusto 2)
field:"IPAddresses" kind:in value:"IPList"
InitiatingProcessSHA256in
  • sha256Hashes corpus 3 (kusto 3)
field:"InitiatingProcessSHA256" kind:in value:"sha256Hashes"
Messagematch
  • IPList transforms: term corpus 2 (kusto 2)
field:"Message" kind:match value:"IPList"
Namein
  • domains corpus 2 (kusto 2)
field:"Name" kind:in value:"domains"
QueryNameis_not_null
  • (no value, null check)
field:"QueryName" kind:is_not_null
QueryNamematch
  • domains transforms: term
field:"QueryName" kind:match value:"domains"
RemoteDnsCanonicalNamesmatch
  • domains transforms: term corpus 2 (kusto 2)
field:"RemoteDnsCanonicalNames" kind:match value:"domains"
RemoteIPin
  • IPList corpus 2 (kusto 2)
field:"dest_ip" kind:in value:"IPList"
RemoteUrlmatch
  • domains transforms: term corpus 2 (kusto 2)
field:"DestinationHostname" kind:match value:"domains"
RequestURLmatch
  • domains transforms: term corpus 2 (kusto 2)
field:"RequestURL" kind:match value:"domains"
ResourceTypeeq
  • AZUREFIREWALLS corpus 3 (kusto 3)
field:"ResourceType" kind:eq value:"AZUREFIREWALLS"
SHA256match
  • sha256Hashes transforms: term corpus 3 (kusto 3)
field:"sha256" kind:match value:"sha256Hashes"
SourceIPin
  • IPList corpus 2 (kusto 2)
field:"SourceIP" kind:in value:"IPList"
SourceIpin
  • IPList corpus 2 (kusto 2)
field:"src_ip" kind:in value:"IPList"
TargetFileSHA256match
  • sha256Hashes transforms: term corpus 3 (kusto 3)
field:"sha256" kind:match value:"sha256Hashes"
msg_smatch
  • IPList transforms: term
  • domains transforms: term
field:"msg_s" kind:match

Output fields

These fields are emitted when the rule matches.

FieldSource
AccountNTproject
CommandLineproject
Computerproject
EventDetailproject
Hashesproject
Imageproject
Sourceproject
TimeGeneratedproject
Typeextend
Algorithmextend
FileHashextend
AccountNTDomainextend
AccountNTNameextend
HostNameextend
HostNameDomainextend