Detection rules › Kusto
Malware in the recycle bin
The query detects Windows binaries that can be used for executing malware and have been hidden in the recycle bin. The list of these binaries is sourced from https://lolbas-project.github.io/ References: https://azure.microsoft.com/blog/how-azure-security-center-helps-reveal-a-cyberattack/.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Stealth |
Telemetry coverage
| Provider | Record / event type |
|---|---|
| Security-Auditing | Event ID 4688: A new process has been created. |
Rule body
id: 75bf9902-0789-47c1-a5d8-f57046aa72df
name: Malware in the recycle bin
description: |
'The query detects Windows binaries that can be used for executing malware and have been hidden in the recycle bin.
The list of these binaries is sourced from https://lolbas-project.github.io/
References: https://azure.microsoft.com/blog/how-azure-security-center-helps-reveal-a-cyberattack/.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsForwardedEvents
dataTypes:
- WindowsEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1564
query: |
let procList = externaldata(Process:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv"] with (format="csv", ignoreFirstRecord=True);
let recycle_bin_paths = dynamic([@":\RECYCLER", @":\$RECYCLE.BIN"]);
let ProcessCreationEvents=(union isfuzzy=true
(SecurityEvent
| where EventID==4688
| where isnotempty(CommandLine)
| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,
FileName = Process, CommandLine, ParentProcessName
),
(WindowsEvent
| where EventID==4688 and EventData has_any (procList) and EventData has_any (recycle_bin_paths)
| extend CommandLine = tostring(EventData.CommandLine)
| where isnotempty(CommandLine)
| extend SubjectUserName = tostring(EventData.SubjectUserName)
| extend SubjectDomainName = tostring(EventData.SubjectDomainName)
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend ParentProcessName = tostring(EventData.ParentProcessName)
| extend Process=tostring(split(NewProcessName, '\\')[-1])
| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,
FileName = Process, CommandLine, ParentProcessName
));
ProcessCreationEvents
| where FileName in~ (procList)
| where CommandLine has_any (recycle_bin_paths)
| project StartTimeUtc = TimeGenerated, Computer, Account, NewProcessName, FileName, CommandLine, ParentProcessName
| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Account
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: DnsDomain
version: 1.1.6
kind: Scheduled
Stages and Predicates
Stage 0: let
let procList = externaldata(Process:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv"] with (format="csv", ignoreFirstRecord=True);
let recycle_bin_paths = dynamic([@":\RECYCLER", @":\$RECYCLE.BIN"]);
let ProcessCreationEvents = (union <inlined as stages below>;
Stage 1: source
let ProcessCreationEvents
Stage 2: union
union of 2 branches
Stage 3: source
SecurityEvent
Stage 4: where
| where EventID==4688
Stage 5: where
| where isnotempty(CommandLine)
Stage 6: project
| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,
FileName = Process, CommandLine, ParentProcessName
Stage 7: source
WindowsEvent
Stage 8: where
| where EventID==4688 and EventData has_any (procList) and EventData has_any (recycle_bin_paths)
Stage 9: extend
| extend CommandLine = tostring(EventData.CommandLine)
Stage 10: where
| where isnotempty(CommandLine)
Stage 11: extend (5 consecutive steps)
| extend SubjectUserName = tostring(EventData.SubjectUserName)
| extend SubjectDomainName = tostring(EventData.SubjectDomainName)
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend ParentProcessName = tostring(EventData.ParentProcessName)
| extend Process=tostring(split(NewProcessName, '\\')[-1])
Stage 12: project
| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,
FileName = Process, CommandLine, ParentProcessName
Stage 13: where
where FileName =~ "procList"
Stage 14: where
where (CommandLine contains @":\RECYCLER" or CommandLine contains @":\$RECYCLE.BIN")
Stage 15: project
project Account, CommandLine, Computer, FileName, NewProcessName, ParentProcessName, StartTimeUtc
Stage 16: extend
extend DnsDomain, HostName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CommandLine | is_not_null | field:"CommandLine" kind:is_not_null | |
CommandLine | match |
| field:"CommandLine" kind:match |
EventData | match |
| field:"EventData" kind:match |
EventID | eq |
| field:"EventID" kind:eq value:"4688" |
FileName | in |
| field:"file_name" kind:in value:"procList" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Account | project |
CommandLine | project |
Computer | project |
FileName | project |
NewProcessName | project |
ParentProcessName | project |
StartTimeUtc | project |
DnsDomain | extend |
HostName | extend |