Detection rules › Kusto

Malware in the recycle bin

Status
available
Severity
medium
Time window
1d
Source
github.com/Azure/Azure-Sentinel

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

TacticTechniques
Stealth

Telemetry coverage

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.

FieldKindValuesSearch
CommandLineis_not_null
  • (no value, null check)
field:"CommandLine" kind:is_not_null
CommandLinematch
  • :\$RECYCLE.BIN transforms: term corpus 2 (sigma 1, kusto 1)
  • :\RECYCLER transforms: term
field:"CommandLine" kind:match
EventDatamatch
  • :\$RECYCLE.BIN transforms: term
  • :\RECYCLER transforms: term
  • procList transforms: term
field:"EventData" kind:match
EventIDeq
  • 4688 corpus 317 (splunk 283, kusto 33, elastic 1)
field:"EventID" kind:eq value:"4688"
FileNamein
  • procList
field:"file_name" kind:in value:"procList"

Output fields

These fields are emitted when the rule matches.

FieldSource
Accountproject
CommandLineproject
Computerproject
FileNameproject
NewProcessNameproject
ParentProcessNameproject
StartTimeUtcproject
DnsDomainextend
HostNameextend