Detection rules › Kusto

Registry Run Keys - Suspicious Registry Run Keys

Group by
NormalizedRegistryValueData
Author
Cyb3rMonk
Source
github.com/Cyb3r-Monk/Threat-Hunting-and-Detection

Below query looks for suspicious additions to Run, RunOnce and several other registry keys. The query analyzes all values in the specified registry keys and finds anomalous ones based on commonality in the environment and excludes possible legitimate activities like software installations. The query might require tuning according to the environment.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

// Author: Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
// Link to original post: https://mergene.medium.com/threat-hunting-with-data-science-registry-run-keys-9ae329d1ad85
// Description: This query looks for suspicious additions to Run, RunOnce and several other registry keys. 
//              The query analyzes all values in the specified registry keys and finds anomalous ones based on
//              commonality in the environment and excludes possible legitimate activities like software installations.
//              The query might requiure tuning according to the environment.
let dataset= materialize (
DeviceRegistryEvents 
| where ActionType == "RegistryValueSet" 
// registry keys to be monitored
| where RegistryKey has @"Microsoft\Windows\CurrentVersion\RunOnce"
    or RegistryKey has @"Microsoft\Windows\CurrentVersion\RunOnceEx"
    or RegistryKey has @"Microsoft\Windows\CurrentVersion\Run"
    or RegistryKey has @"\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
    or (RegistryKey has @"\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders")
    or (RegistryKey has @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" and RegistryValueName == "Run")
    or (RegistryKey has @"\Session Manager" and RegistryValueName == "BootExecute")
    or (RegistryKey has @"Microsoft\Windows NT\CurrentVersion\Winlogon" and RegistryValueName == "Userinit")
    or (RegistryKey has @"Microsoft\Windows NT\CurrentVersion\Winlogon" and RegistryValueName == "Shell")
    or (RegistryKey has @"Microsoft\Windows NT\CurrentVersion\Windows" and RegistryValueName == "load")
    or RegistryKey has @"Microsoft\Windows NT\CurrentVersion\Winlogon\Notify" 
    or RegistryKey has @"\Software\Microsoft\Windows\CurrentVersion\RunServices"
    or RegistryKey has @"\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce"
    or RegistryKey has @"\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run"
        // below is related to the persistence using CLSID (junction folders, etc.)
    or (RegistryKey has @"SOFTWARE\Classes\CLSID" and RegistryKey endswith "InprocServer32" and isempty(RegistryValueName))
// exclude Config.Msi folder items
| where RegistryValueData !endswith @".rbf /restore"
// create NormalizedRegistryValueData field
| extend NormalizedRegistryValueData = replace(@'(C|D):\\Users\\.*?\\', @'C:\\Users\\userxx\\',RegistryValueData )
| extend NormalizedRegistryValueData = replace(@'\{.*\}', @'\{xxxxxxxxxx\}',NormalizedRegistryValueData ) //{fe07d7-d438-4dd9-bb0f-5721658f4f}
| extend NormalizedRegistryValueData = replace(@'\\[A-Za-z0-9-]+-[A-Za-z0-9]+\\', @'\\xxxxxxxxxx\\',NormalizedRegistryValueData ) //\fe07d7-d438-4dd9-bb0f-5721658f4f\
| extend NormalizedRegistryValueData = replace(@'\d+\.\d+\.\d+\.\d+', @'X.Y.Z.T',NormalizedRegistryValueData )
| extend NormalizedRegistryValueData = replace(@'-\d+\.\d+\.\d+', @'-X.Y.Z',NormalizedRegistryValueData )
| extend NormalizedRegistryValueData = replace(@'_\d+\.log', @'_XYZT.log',NormalizedRegistryValueData )
| extend NormalizedRegistryValueData = replace(@'--quiet|--passive', @'',NormalizedRegistryValueData )
| extend NormalizedRegistryValueData = replace(@'installSessionId\s[A-Za-z0-9-]+', @'installSessionId xxxxxx',NormalizedRegistryValueData )
| extend NormalizedRegistryValueData = replace(@'C:\\ProgramData\\.*?\\Microsoft\\Teams\\',@'C:\\ProgramData\\userxxx\\Microsoft\\Teams\\',NormalizedRegistryValueData)
);
dataset
| summarize dcount_device = dcount(DeviceId), total_count = count() by NormalizedRegistryValueData
| where dcount_device <=5 and total_count <20
| join kind=inner (dataset| where Timestamp > ago(1d)) on NormalizedRegistryValueData
| invoke FileProfile(InitiatingProcessSHA1,1000)
| where GlobalPrevalence <100
         or isempty(GlobalPrevalence)
         // inlcude processes that are involved in malicious attacks(e.g. office macro creating the registry key)
         or InitiatingProcessFileName in~ ("powershell.exe","reg.exe", "regedit.exe", "cmd.exe","winword.exe","excel.exe","powerpnt.exe")

Stages and Predicates

let dataset is inlined into the numbered stages below.

Stage 1: source

let dataset

Stage 2: source

DeviceRegistryEvents

Stage 3: where

where ActionType =~ "RegistryValueSet"

Stage 4: where

where ((RegistryKey endswith "InprocServer32" and RegistryKey contains @"SOFTWARE\Classes\CLSID" and isempty(RegistryValueName)) or (RegistryKey contains @"Microsoft\Windows NT\CurrentVersion\Windows" and RegistryValueName =~ "load") or (RegistryKey contains @"Microsoft\Windows NT\CurrentVersion\Winlogon" and RegistryValueName =~ "Shell") or (RegistryKey contains @"Microsoft\Windows NT\CurrentVersion\Winlogon" and RegistryValueName =~ "Userinit") or (RegistryKey contains @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" and RegistryValueName =~ "Run") or (RegistryKey contains @"\Session Manager" and RegistryValueName =~ "BootExecute") or RegistryKey contains @"Microsoft\Windows NT\CurrentVersion\Winlogon\Notify" or RegistryKey contains @"Microsoft\Windows\CurrentVersion\Run" or RegistryKey contains @"Microsoft\Windows\CurrentVersion\RunOnce" or RegistryKey contains @"Microsoft\Windows\CurrentVersion\RunOnceEx" or RegistryKey contains @"\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" or RegistryKey contains @"\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" or RegistryKey contains @"\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run" or RegistryKey contains @"\Software\Microsoft\Windows\CurrentVersion\RunServices" or RegistryKey contains @"\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce")

Stage 5: where

where not (RegistryValueData endswith ".rbf /restore")

Stage 6: extend (9 consecutive steps)

extend NormalizedRegistryValueData

Stage 7: summarize

summarize dcount_device, total_count by NormalizedRegistryValueData

Stage 8: where

where dcount_device <= 5 and total_count < 20

Stage 9: join

join kind=inner (dataset) on NormalizedRegistryValueData

Stage 10: invoke

invoke

Stage 11: where

where (isempty(GlobalPrevalence) or GlobalPrevalence < 100 or InitiatingProcessFileName in~ ("cmd.exe", "excel.exe", "powerpnt.exe", "powershell.exe", "reg.exe", "regedit.exe", "winword.exe"))

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
RegistryValueDataends_with.rbf /restoreexcludes:RegistryValueData field:"RegistryValueData" value:".rbf /restore"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
ActionTypeeq
  • RegistryValueSet
field:"EventType" kind:eq value:"RegistryValueSet"
GlobalPrevalenceis_null
  • (no value, null check)
field:"GlobalPrevalence" kind:is_null
GlobalPrevalencelt
  • 100
field:"GlobalPrevalence" kind:lt value:"100"
InitiatingProcessFileNamein
  • cmd.exe
  • excel.exe
  • powerpnt.exe
  • powershell.exe
  • reg.exe
  • regedit.exe
  • winword.exe
field:"parent_process_name" kind:in
RegistryKeyends_with
  • InprocServer32
field:"TargetObject" kind:ends_with value:"InprocServer32"
RegistryKeymatch
  • Microsoft\Windows NT\CurrentVersion\Windows transforms: term
  • Microsoft\Windows NT\CurrentVersion\Winlogon transforms: term
  • Microsoft\Windows NT\CurrentVersion\Winlogon\Notify transforms: term
  • Microsoft\Windows\CurrentVersion\Run transforms: term
  • Microsoft\Windows\CurrentVersion\RunOnce transforms: term
  • Microsoft\Windows\CurrentVersion\RunOnceEx transforms: term
  • SOFTWARE\Classes\CLSID transforms: term
  • Software\Microsoft\Windows\CurrentVersion\Policies\Explorer transforms: term
  • \Microsoft\Windows\CurrentVersion\Explorer\Shell Folders transforms: term
  • \Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders transforms: term
  • \Session Manager transforms: term
  • \Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run transforms: term
  • \Software\Microsoft\Windows\CurrentVersion\RunServices transforms: term
  • \Software\Microsoft\Windows\CurrentVersion\RunServicesOnce transforms: term
field:"TargetObject" kind:match
RegistryValueNameeq
  • BootExecute
  • Run
  • Shell
  • Userinit
  • load
field:"RegistryValueName" kind:eq
RegistryValueNameis_null
  • (no value, null check)
field:"RegistryValueName" kind:is_null
dcount_devicele
  • 5
field:"dcount_device" kind:le value:"5"
total_countlt
  • 20
field:"total_count" kind:lt value:"20"

Output fields

These fields are emitted when the rule matches.

FieldSource
NormalizedRegistryValueDatasummarize
dcount_devicesummarize
total_countsummarize