Catching shadow copy deletion before the encryption starts
Almost every ransomware family removes the victim's ability to recover before it encrypts anything. On Windows that means deleting Volume Shadow Copies, wiping the backup catalog and turning off automatic repair. MITRE ATT&CK tracks this as T1490, Inhibit System Recovery.
I first wrote about this in the context of REvil, which ran vssadmin.exe delete shadows /all /quiet as one of its first actions. REvil is gone, but the technique outlived it, and the same handful of commands show up across most families since. That makes it one of the highest-value detections available: it is cheap, it has few legitimate uses, and it fires before the damage is done.
What to look for
| Tool | Command pattern | Effect |
|---|---|---|
vssadmin.exe |
delete shadows |
Deletes shadow copies |
vssadmin.exe |
resize shadowstorage |
Shrinks storage so Windows purges the copies itself |
wmic.exe |
shadowcopy delete |
Deletes shadow copies through WMI |
wbadmin.exe |
delete catalog, delete systemstatebackup |
Removes the Windows Backup catalog or backups |
bcdedit.exe |
recoveryenabled no, bootstatuspolicy ignoreallfailures |
Disables automatic repair at boot |
powershell.exe |
Win32_ShadowCopy with a delete or remove call |
Deletes shadow copies through WMI or CIM |
All of these need process creation logging with command lines: Sysmon event 1, Windows event 4688 with command-line auditing enabled, or EDR telemetry.
Splunk
Written against the CIM Endpoint data model, so it works with any process source that is mapped to it.
| tstats summariesonly=true count min(_time) as first_seen max(_time) as last_seen
from datamodel=Endpoint.Processes
where Processes.process_name IN ("vssadmin.exe", "wmic.exe", "wbadmin.exe", "bcdedit.exe", "powershell.exe", "pwsh.exe")
by Processes.dest, Processes.user, Processes.parent_process_name, Processes.process_name, Processes.process
| `drop_dm_object_name(Processes)`
| eval process_name = lower(process_name)
| where (process_name="vssadmin.exe" AND match(process, "(?i)delete\s+shadows|resize\s+shadowstorage"))
OR (process_name="wmic.exe" AND match(process, "(?i)shadowcopy.+delete"))
OR (process_name="wbadmin.exe" AND match(process, "(?i)delete\s+(catalog|systemstatebackup|backup)"))
OR (process_name="bcdedit.exe" AND match(process, "(?i)recoveryenabled\s+no|bootstatuspolicy\s+ignoreallfailures"))
OR (process_name IN ("powershell.exe", "pwsh.exe") AND match(process, "(?i)win32_shadowcopy") AND match(process, "(?i)delete|remove-"))
| convert ctime(first_seen) ctime(last_seen)
Microsoft Sentinel
Using Defender for Endpoint process events.
DeviceProcessEvents
| where TimeGenerated > ago(1h)
| where (FileName =~ "vssadmin.exe" and ProcessCommandLine matches regex @"(?i)delete\s+shadows|resize\s+shadowstorage")
or (FileName =~ "wmic.exe" and ProcessCommandLine has "shadowcopy" and ProcessCommandLine has "delete")
or (FileName =~ "wbadmin.exe" and ProcessCommandLine has "delete" and ProcessCommandLine has_any ("catalog", "systemstatebackup", "backup"))
or (FileName =~ "bcdedit.exe" and ProcessCommandLine has_any ("recoveryenabled", "bootstatuspolicy"))
or (FileName in~ ("powershell.exe", "pwsh.exe") and ProcessCommandLine has "Win32_ShadowCopy" and ProcessCommandLine has_any ("Delete", "Remove-WmiObject", "Remove-CimInstance"))
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine
Elastic
As an EQL rule over endpoint process events.
process where event.type == "start" and
(
(process.name : "vssadmin.exe" and process.args : ("delete", "resize") and process.args : ("shadows", "shadowstorage")) or
(process.name : "wmic.exe" and process.args : "shadowcopy" and process.args : "delete") or
(process.name : "wbadmin.exe" and process.args : "delete" and process.args : ("catalog", "systemstatebackup", "backup")) or
(process.name : "bcdedit.exe" and process.args : ("recoveryenabled", "bootstatuspolicy"))
)
Tuning
Expect a small number of legitimate hits, and they are usually easy to recognize:
- Backup software manages shadow copies as part of its normal job. Allowlist by parent process and host, not by command line.
- Imaging and deployment tooling calls
bcdeditduring task sequences. The parent process and the timing, during provisioning, give it away. - Administrators freeing disk space on a full volume. This should be rare enough to confirm by asking them.
Avoid excluding by user account alone. Ransomware operators run these commands as a domain admin or as SYSTEM, which are exactly the accounts a broad exclusion would cover.
What this will not catch
Some families delete shadow copies by calling the WMI or VSS COM interfaces directly from the payload. No child process is created, so there is no command line to match. Renamed binaries are a smaller gap: match on the original file name from the PE header where your telemetry has it (process.pe.original_file_name in Elastic, ProcessVersionInfoOriginalFileName in Defender) rather than the name on disk.
That is why this detection belongs alongside the others in the chain, such as failed-then-successful RDP logons from unfamiliar sources and unexpected privilege changes, and not in place of them.
When it fires
Treat a true positive as an incident in progress, not a ticket. Isolate the host, then work backwards from the parent process: how did the command get there, which account ran it, and where else has that account authenticated in the last 24 hours. Encryption typically follows within minutes.