Hunting Sandworm Team’s TTPs

montysecurity
6 min readNov 16, 2023

Introduction

This post is the result of reviewing the references for Sandworm Team’s MITRE Group page (as of November 2023). Searches are provided in KQL for Defender for Endpoint.

A few notes:

  • This does not cover every TTP they use. The focus is on process events.
  • No attribution work was done as a part of this analysis. I simply reviewed the existing references in MITRE and took them at face value.
  • Evidence of the TTP does not guarantee evidence of the TA and vice versa (many of these TTPs are common amongst various TAs).
  • In a lot of cases, I do not match on file names. This is by design to catch the activity if the binaries are renamed. However, the intended file name filters (if applicable) are put at the bottom of the queries and commented out.
  • If you spot any issues or mistakes, DM me on twitter [at]_montysecurity or just comment on this post.

Defense Evasion — RunDLL32 — T1218.011

Reference: BLACKENERGY & QUEDAGH The convergence of crimeware and APT attacks — F-Secure

DeviceProcessEvents
| where FileName =~ "rundll32.exe"
| where ProcessCommandLine contains "," // Specify entry point
| where ProcessCommandLine contains "-" // Hyphen seen in volume serial numbers
// it is unclear if the DLL file name or entry point (or both) is based on
// the volume serial number but this should catch both
// Look for rundll32.exe calling out to the internet
DeviceNetworkEvents
| where InitiatingProcessFileName =~ "rundll32.exe"

Discovery — System Information — T1082

Reference: BLACKENERGY & QUEDAGH The convergence of crimeware and APT attacks — F-Secure

// Processes that ran multiple of the enumeration commands
DeviceProcessEvents
| where FileName in~ ("systeminfo.exe", "tasklist.exe", "ipconfig.exe",
"netstat.exe", "route.exe", "tracert.exe", "ping.exe")
| summarize CommandsRan=dcount(FileName), MV_COMS=make_set(ProcessCommandLine) by
InitiatingProcessFolderPath,
InitiatingProcessId, DeviceName
| sort by CommandsRan desc nulls last
| mv-expand MV_COMS
// Processes that ran the exact number of enumeration commands
let EnumCommands = dynamic(["systeminfo.exe", "tasklist.exe", "ipconfig.exe",
"netstat.exe", "route.exe", "tracert.exe", "ping.exe"]);
let NumberOfCommands = array_length(EnumCommands);
let Hashes = DeviceProcessEvents
| where FileName in~ (EnumCommands)
| summarize NumberOfCommandsRan=dcount(FileName) by InitiatingProcessSHA256
| where NumberOfCommandsRan == NumberOfCommands
| distinct InitiatingProcessSHA256;
DeviceProcessEvents
| where InitiatingProcessSHA256 in (Hashes)

Lateral Movement, Credential Access & Impact — Multiple TTPs

Reference: https://www.microsoft.com/en-us/security/blog/2022/10/14/new-prestige-ransomware-impacts-organizations-in-ukraine-and-poland/

// comsvcs dumping memory, https://lolbas-project.github.io/lolbas/Libraries/comsvcs/
// ntdsutil creating ntds.dit, https://lolbas-project.github.io/lolbas/OtherMSBinaries/Ntdsutil/
// Impacket WMIExec
//// https://github.com/fortra/impacket/blob/master/examples/wmiexec.py
//// https://www.crowdstrike.com/blog/how-to-detect-and-prevent-impackets-wmiexec/
DeviceProcessEvents
| where ProcessCommandLine has_all ("comsvcs.dll", "MiniDump", "full")
or ProcessCommandLine has_all ("ac i ntds", "create", "full")
or ProcessCommandLine contains_cs "-NoP -NoL -sta -NonI -W Hidden -Exec Bypass -Enc "
or ProcessCommandLine contains_cs "/Q /c "
or InitiatingProcessFileName =~ "wmiprvse.exe"
// Stopping MS SQL Server
DeviceProcessEvents
| where ProcessCommandLine has_all ("stop", "MSSQLSERVER")
//| where FileName in~ ("net.exe", "net1.exe")
// Deletion of the backup catalog or shadow copies
DeviceProcessEvents
| where ProcessCommandLine has "delete"
| where ProcessCommandLine has_any ("catalog", "shadows")
| where ProcessCommandLine contains "quiet"
//| where FileName in~ ("wbadmin.exe", "vssadmin.exe")

