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 |
Rule body
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 fileHashIndicators is inlined into the numbered stages below.
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"));
Stages 1 to 2 define let fileHashIndicators (the rule's main pipeline source); stages 3 to 11 combine it with further branches.
Stage 1: source
covidIndicators
Stage 2: where
| where isnotempty(FileHashValue)
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
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
FileHash | is_not_null | field:"FileHash" kind:is_not_null | |
FileHashValue | is_not_null | field:"FileHashValue" kind:is_not_null |
Output fields
These fields are emitted when the rule matches.
| 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 |