Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
NIST CSF 2.0
When to Use
- When proactively hunting for indicators of hunting for shadow copy deletion in the environment
- After threat intelligence indicates active campaigns using these techniques
- During incident response to scope compromise related to these techniques
- When EDR or SIEM alerts trigger on related indicators
- During periodic security assessments and purple team exercises
Prerequisites
- EDR platform with process and network telemetry (CrowdStrike, MDE, SentinelOne)
- SIEM with relevant log data ingested (Splunk, Elastic, Sentinel)
- Sysmon deployed with comprehensive configuration
- Windows Security Event Log forwarding enabled
- Threat intelligence feeds for IOC correlation
Workflow
- Formulate Hypothesis: Define a testable hypothesis based on threat intelligence or ATT&CK gap analysis.
- Identify Data Sources: Determine which logs and telemetry are needed to validate or refute the hypothesis.
- Execute Queries: Run detection queries against SIEM and EDR platforms to collect relevant events.
- Analyze Results: Examine query results for anomalies, correlating across multiple data sources.
- Validate Findings: Distinguish true positives from false positives through contextual analysis.
- Correlate Activity: Link findings to broader attack chains and threat actor TTPs.
- Document and Report: Record findings, update detection rules, and recommend response actions.
Key Concepts
| Concept | Description |
|---|---|
| T1490 | Inhibit System Recovery |
| T1486 | Data Encrypted for Impact |
| T1485 | Data Destruction |
Tools & Systems
| Tool | Purpose |
|---|---|
| CrowdStrike Falcon | EDR telemetry and threat detection |
| Microsoft Defender for Endpoint | Advanced hunting with KQL |
| Splunk Enterprise | SIEM log analysis with SPL queries |
| Elastic Security | Detection rules and investigation timeline |
| Sysmon | Detailed Windows event monitoring |
| Velociraptor | Endpoint artifact collection and hunting |
| Sigma Rules | Cross-platform detection rule format |
Common Scenarios
- Scenario 1: Ransomware deleting shadow copies before encryption
- Scenario 2: vssadmin delete shadows /all /quiet pre-encryption
- Scenario 3: WMIC shadowcopy delete via PowerShell
- Scenario 4: bcdedit disabling recovery mode before impact
Output Format
Hunt ID: TH-HUNTIN-[DATE]-[SEQ]
Technique: T1490
Host: [Hostname]
User: [Account context]
Evidence: [Log entries, process trees, network data]
Risk Level: [Critical/High/Medium/Low]
Confidence: [High/Medium/Low]
Recommended Action: [Containment, investigation, monitoring]Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.6 KB
API Reference: Hunting for Shadow Copy Deletion
python-evtx
import Evtx.Evtx as evtx
with evtx.Evtx("Security.evtx") as log:
for record in log.records():
xml_str = record.xml() # full XML of event
ts = record.timestamp() # datetime objectDetection Patterns
| Pattern | Technique | Severity |
|---|---|---|
vssadmin delete shadows |
T1490 | CRITICAL |
wmic shadowcopy delete |
T1490 | CRITICAL |
bcdedit /set recoveryenabled no |
T1490 | HIGH |
wbadmin delete catalog |
T1490 | HIGH |
Win32_ShadowCopy.Delete() |
T1490 | CRITICAL |
Splunk SPL
index=wineventlog (EventCode=4688 OR EventCode=1)
| where match(CommandLine, "(?i)(vssadmin.*delete.*shadows|wmic.*shadowcopy.*delete)")
| table _time Computer User CommandLine ParentImageKQL (Microsoft Sentinel)
DeviceProcessEvents
| where ProcessCommandLine has_any ("vssadmin delete shadows", "wmic shadowcopy delete",
"bcdedit /set", "wbadmin delete catalog")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileNameSigma Rule Format
title: Shadow Copy Deletion
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith: '\vssadmin.exe'
CommandLine|contains|all:
- 'delete'
- 'shadows'
condition: selection
level: critical
tags:
- attack.impact
- attack.t1490References
- MITRE T1490: https://attack.mitre.org/techniques/T1490/
- python-evtx: https://github.com/williballenthin/python-evtx
- Sigma Rules: https://github.com/SigmaHQ/sigma
standards.md1.5 KB
Standards and References - Hunting For Shadow Copy Deletion
MITRE ATT&CK Mappings
| Technique | Name | Description |
|---|---|---|
| T1490 | Inhibit System Recovery | See attack.mitre.org/techniques/T1490 |
| T1486 | Data Encrypted for Impact | See attack.mitre.org/techniques/T1486 |
| T1485 | Data Destruction | See attack.mitre.org/techniques/T1485 |
Detection Data Sources
| Source | Event ID | Purpose |
|---|---|---|
| Sysmon | 1 | Process creation with command line |
| Sysmon | 3 | Network connection initiated |
| Sysmon | 7 | Image loaded (DLL) |
| Sysmon | 10 | Process access (LSASS) |
| Sysmon | 11 | File creation |
| Sysmon | 12/13 | Registry create/set |
| Sysmon | 22 | DNS query |
| Sysmon | 25 | Process tampering |
| Windows Security | 4624 | Successful logon |
| Windows Security | 4625 | Failed logon |
| Windows Security | 4648 | Explicit credential logon |
| Windows Security | 4672 | Special privileges assigned |
| Windows Security | 4688 | Process creation |
| Windows Security | 4697 | Service installed |
| Windows Security | 4698 | Scheduled task created |
| Windows Security | 4769 | Kerberos TGS requested |
| Windows Security | 5140 | Network share accessed |
References
- MITRE ATT&CK Framework: https://attack.mitre.org/
- Sigma Detection Rules: https://github.com/SigmaHQ/sigma
- LOLBAS Project: https://lolbas-project.github.io/
- Atomic Red Team Tests: https://github.com/redcanaryco/atomic-red-team
- Red Canary Threat Detection Report
- SANS Threat Hunting Summit Resources
workflows.md2.8 KB
Detailed Hunting Workflow - Hunting For Shadow Copy Deletion
Phase 1: Data Collection and Querying
Splunk SPL Query
index=sysmon EventCode=1
| where match(CommandLine, "(?i)(vssadmin.*delete|wmic.*shadowcopy.*delete|bcdedit.*recoveryenabled.*no|wbadmin.*delete)")
| table _time Computer User Image CommandLine ParentImageKQL Query (Microsoft Defender for Endpoint)
DeviceProcessEvents
| where ProcessCommandLine has_any ("vssadmin delete","shadowcopy delete","bcdedit","recoveryenabled no","wbadmin delete")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLinePhase 2: Baseline and Anomaly Detection
Step 2.1 - Establish Normal Behavior Baseline
- Collect 30 days of historical data for the targeted technique
- Document expected patterns, frequencies, and legitimate use cases
- Identify known false positive sources and document exceptions
- Build statistical baseline (mean, standard deviation) for key metrics
Step 2.2 - Identify Anomalies
- Compare current activity against the 30-day baseline
- Flag events exceeding 3 standard deviations from normal
- Prioritize anomalies by risk score and potential business impact
- Cross-reference with threat intelligence for known IOCs
Phase 3: Investigation and Correlation
Step 3.1 - Deep Dive Analysis
- For each anomaly, collect full process tree context
- Correlate with network activity, file operations, and authentication events
- Check binary signatures, file hashes, and certificate validity
- Review user account context and access patterns
Step 3.2 - Attack Chain Reconstruction
- Map findings to MITRE ATT&CK kill chain stages
- Identify initial access vector if applicable
- Trace lateral movement and privilege escalation paths
- Determine data access and potential exfiltration
Phase 4: Validation and Response
Step 4.1 - True/False Positive Determination
- Verify findings with system owners and IT operations
- Check change management records for authorized activities
- Validate user context (authorized actions vs. compromised account)
- Document determination rationale for each finding
Step 4.2 - Response Actions
- For confirmed threats: initiate incident response procedures
- For detection gaps: create or update detection rules
- For false positives: tune existing rules and update exclusions
- Update threat hunting playbook with lessons learned
Phase 5: Documentation and Reporting
Step 5.1 - Hunt Report
- Summarize hypothesis, methodology, and findings
- Include all queries executed and their results
- Document IOCs discovered and detection rules created
- Provide recommendations for security improvements
Step 5.2 - Knowledge Base Update
- Add findings to threat intelligence platform
- Update MITRE ATT&CK coverage heatmap
- Share detection rules via Sigma format
- Schedule follow-up hunts for related techniques
Scripts 2
agent.py6.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for hunting shadow copy deletion activity indicating ransomware or anti-forensics."""
import json
import argparse
import re
import xml.etree.ElementTree as ET
from datetime import datetime
from pathlib import Path
try:
import Evtx.Evtx as evtx
except ImportError:
evtx = None
SHADOW_PATTERNS = [
r"vssadmin\s+delete\s+shadows",
r"vssadmin\.exe.*delete.*shadows",
r"wmic\s+shadowcopy\s+delete",
r"Get-WmiObject\s+Win32_ShadowCopy.*Delete",
r"gwmi\s+Win32_ShadowCopy.*Remove",
r"bcdedit.*recoveryenabled.*no",
r"bcdedit.*/set.*bootstatuspolicy\s+ignoreallfailures",
r"wbadmin\s+delete\s+catalog",
r"Win32_ShadowCopy.*\.Delete",
r"powershell.*shadowcopy.*delete",
]
RECOVERY_DISABLE_PATTERNS = [
r"bcdedit\s+/set\s+\{default\}\s+recoveryenabled\s+no",
r"reagentc\s+/disable",
r"vssadmin\s+resize\s+shadowstorage.*maxsize=",
]
def parse_evtx_file(evtx_path):
"""Parse Windows EVTX file for shadow copy deletion events."""
if evtx is None:
return []
events = []
with evtx.Evtx(evtx_path) as log:
for record in log.records():
xml_str = record.xml()
try:
root = ET.fromstring(xml_str)
ns = {"ns": "http://schemas.microsoft.com/win/2004/08/events/event"}
event_id_el = root.find(".//ns:EventID", ns)
if event_id_el is None:
continue
event_id = int(event_id_el.text)
if event_id in (1, 4688, 4698):
data_elements = root.findall(".//ns:Data", ns)
event_data = {}
for d in data_elements:
name = d.get("Name", "")
event_data[name] = d.text or ""
events.append({
"event_id": event_id,
"timestamp": record.timestamp().isoformat(),
"data": event_data,
})
except ET.ParseError:
continue
return events
def scan_command_line(cmd_line):
"""Check a command line string against shadow copy deletion patterns."""
findings = []
for pattern in SHADOW_PATTERNS:
if re.search(pattern, cmd_line, re.IGNORECASE):
findings.append({"pattern": pattern, "severity": "CRITICAL", "category": "shadow_copy_deletion"})
for pattern in RECOVERY_DISABLE_PATTERNS:
if re.search(pattern, cmd_line, re.IGNORECASE):
findings.append({"pattern": pattern, "severity": "HIGH", "category": "recovery_disable"})
return findings
def hunt_evtx(evtx_path):
"""Hunt for shadow copy deletion in EVTX logs."""
events = parse_evtx_file(evtx_path)
results = []
for event in events:
cmd = event["data"].get("CommandLine", "") or event["data"].get("TaskContent", "")
if not cmd:
cmd = " ".join(event["data"].values())
matches = scan_command_line(cmd)
if matches:
results.append({
"timestamp": event["timestamp"],
"event_id": event["event_id"],
"command_line": cmd[:500],
"user": event["data"].get("SubjectUserName", event["data"].get("User", "")),
"computer": event["data"].get("Computer", ""),
"findings": matches,
})
return results
def scan_sysmon_json(log_path):
"""Scan JSON-exported Sysmon logs for shadow copy deletion."""
results = []
with open(log_path) as f:
for line in f:
try:
entry = json.loads(line)
except json.JSONDecodeError:
continue
cmd = entry.get("CommandLine", entry.get("command_line", ""))
image = entry.get("Image", entry.get("process_name", ""))
matches = scan_command_line(cmd)
if matches:
results.append({
"timestamp": entry.get("UtcTime", entry.get("timestamp", "")),
"image": image,
"command_line": cmd[:500],
"parent_image": entry.get("ParentImage", ""),
"user": entry.get("User", ""),
"hostname": entry.get("Computer", entry.get("hostname", "")),
"findings": matches,
})
return results
def generate_sigma_rule():
"""Generate a Sigma detection rule for shadow copy deletion."""
return {
"title": "Shadow Copy Deletion via Vssadmin or WMIC",
"id": "faa6e1e2-5b4c-4e1a-bb2a-5c1f3e5e3f0a",
"status": "production",
"level": "critical",
"logsource": {"category": "process_creation", "product": "windows"},
"detection": {
"selection_vssadmin": {
"Image|endswith": "\\vssadmin.exe",
"CommandLine|contains|all": ["delete", "shadows"],
},
"selection_wmic": {
"Image|endswith": "\\wmic.exe",
"CommandLine|contains|all": ["shadowcopy", "delete"],
},
"selection_powershell": {
"Image|endswith": ["\\powershell.exe", "\\pwsh.exe"],
"CommandLine|contains": "Win32_ShadowCopy",
},
"condition": "selection_vssadmin or selection_wmic or selection_powershell",
},
"tags": ["attack.impact", "attack.t1490"],
}
def main():
parser = argparse.ArgumentParser(description="Shadow Copy Deletion Hunter")
parser.add_argument("--evtx", help="Path to EVTX log file")
parser.add_argument("--json-log", help="Path to JSON Sysmon log")
parser.add_argument("--output", default="shadow_copy_hunt_report.json")
parser.add_argument("--action", choices=["hunt_evtx", "hunt_json", "sigma", "full"],
default="full")
args = parser.parse_args()
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
if args.action in ("hunt_evtx", "full") and args.evtx:
results = hunt_evtx(args.evtx)
report["findings"]["evtx_hits"] = results
print(f"[+] EVTX shadow copy deletion events: {len(results)}")
if args.action in ("hunt_json", "full") and args.json_log:
results = scan_sysmon_json(args.json_log)
report["findings"]["sysmon_hits"] = results
print(f"[+] Sysmon JSON shadow copy hits: {len(results)}")
if args.action in ("sigma", "full"):
rule = generate_sigma_rule()
report["findings"]["sigma_rule"] = rule
print("[+] Sigma rule generated")
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
process.py3.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Shadow Copy Deletion Detection - Analyzes logs for T1490 indicators."""
import json, csv, argparse, datetime, re
from collections import defaultdict
from pathlib import Path
DETECTION_PATTERNS = [
r'vssadmin.*delete',
r'wmic.*shadowcopy.*delete',
r'bcdedit.*recoveryenabled.*no',
r'wbadmin.*delete',
r'Get-WmiObject.*Win32_ShadowCopy.*Delete',
]
def parse_logs(path):
p = Path(path)
if p.suffix == ".json":
with open(p, encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, list) else data.get("events", [])
elif p.suffix == ".csv":
with open(p, encoding="utf-8-sig") as f:
return [dict(r) for r in csv.DictReader(f)]
return []
def analyze_event(event):
cmd = event.get("CommandLine", event.get("command_line", event.get("ProcessCommandLine", "")))
content = event.get("Task_Content", event.get("Parameters", event.get("RawEventData", "")))
search_text = f"{cmd} {content}"
risk = 0
indicators = []
for pattern in DETECTION_PATTERNS:
if re.search(pattern, search_text, re.IGNORECASE):
risk += 25
indicators.append(f"Pattern match: {pattern}")
if not indicators:
return None
risk = min(risk, 100)
return {
"technique": "T1490",
"command_line": cmd[:500] if cmd else content[:500],
"hostname": event.get("Computer", event.get("DeviceName", event.get("hostname", "unknown"))),
"user": event.get("User", event.get("AccountName", event.get("UserId", "unknown"))),
"timestamp": event.get("_time", event.get("timestamp", event.get("UtcTime", event.get("Timestamp", "")))),
"risk_score": risk,
"risk_level": "CRITICAL" if risk >= 75 else "HIGH" if risk >= 50 else "MEDIUM" if risk >= 25 else "LOW",
"indicators": indicators,
}
def run_hunt(input_path, output_dir):
print(f"[*] Shadow Copy Deletion Hunt - {datetime.datetime.now().isoformat()}")
events = parse_logs(input_path)
findings = [f for f in (analyze_event(e) for e in events) if f]
Path(output_dir).mkdir(parents=True, exist_ok=True)
slug = "hunting_for_shadow_c"
with open(Path(output_dir) / f"{slug}_findings.json", "w", encoding="utf-8") as f:
json.dump({"hunt_id": f"TH-{datetime.date.today()}", "total_events": len(events), "findings": findings}, f, indent=2)
with open(Path(output_dir) / "hunt_report.md", "w", encoding="utf-8") as f:
f.write(f"# Shadow Copy Deletion Hunt Report\n\n")
f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"**Findings**: {len(findings)}\n\n")
for finding in sorted(findings, key=lambda x: x["risk_score"], reverse=True)[:20]:
f.write(f"### [{finding['risk_level']}] {finding['technique']}\n")
f.write(f"- **Host**: {finding['hostname']}\n")
f.write(f"- **Indicators**: {', '.join(finding['indicators'])}\n\n")
print(f"[+] {len(findings)} findings written to {output_dir}")
def main():
p = argparse.ArgumentParser(description="Shadow Copy Deletion Detection")
sp = p.add_subparsers(dest="cmd")
h = sp.add_parser("hunt"); h.add_argument("--input", "-i", required=True); h.add_argument("--output", "-o", default="./hunting_for_sha_output")
sp.add_parser("queries")
args = p.parse_args()
if args.cmd == "hunt": run_hunt(args.input, args.output)
elif args.cmd == "queries":
print("=== Detection Queries ===")
print("See references/workflows.md for platform-specific queries")
else: p.print_help()
if __name__ == "__main__": main()
Assets 1
template.mdtext/markdown · 2.6 KBKeep exploring