Execution — Windows Command Shell — T1059.003

Reference: https://www.cisa.gov/news-events/ics-alerts/ics-alert-14-281-01e

// Arguments suggesting copying a txt file and running something
DeviceProcessEvents
| where ProcessCommandLine has_all ("copy", ".txt", "start")
//| where FileName =~ "cmd.exe"

Command & Control — Web Protocols — T1071.001

Reference: https://www.welivesecurity.com/2016/12/13/rise-telebots-analyzing-disruptive-killdisk-attacks/

// Processes contacting a Telegram Bot
DeviceNetworkEvents
| where RemoteUrl has_all ("api.telegram.org", "bot")

Initial Access — Spearphishing Attachment — T1566.001

Reference: https://www.boozallen.com/content/dam/boozallen/documents/2016/09/ukraine-report-when-the-lights-went-out.pdf

// Word or Excel executing commands
// Especially relevant if the dropper uses CMD/PowerShell, covered below
DeviceProcessEvents
| where InitiatingProcessFileName in~ ("winword.exe", "excel.exe")
// Word or Excel dropping files
DeviceFileEvents
| where ActionType == "FileCreated"
| where InitiatingProcessFileName in~ ("winword.exe", "excel.exe")

Execution & Lateral Movement — Multiple TTPs

Reference: https://www.boozallen.com/content/dam/boozallen/documents/2016/09/ukraine-report-when-the-lights-went-out.pdf

// PSExec executing commands
// https://www.logpoint.com/en/blog/hunting-for-psexec-artifacts-in-your-enterprise/
DeviceProcessEvents
| where InitiatingProcessFileName =~ "psexesvc.exe"
// Scheduled tasks
DeviceProcessEvents
| where ProcessCommandLine has_any ("/every:", "/next:")
or (ProcessCommandLine has " /tr "
and ProcessCommandLine has_any ("/create", "/change"))
//| where FileName in~ ("at.exe", "schtasks.exe")

Reference: https://www.dragos.com/wp-content/uploads/CRASHOVERRIDE2018.pdf

// Processes spawned by MS SQL
DeviceProcessEvents
| where InitiatingProcessFileName =~ "sqlserver.exe"
// PowerShell contacting web server and using invoke-expression
DeviceProcessEvents
| where ProcessCommandLine has_any ("http", "https")
| where ProcessCommandLine contains "://"
| where ProcessCommandLine contains "IEX"
or ProcessCommandLine contains "Invoke-Expr"
// MS SQL Server running scripts
DeviceProcessEvents
| where
(InitiatingProcessFileName =~ "sqlserver.exe"
and FileName in~ ("cscript.exe", "wscript.exe"))
or
// Also looking 1 layer "up" the process tree since we see
// the custom script executing an EXE
(InitiatingProcessParentFileName =~ "sqlserver.exe"
and InitiatingProcessFileName in~ ("cscript.exe", "wscript.exe"))
// Custom "remote.vbs" script
DeviceProcessEvents
| where ProcessCommandLine contains "/s:"
| where ProcessCommandLine contains "/u:"
| where ProcessCommandLine contains "/p:"
| where ProcessCommandLine contains "/t:"
//| where FileName in~ ("cscript.exe", "wscript.exe")
// Network Connections to internal systems caused by a script
DeviceNetworkEvents
| where InitiatingProcessFileName in~ ("cscript.exe", "wscript.exe")
| where RemoteIPType == "Private"

Reference: https://www.dragos.com/wp-content/uploads/CrashOverride-01.pdf

// Exe launched with arguments that may match the wiper-loader
DeviceProcessEvents
| where FileName endswith ".exe"
| where ProcessCommandLine has_all (".dll", ".ini")

Initial Access — Spearphishing Attachment — T1566.001

Reference: https://www.youtube.com/watch?v=xoNSbm1aX_w

// Word Doc Launching PowerShell Dropper for Empire
// Not accounting for processes being renamed since initial access payloads
// typically rely on default names for the target binary, by default
DeviceProcessEvents
| where InitiatingProcessFileName =~ "winword.exe"
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe")

--

--