Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
T1046 on the official MITRE ATT&CK siteT1047 on the official MITRE ATT&CK siteT1057 on the official MITRE ATT&CK siteT1059.005 on the official MITRE ATT&CK siteT1059.007 on the official MITRE ATT&CK siteT1082 on the official MITRE ATT&CK siteT1083 on the official MITRE ATT&CK siteT1546.003 on the official MITRE ATT&CK siteT1547 on the official MITRE ATT&CK site
NIST CSF 2.0
MITRE D3FEND
When to Use
- When proactively searching for fileless persistence mechanisms in Windows environments
- After threat intelligence reports indicate WMI-based persistence by APT groups (APT29, APT32, FIN8)
- When investigating systems where malware persists across reboots despite cleanup attempts
- During incident response when standard persistence locations (Run keys, scheduled tasks) are clean
- When WmiPrvSe.exe is observed spawning unexpected child processes
Prerequisites
- Sysmon Event ID 19, 20, 21 (WMI Event Filter/Consumer/Binding) enabled
- Windows Event ID 5861 (WMI activity logging) from Microsoft-Windows-WMI-Activity
- PowerShell logging enabled (Script Block Logging, Module Logging)
- WMI repository access for enumeration
- SIEM platform for event correlation
Workflow
- Enumerate Existing WMI Subscriptions: Query all permanent WMI event subscriptions on target systems. A clean system typically has very few or zero permanent subscriptions, making anomalies easy to spot.
- Monitor WMI Event Creation (Sysmon 19/20/21): Sysmon Event 19 captures WmiEventFilter activity, Event 20 captures WmiEventConsumer activity, and Event 21 captures WmiEventConsumerToFilter binding.
- Analyze Consumer Types: Focus on ActiveScriptEventConsumer (runs VBScript/JScript) and CommandLineEventConsumer (executes commands) -- these are the dangerous types used for persistence.
- Check Event Filter Triggers: Examine what triggers the subscription. Common malicious triggers include system startup (Win32_ProcessStartTrace), user logon, or timer-based execution intervals.
- Investigate WmiPrvSe.exe Child Processes: When a WMI subscription fires, the action is executed by WmiPrvSe.exe. Hunt for unusual child processes of WmiPrvSe.exe.
- Correlate with MOF Compilation: Detect
mofcomp.exeusage which compiles MOF files to create WMI subscriptions programmatically. - Validate and Respond: Confirm malicious subscriptions, remove them, and trace back to the initial infection vector.
Key Concepts
| Concept | Description |
|---|---|
| T1546.003 | Event Triggered Execution: WMI Event Subscription |
| __EventFilter | WMI class defining the trigger condition |
| __EventConsumer | WMI class defining the action to perform |
| __FilterToConsumerBinding | Links a filter to a consumer |
| ActiveScriptEventConsumer | Consumer that runs VBScript or JScript |
| CommandLineEventConsumer | Consumer that executes command lines |
| WmiPrvSe.exe | WMI Provider Host that executes subscription actions |
| MOF File | Managed Object Format used to define WMI objects |
Detection Queries
Splunk -- WMI Subscription Creation via Sysmon
index=sysmon (EventCode=19 OR EventCode=20 OR EventCode=21)
| eval event_type=case(EventCode=19, "EventFilter", EventCode=20, "EventConsumer", EventCode=21, "FilterToConsumerBinding")
| table _time Computer User event_type EventNamespace Name Query Destination OperationSplunk -- WMI Subscription via Windows Event 5861
index=wineventlog source="Microsoft-Windows-WMI-Activity/Operational" EventCode=5861
| table _time Computer NamespaceName Operation PossibleCausePowerShell -- Enumerate WMI Subscriptions
Get-WmiObject -Namespace root\subscription -Class __EventFilter
Get-WmiObject -Namespace root\subscription -Class __EventConsumer
Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBindingKQL -- WmiPrvSe.exe Spawning Suspicious Children
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName =~ "wmiprvse.exe"
| where FileName in~ ("cmd.exe", "powershell.exe", "wscript.exe", "cscript.exe", "mshta.exe", "rundll32.exe")
| project Timestamp, DeviceName, FileName, ProcessCommandLineSigma Rule
title: WMI Event Subscription Persistence
status: stable
logsource:
product: windows
category: wmi_event
detection:
selection_consumer:
EventID: 20
Destination|contains:
- 'ActiveScriptEventConsumer'
- 'CommandLineEventConsumer'
condition: selection_consumer
level: high
tags:
- attack.persistence
- attack.t1546.003Common Scenarios
- APT29 WMI Persistence: Creates an ActiveScriptEventConsumer that executes a VBScript backdoor on system startup, surviving reboots and credential resets.
- Turla WMI Backdoor: Uses Win32_ProcessStartTrace filter combined with CommandLineEventConsumer for covert command execution.
- FIN8 WMI Timer: Interval-based __IntervalTimerEvent triggering encoded PowerShell downloads every 30 minutes.
- MOF-Based Installation: Adversary drops a .mof file and compiles it with
mofcomp.exeto silently create persistent subscriptions.
Output Format
Hunt ID: TH-WMI-[DATE]-[SEQ]
Host: [Hostname]
Subscription Name: [Filter/Consumer name]
Filter Query: [WQL trigger condition]
Consumer Type: [ActiveScript/CommandLine]
Consumer Action: [Script content or command]
Binding: [Filter-to-Consumer link]
Created: [Timestamp]
User Context: [SYSTEM/User]
Risk Level: [Critical/High/Medium/Low]Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.9 KB
API Reference — Hunting for Persistence via WMI Subscriptions
Libraries Used
- subprocess: Execute WMIC and PowerShell commands for WMI enumeration
- python-evtx (Evtx): Parse Sysmon EVTX for WMI-related events (IDs 19, 20, 21)
- re: Pattern matching for suspicious WMI consumer payloads
CLI Interface
python agent.py enumerate # WMIC-based WMI subscription enumeration
python agent.py powershell # PowerShell Get-WMIObject enumeration
python agent.py sysmon --evtx-file <path> # Scan Sysmon EVTX for WMI eventsCore Functions
enumerate_wmi_subscriptions()
Queries four WMI subscription classes via WMIC and flags entries matching suspicious patterns.
Returns: dict with classes (EventFilter, EventConsumer, ActiveScriptEventConsumer, FilterToConsumerBinding) and suspicious list.
scan_sysmon_wmi_events(evtx_file)
Parses Sysmon EVTX for Event IDs 19 (WmiEventFilter), 20 (WmiEventConsumer), 21 (WmiEventBinding).
Parameters:
| Name | Type | Description |
|---|---|---|
evtx_file |
str | Path to Sysmon .evtx file |
query_powershell_wmi()
Uses PowerShell Get-WMIObject to enumerate WMI subscriptions in root\Subscription namespace.
WMI Classes Enumerated
| Class | Description |
|---|---|
__EventFilter |
Defines the WQL query that triggers the subscription |
CommandLineEventConsumer |
Executes a command when the filter matches |
ActiveScriptEventConsumer |
Runs VBScript/JScript when the filter matches |
__FilterToConsumerBinding |
Links a filter to its consumer |
Sysmon Event IDs
| Event ID | Description |
|---|---|
| 19 | WmiEvent - Filter activity detected |
| 20 | WmiEvent - Consumer activity detected |
| 21 | WmiEvent - Consumer-to-filter binding |
Dependencies
pip install python-evtx # Optional, for EVTX parsingstandards.md2.6 KB
Standards and References - WMI Event Subscription Persistence
MITRE ATT&CK References
| Technique | Name | Description |
|---|---|---|
| T1546.003 | WMI Event Subscription | Primary persistence technique |
| T1047 | WMI | WMI execution for lateral movement |
| T1059.005 | Visual Basic | VBScript in ActiveScriptEventConsumer |
| T1059.007 | JavaScript | JScript in ActiveScriptEventConsumer |
WMI Subscription Components
| Component | WMI Class | Purpose |
|---|---|---|
| Event Filter | __EventFilter | Defines the trigger (WQL query) |
| Event Consumer | __EventConsumer | Defines the action |
| Binding | __FilterToConsumerBinding | Links filter to consumer |
Consumer Types and Risk
| Consumer Class | Risk Level | Description |
|---|---|---|
| ActiveScriptEventConsumer | Critical | Executes VBScript/JScript code |
| CommandLineEventConsumer | Critical | Executes arbitrary commands |
| LogFileEventConsumer | Low | Writes to a log file |
| NTEventLogEventConsumer | Low | Writes to Windows Event Log |
| SMTPEventConsumer | Medium | Sends email notifications |
Common Malicious Filter Queries
| Filter Type | WQL Query | Usage |
|---|---|---|
| Process Start | SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process' | Execute on specific process start |
| System Startup | SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' | Execute shortly after boot |
| Timer-Based | SELECT * FROM __TimerEvent WHERE TimerID='MyTimer' | Execute at intervals |
| User Logon | SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_LogonSession' | Execute on user logon |
Detection Events
| Source | Event ID | Description |
|---|---|---|
| Sysmon | 19 | WmiEventFilter activity detected |
| Sysmon | 20 | WmiEventConsumer activity detected |
| Sysmon | 21 | WmiEventConsumerToFilter activity detected |
| WMI-Activity | 5861 | WMI permanent event subscription created |
| Security | 4688 | Process creation (mofcomp.exe, WmiPrvSe.exe children) |
Known APT Usage
| Group | Technique Details |
|---|---|
| APT29 | ActiveScriptEventConsumer with encoded VBScript backdoor |
| APT32 (OceanLotus) | WMI subscription for persistence in targeted attacks |
| FIN8 | CommandLineEventConsumer for PowerShell execution |
| Turla | WMI event subscription combined with COM hijacking |
| HEXANE | WMI persistence in Middle Eastern energy sector attacks |
workflows.md3.1 KB
Detailed Hunting Workflow - WMI Subscription Persistence
Phase 1: Enumerate Existing Subscriptions
Step 1.1 - PowerShell Enumeration
# List all event filters
Get-WMIObject -Namespace root\Subscription -Class __EventFilter | Select-Object Name, Query, QueryLanguage
# List all event consumers
Get-WMIObject -Namespace root\Subscription -Class __EventConsumer | Select-Object Name, __CLASS
# List all bindings
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding | Select-Object Filter, Consumer
# Detailed ActiveScriptEventConsumer inspection
Get-WMIObject -Namespace root\Subscription -Class ActiveScriptEventConsumer | Select-Object Name, ScriptingEngine, ScriptText
# Detailed CommandLineEventConsumer inspection
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer | Select-Object Name, ExecutablePath, CommandLineTemplateStep 1.2 - WMIC Enumeration
wmic /namespace:\\root\subscription path __EventFilter get Name, Query
wmic /namespace:\\root\subscription path __EventConsumer get Name, __CLASS
wmic /namespace:\\root\subscription path __FilterToConsumerBinding get Filter, ConsumerPhase 2: Monitor Creation Events
Step 2.1 - Sysmon WMI Event Detection
index=sysmon (EventCode=19 OR EventCode=20 OR EventCode=21)
| eval event_type=case(
EventCode=19, "EventFilter Created",
EventCode=20, "EventConsumer Created",
EventCode=21, "Binding Created"
)
| table _time Computer User event_type Name Query Consumer DestinationStep 2.2 - Windows WMI Activity Log
index=wineventlog source="Microsoft-Windows-WMI-Activity/Operational"
| where EventCode IN (5857, 5858, 5859, 5860, 5861)
| table _time Computer EventCode NamespaceName Query Operation PossibleCausePhase 3: Hunt for WmiPrvSe.exe Suspicious Children
Step 3.1 - Process Tree Analysis
index=sysmon EventCode=1
| where match(ParentImage, "(?i)WmiPrvSe\.exe$")
| where match(Image, "(?i)(cmd|powershell|wscript|cscript|mshta|rundll32|regsvr32)\.exe$")
| table _time Computer Image CommandLine User ParentImageStep 3.2 - MOF Compilation Detection
index=sysmon EventCode=1 Image="*\\mofcomp.exe"
| table _time Computer User CommandLine ParentImagePhase 4: Removal and Cleanup
Step 4.1 - Remove Malicious Subscription
# Remove specific subscription components
Get-WMIObject -Namespace root\Subscription -Class __EventFilter -Filter "Name='MaliciousFilter'" | Remove-WmiObject
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer -Filter "Name='MaliciousConsumer'" | Remove-WmiObject
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding -Filter "Filter=""__EventFilter.Name='MaliciousFilter'""" | Remove-WmiObjectPhase 5: Response
- Document all found subscriptions with full details
- Remove malicious subscriptions from all affected hosts
- Block WMI subscription creation via Group Policy where possible
- Deploy ongoing monitoring via Sysmon Events 19/20/21
- Investigate initial infection vector that created the subscription
Scripts 2
agent.py6.3 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for hunting WMI event subscription persistence (T1546.003)."""
import json
import argparse
import subprocess
import re
from datetime import datetime
WMI_CLASSES = {
"EventFilter": {
"wmic_cmd": ["wmic", "/namespace:\\\\root\\subscription", "path", "__EventFilter", "get", "/format:list"],
"description": "WMI event filters that trigger on system events",
},
"EventConsumer": {
"wmic_cmd": ["wmic", "/namespace:\\\\root\\subscription", "path", "CommandLineEventConsumer", "get", "/format:list"],
"description": "Command-line consumers that execute when filters trigger",
},
"ActiveScriptEventConsumer": {
"wmic_cmd": ["wmic", "/namespace:\\\\root\\subscription", "path", "ActiveScriptEventConsumer", "get", "/format:list"],
"description": "Script-based consumers (VBScript/JScript) for WMI persistence",
},
"FilterToConsumerBinding": {
"wmic_cmd": ["wmic", "/namespace:\\\\root\\subscription", "path", "__FilterToConsumerBinding", "get", "/format:list"],
"description": "Bindings linking event filters to consumers",
},
}
SUSPICIOUS_WMI_PATTERNS = [
r"powershell", r"cmd\.exe", r"mshta", r"rundll32",
r"certutil", r"bitsadmin", r"regsvr32",
r"base64", r"IEX", r"DownloadString", r"Net\.WebClient",
r"invoke-expression", r"new-object.*net\.webclient",
r"\\temp\\", r"\\appdata\\", r"\\users\\public\\",
r"wscript", r"cscript", r"javascript:", r"vbscript:",
]
def enumerate_wmi_subscriptions():
"""Enumerate all WMI event subscriptions on the local system."""
results = {"timestamp": datetime.utcnow().isoformat(), "classes": {}, "suspicious": []}
for class_name, info in WMI_CLASSES.items():
try:
proc = subprocess.run(info["wmic_cmd"], capture_output=True, text=True, timeout=15)
entries = parse_wmic_list(proc.stdout)
suspicious_entries = []
for entry in entries:
entry_text = json.dumps(entry).lower()
matched = [p for p in SUSPICIOUS_WMI_PATTERNS if re.search(p, entry_text, re.I)]
if matched:
entry["matched_patterns"] = matched
suspicious_entries.append(entry)
results["classes"][class_name] = {
"description": info["description"],
"total_entries": len(entries),
"entries": entries,
}
results["suspicious"].extend([{**e, "class": class_name} for e in suspicious_entries])
except (subprocess.TimeoutExpired, FileNotFoundError):
results["classes"][class_name] = {"error": "command failed"}
results["total_suspicious"] = len(results["suspicious"])
return results
def parse_wmic_list(output):
"""Parse WMIC /format:list output into list of dicts."""
entries = []
current = {}
for line in output.strip().split("\n"):
line = line.strip()
if not line:
if current:
entries.append(current)
current = {}
continue
if "=" in line:
key, _, value = line.partition("=")
current[key.strip()] = value.strip()
if current:
entries.append(current)
return entries
def scan_sysmon_wmi_events(evtx_file):
"""Parse Sysmon EVTX for WMI events (Event IDs 19, 20, 21)."""
try:
import Evtx.Evtx as evtx_lib
except ImportError:
return {"error": "python-evtx not installed"}
findings = []
wmi_event_ids = {"19", "20", "21"}
with evtx_lib.Evtx(evtx_file) as log:
for record in log.records():
xml = record.xml()
for eid in wmi_event_ids:
if f"<EventID>{eid}</EventID>" in xml:
suspicious = any(re.search(p, xml, re.I) for p in SUSPICIOUS_WMI_PATTERNS)
findings.append({
"record_id": record.record_num(),
"event_id": int(eid),
"event_type": {
"19": "WmiEventFilter", "20": "WmiEventConsumer", "21": "WmiEventBinding"
}[eid],
"suspicious": suspicious,
"xml_snippet": xml[:800],
})
break
return {
"file": evtx_file,
"total_wmi_events": len(findings),
"suspicious_events": sum(1 for f in findings if f["suspicious"]),
"findings": findings[:300],
}
def query_powershell_wmi():
"""Use PowerShell Get-WMIObject to enumerate WMI subscriptions."""
ps_script = """
$filters = Get-WMIObject -Namespace root\\Subscription -Class __EventFilter | Select Name,Query
$consumers = Get-WMIObject -Namespace root\\Subscription -Class CommandLineEventConsumer | Select Name,CommandLineTemplate
$bindings = Get-WMIObject -Namespace root\\Subscription -Class __FilterToConsumerBinding | Select Filter,Consumer
@{Filters=$filters;Consumers=$consumers;Bindings=$bindings} | ConvertTo-Json -Depth 5
"""
try:
result = subprocess.run(
["powershell", "-NoProfile", "-Command", ps_script],
capture_output=True, text=True, timeout=30
)
if result.returncode == 0 and result.stdout.strip():
return json.loads(result.stdout)
return {"error": result.stderr[:500]}
except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError) as e:
return {"error": str(e)}
def main():
parser = argparse.ArgumentParser(description="Hunt for WMI event subscription persistence")
sub = parser.add_subparsers(dest="command")
sub.add_parser("enumerate", help="Enumerate WMI subscriptions via WMIC")
sub.add_parser("powershell", help="Enumerate via PowerShell Get-WMIObject")
s = sub.add_parser("sysmon", help="Scan Sysmon EVTX for WMI events (19/20/21)")
s.add_argument("--evtx-file", required=True)
args = parser.parse_args()
if args.command == "enumerate":
result = enumerate_wmi_subscriptions()
elif args.command == "powershell":
result = query_powershell_wmi()
elif args.command == "sysmon":
result = scan_sysmon_wmi_events(args.evtx_file)
else:
parser.print_help()
return
print(json.dumps(result, indent=2, default=str))
if __name__ == "__main__":
main()
process.py6.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
WMI Subscription Persistence Detection Script
Analyzes Sysmon Events 19/20/21 and process creation logs to detect
malicious WMI permanent event subscriptions used for persistence.
"""
import json
import csv
import argparse
import datetime
import re
from pathlib import Path
DANGEROUS_CONSUMER_TYPES = {"ActiveScriptEventConsumer", "CommandLineEventConsumer"}
SUSPICIOUS_FILTER_PATTERNS = [
(r"__InstanceCreationEvent.*Win32_Process", "process_start_trigger"),
(r"__InstanceModificationEvent.*Win32_PerfFormattedData", "system_startup_trigger"),
(r"__TimerEvent", "timer_based_trigger"),
(r"__InstanceCreationEvent.*Win32_LogonSession", "user_logon_trigger"),
(r"Win32_ProcessStartTrace", "process_trace_trigger"),
]
SUSPICIOUS_CONSUMER_PATTERNS = [
(r"(?i)powershell", "powershell_execution"),
(r"(?i)(cmd\.exe|cmd\s/c)", "command_execution"),
(r"(?i)(http|https)://", "network_callback"),
(r"(?i)(wscript|cscript)", "script_execution"),
(r"(?i)(base64|encodedcommand|-enc\s)", "encoded_content"),
(r"(?i)(invoke-expression|iex|downloadstring)", "download_cradle"),
]
def parse_events(input_path: str) -> list[dict]:
"""Parse Sysmon WMI event logs."""
path = Path(input_path)
events = []
if path.suffix == ".json":
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
events = data if isinstance(data, list) else data.get("events", [])
elif path.suffix == ".csv":
with open(path, "r", encoding="utf-8-sig") as f:
events = [dict(row) for row in csv.DictReader(f)]
return events
def detect_wmi_persistence(events: list[dict]) -> list[dict]:
"""Detect malicious WMI event subscriptions."""
findings = []
filters = {}
consumers = {}
for event in events:
event_code = str(event.get("EventCode", event.get("EventID", "")))
computer = event.get("Computer", event.get("host", ""))
timestamp = event.get("UtcTime", event.get("_time", ""))
user = event.get("User", event.get("user", ""))
if event_code == "19": # EventFilter
name = event.get("Name", event.get("name", ""))
query = event.get("Query", event.get("query", ""))
filters[name] = {"query": query, "computer": computer, "timestamp": timestamp}
for pattern, trigger_type in SUSPICIOUS_FILTER_PATTERNS:
if re.search(pattern, query, re.IGNORECASE):
findings.append({
"timestamp": timestamp,
"computer": computer,
"user": user,
"event_type": "EventFilter",
"name": name,
"query": query,
"trigger_type": trigger_type,
"severity": "HIGH",
"technique": "T1546.003",
})
break
elif event_code == "20": # EventConsumer
name = event.get("Name", event.get("name", ""))
consumer_type = event.get("Type", event.get("Destination", ""))
destination = event.get("Destination", event.get("destination", ""))
consumers[name] = {"type": consumer_type, "destination": destination}
severity = "CRITICAL" if any(dt in str(consumer_type) for dt in DANGEROUS_CONSUMER_TYPES) else "MEDIUM"
indicators = []
for pattern, indicator in SUSPICIOUS_CONSUMER_PATTERNS:
if re.search(pattern, str(destination)):
indicators.append(indicator)
severity = "CRITICAL"
findings.append({
"timestamp": timestamp,
"computer": computer,
"user": user,
"event_type": "EventConsumer",
"name": name,
"consumer_type": str(consumer_type),
"destination": destination,
"indicators": indicators,
"severity": severity,
"technique": "T1546.003",
})
elif event_code == "21": # Binding
consumer = event.get("Consumer", event.get("consumer", ""))
filter_ref = event.get("Filter", event.get("filter", ""))
findings.append({
"timestamp": timestamp,
"computer": computer,
"user": user,
"event_type": "FilterToConsumerBinding",
"consumer": consumer,
"filter": filter_ref,
"severity": "HIGH",
"technique": "T1546.003",
})
elif event_code == "1": # Process creation
parent = event.get("ParentImage", "")
image = event.get("Image", "")
cmdline = event.get("CommandLine", "")
if "wmiprvse.exe" in parent.lower():
image_name = image.split("\\")[-1].lower()
if image_name in {"cmd.exe", "powershell.exe", "wscript.exe", "cscript.exe", "mshta.exe"}:
findings.append({
"timestamp": timestamp,
"computer": computer,
"user": user,
"event_type": "WmiPrvSe_Child_Process",
"child_process": image,
"command_line": cmdline,
"severity": "HIGH",
"technique": "T1546.003",
})
return sorted(findings, key=lambda x: {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2}.get(x["severity"], 3))
def run_hunt(input_path: str, output_dir: str) -> None:
"""Execute WMI subscription persistence hunt."""
print(f"[*] WMI Subscription Persistence Hunt - {datetime.datetime.now().isoformat()}")
events = parse_events(input_path)
print(f"[*] Loaded {len(events)} events")
findings = detect_wmi_persistence(events)
print(f"[!] WMI persistence detections: {len(findings)}")
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
with open(output_path / "wmi_persistence_findings.json", "w", encoding="utf-8") as f:
json.dump({
"hunt_id": f"TH-WMI-{datetime.date.today().isoformat()}",
"total_events": len(events),
"findings_count": len(findings),
"findings": findings,
}, f, indent=2)
print(f"[+] Results written to {output_dir}")
def main():
parser = argparse.ArgumentParser(description="WMI Subscription Persistence Detection")
parser.add_argument("--input", "-i", required=True)
parser.add_argument("--output", "-o", default="./wmi_hunt_output")
args = parser.parse_args()
run_hunt(args.input, args.output)
if __name__ == "__main__":
main()
Assets 1
template.mdtext/markdown · 1.0 KBKeep exploring