threat hunting

Hunting for Persistence via WMI Subscriptions

Hunt for adversary persistence through Windows Management Instrumentation event subscriptions by monitoring WMI consumer, filter, and binding creation events that execute malicious code triggered by system events.

endpoint-detectionevent-subscriptionmitre-t1546-003threat-huntingwindowswmi-persistence
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

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

  1. 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.
  2. 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.
  3. Analyze Consumer Types: Focus on ActiveScriptEventConsumer (runs VBScript/JScript) and CommandLineEventConsumer (executes commands) -- these are the dangerous types used for persistence.
  4. Check Event Filter Triggers: Examine what triggers the subscription. Common malicious triggers include system startup (Win32_ProcessStartTrace), user logon, or timer-based execution intervals.
  5. 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.
  6. Correlate with MOF Compilation: Detect mofcomp.exe usage which compiles MOF files to create WMI subscriptions programmatically.
  7. 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 Operation

Splunk -- WMI Subscription via Windows Event 5861

index=wineventlog source="Microsoft-Windows-WMI-Activity/Operational" EventCode=5861
| table _time Computer NamespaceName Operation PossibleCause

PowerShell -- Enumerate WMI Subscriptions

Get-WmiObject -Namespace root\subscription -Class __EventFilter
Get-WmiObject -Namespace root\subscription -Class __EventConsumer
Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding

KQL -- 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, ProcessCommandLine

Sigma 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.003

Common Scenarios

  1. APT29 WMI Persistence: Creates an ActiveScriptEventConsumer that executes a VBScript backdoor on system startup, surviving reboots and credential resets.
  2. Turla WMI Backdoor: Uses Win32_ProcessStartTrace filter combined with CommandLineEventConsumer for covert command execution.
  3. FIN8 WMI Timer: Interval-based __IntervalTimerEvent triggering encoded PowerShell downloads every 30 minutes.
  4. MOF-Based Installation: Adversary drops a .mof file and compiles it with mofcomp.exe to 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 events

Core 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 parsing
standards.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, CommandLineTemplate

Step 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, Consumer

Phase 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 Destination

Step 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 PossibleCause

Phase 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 ParentImage

Step 3.2 - MOF Compilation Detection

index=sysmon EventCode=1 Image="*\\mofcomp.exe"
| table _time Computer User CommandLine ParentImage

Phase 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-WmiObject

Phase 5: Response

  1. Document all found subscriptions with full details
  2. Remove malicious subscriptions from all affected hosts
  3. Block WMI subscription creation via Group Policy where possible
  4. Deploy ongoing monitoring via Sysmon Events 19/20/21
  5. 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 KB
Keep exploring