Detection rules › Kusto
Microsoft COVID-19 file hash indicator matches
'Identifies a match in CommonSecurityLog Event data from any FileHash published in the Microsoft COVID-19 Threat Intel Feed - as described at https://www.microsoft.com/security/blog/2020/05/14/open-sourcing-covid-threat-intelligence/'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Execution | T1204.002 User Execution: Malicious File |
Rule body kusto
id: 2be4ef67-a93f-4d8a-981a-88158cb73abd
name: Microsoft COVID-19 file hash indicator matches
description: |
'Identifies a match in CommonSecurityLog Event data from any FileHash published in the Microsoft COVID-19 Threat Intel Feed - as described at https://www.microsoft.com/security/blog/2020/05/14/open-sourcing-covid-threat-intelligence/'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
relevantTechniques:
- T1204.002
query: |
let dt_lookBack = 1h;
let covidIndicators = (externaldata(TimeGenerated:datetime, FileHashValue:string, FileHashType: string, TlpLevel: string, Product: string, ThreatType: string, Description: string )
[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.Covid19.Indicators.csv"] with (format="csv"));
let fileHashIndicators = covidIndicators
| where isnotempty(FileHashValue);
// Handle matches against both lower case and uppercase versions of the hash:
(fileHashIndicators | extend FileHashValue = tolower(FileHashValue)
| union (fileHashIndicators | extend FileHashValue = toupper(FileHashValue)))
// using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
| join kind=innerunique (
CommonSecurityLog | where TimeGenerated >= ago(dt_lookBack)
| where isnotempty(FileHash)
| extend CommonSecurityLog_TimeGenerated = TimeGenerated
)
on $left.FileHashValue == $right.FileHash
| summarize CommonSecurityLog_TimeGenerated = arg_max(CommonSecurityLog_TimeGenerated, *) by FileHashValue
| project CommonSecurityLog_TimeGenerated, FileHashValue, FileHashType, Description, ThreatType,
SourceIP, SourcePort, DestinationIP, DestinationPort, SourceUserID, SourceUserName, DeviceName, DeviceAction,
RequestURL, DestinationUserName, DestinationUserID, ApplicationProtocol, Activity
| extend AccountName = tostring(split(SourceUserName, "@")[0]), AccountUPNSuffix = tostring(split(SourceUserName, "@")[1])
| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: SourceUserName
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: HostNameDomain
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
- entityType: FileHash
fieldMappings:
- identifier: Value
columnName: FileHashValue
- identifier: Algorithm
columnName: FileHashType
version: 1.3.6
kind: Scheduled
Stages and Predicates
Parameters
let dt_lookBack = 1h;
Let binding: covidIndicators
let covidIndicators = (externaldata(TimeGenerated:datetime, FileHashValue:string, FileHashType: string, TlpLevel: string, Product: string, ThreatType: string, Description: string )
[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.Covid19.Indicators.csv"] with (format="csv"));
The stages below define let fileHashIndicators (the rule's main pipeline source).
Stage 1: source
covidIndicators
Stage 2: where
| where isnotempty(FileHashValue)
The stages below run on fileHashIndicators (the outer pipeline).
Stage 3: extend
fileHashIndicators
| extend FileHashValue = tolower(FileHashValue)
Stage 4: union
| union
Stage 5: source
covidIndicators
Stage 6: where
| where isnotempty(FileHashValue)
Stage 7: extend
| extend FileHashValue = toupper(FileHashValue)
Stage 8: join
| join kind=innerunique (
CommonSecurityLog | where TimeGenerated >= ago(dt_lookBack)
| where isnotempty(FileHash)
| extend CommonSecurityLog_TimeGenerated = TimeGenerated
)
on $left.FileHashValue == $right.FileHash
Stage 9: summarize
| summarize CommonSecurityLog_TimeGenerated = arg_max(CommonSecurityLog_TimeGenerated, *) by FileHashValue
Stage 10: project
| project CommonSecurityLog_TimeGenerated, FileHashValue, FileHashType, Description, ThreatType,
SourceIP, SourcePort, DestinationIP, DestinationPort, SourceUserID, SourceUserName, DeviceName, DeviceAction,
RequestURL, DestinationUserName, DestinationUserID, ApplicationProtocol, Activity
Stage 11: extend (3 consecutive steps)
| extend AccountName = tostring(split(SourceUserName, "@")[0]), AccountUPNSuffix = tostring(split(SourceUserName, "@")[1])
| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
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 |
|---|---|---|
FileHash | is_not_null | |
FileHashValue | is_not_null |
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 |
|---|---|
Activity | project |
ApplicationProtocol | project |
CommonSecurityLog_TimeGenerated | project |
Description | project |
DestinationIP | project |
DestinationPort | project |
DestinationUserID | project |
DestinationUserName | project |
DeviceAction | project |
DeviceName | project |
FileHashType | project |
FileHashValue | project |
RequestURL | project |
SourceIP | project |
SourcePort | project |
SourceUserID | project |
SourceUserName | project |
ThreatType | project |
AccountName | extend |
AccountUPNSuffix | extend |
DomainIndex | extend |
HostName | extend |
HostNameDomain | extend |