Detection rules › Kusto

Remote File Creation with PsExec

Status
available
Severity
high
Time window
10m
Group by
DeviceId, DeviceName, InitiatingProcessFileName, TimeWindow
Source
github.com/Azure/Azure-Sentinel

This query was originally published in the threat analytics report, Ryuk ransomware. There is also a related blog. Ryuk is human-operated ransomware. Much like DoppelPaymer ransomware, Ryuk is spread manually, often on networks that are already infected with Trickbot. Ryuk operators use PsExec to manually spread the ransomware to other devices. The following query detects remote file creation events that might indicate an active attack. The See also section below lists links to other queries associated with Ryuk ransomware. References: https://www.microsoft.com/security/blog/2020/03/05/human-operated-ransomware-attacks-a-preventable-disaster/ https://www.microsoft.com/en-us/wdsi/threats/malware-encyclopedia-description?Name=Ransom:Win32/Ryuk.AA https://www.microsoft.com/security/blog/2020/03/05/human-operated-ransomware-attacks-a-preventable-disaster/ https://docs.microsoft.com/sysinternals/downloads/psexec

MITRE ATT&CK coverage

TacticTechniques
Lateral MovementT1570 Lateral Tool Transfer

Event coverage

Rule body kusto

id: 35ab0d58-baab-4154-87ed-fa2f69797e9e
name: Remote File Creation with PsExec
description: |
  This query was originally published in the threat analytics report, Ryuk ransomware. There is also a related blog.
  Ryuk is human-operated ransomware. Much like DoppelPaymer ransomware, Ryuk is spread manually, often on networks that are already infected with Trickbot.
  Ryuk operators use PsExec to manually spread the ransomware to other devices.
  The following query detects remote file creation events that might indicate an active attack.
  The See also section below lists links to other queries associated with Ryuk ransomware.
  References:
  https://www.microsoft.com/security/blog/2020/03/05/human-operated-ransomware-attacks-a-preventable-disaster/
  https://www.microsoft.com/en-us/wdsi/threats/malware-encyclopedia-description?Name=Ransom:Win32/Ryuk.AA
  https://www.microsoft.com/security/blog/2020/03/05/human-operated-ransomware-attacks-a-preventable-disaster/
  https://docs.microsoft.com/sysinternals/downloads/psexec
severity: High
status: Available
requiredDataConnectors:
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceFileEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - LateralMovement
relevantTechniques:
  - T1570
tags:
  - Ryuk
  - Ransomware
  - PsExec
query: |
  // Find PsExec creating multiple files on remote machines in a 10-minute window
  DeviceFileEvents
  // Looking for PsExec by accepteula command flag
  | where InitiatingProcessCommandLine has "accepteula"
  // Remote machines and file is exe
  | where FolderPath has "\\\\" and FileName endswith ".exe"
  | extend Exe = countof(InitiatingProcessCommandLine, ".exe")
  // Checking to see if command line has 2 .exe or .bat
  | where InitiatingProcessCommandLine !has ".ps1" and Exe > 1 or
  InitiatingProcessCommandLine has ".bat"
  // Exclusions: Remove the following line to widen scope of AHQ
  | where not(InitiatingProcessCommandLine has_any("batch", "auditpol",
  "script", "scripts", "illusive", "rebootrequired"))
  | summarize FileCount = dcount(FolderPath), make_set(SHA1, 100000), make_set(FolderPath, 100000),
  make_set(FileName, 100000), make_set(InitiatingProcessCommandLine, 100000) by DeviceId, DeviceName,
  TimeWindow=bin(TimeGenerated, 10m), InitiatingProcessFileName
  | where FileCount > 4
  | extend HostName = iff(DeviceName has '.', substring(DeviceName, 0, indexof(DeviceName, '.')), DeviceName)
  | extend DnsDomain = iff(DeviceName has '.', substring(DeviceName, indexof(DeviceName, '.') + 1), "")
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: DnsDomain
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

DeviceFileEvents

Stage 2: where

| where InitiatingProcessCommandLine has "accepteula"

Stage 3: where

| where FolderPath has "\\\\" and FileName endswith ".exe"

Stage 4: extend

| extend Exe = countof(InitiatingProcessCommandLine, ".exe")

Stage 5: where

| where InitiatingProcessCommandLine !has ".ps1" and Exe > 1 or
InitiatingProcessCommandLine has ".bat"

Stage 6: where

| where not(InitiatingProcessCommandLine has_any("batch", "auditpol",
"script", "scripts", "illusive", "rebootrequired"))

Stage 7: summarize

| summarize FileCount = dcount(FolderPath), make_set(SHA1, 100000), make_set(FolderPath, 100000),
make_set(FileName, 100000), make_set(InitiatingProcessCommandLine, 100000) by DeviceId, DeviceName,
TimeWindow=bin(TimeGenerated, 10m), InitiatingProcessFileName
Threshold
gt 4

Stage 8: where

| where FileCount > 4

Stage 9: extend

| extend HostName = iff(DeviceName has '.', substring(DeviceName, 0, indexof(DeviceName, '.')), DeviceName)
HostName =
ifDeviceName has "."substring(DeviceName, 0, indexof(DeviceName, '.'))
elseDeviceName

Stage 10: extend

| extend DnsDomain = iff(DeviceName has '.', substring(DeviceName, indexof(DeviceName, '.') + 1), "")
DnsDomain =
ifDeviceName has "."substring(DeviceName, (indexof(DeviceName, '.') + 1))
else""

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
InitiatingProcessCommandLinematchbatch, auditpol, script, scripts, illusive, rebootrequired

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.

FieldKindValues
Exegt
  • 1 transforms: cased
FileCountgt
  • 4 transforms: cased
FileNameends_with
  • .exe corpus 2 (kusto 2)
FolderPathmatch
  • \\\\ transforms: term
InitiatingProcessCommandLinematch
  • .bat transforms: term corpus 11 (sigma 9, elastic 1, kusto 1)
  • accepteula transforms: term corpus 7 (sigma 3, kusto 3, splunk 1)

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.

FieldSource
DeviceIdsummarize
DeviceNamesummarize
FileCountsummarize
InitiatingProcessFileNamesummarize
TimeWindowsummarize
HostNameextend
DnsDomainextend