use super::super::types::{
ArtifactDescriptor, ArtifactLocation, DataScope, Decoder, FieldSchema, OsScope, TriagePriority,
ValueType,
};
pub(crate) static WMI_PERSISTENCE_CIM_REPOSITORY_FIELDS: &[FieldSchema] = &[
FieldSchema {
name: "namespace",
value_type: ValueType::Text,
description: "CIM namespace the subscription is registered in. Permanent subscriptions are recommended in root\\subscription, but any namespace can host them — check all",
is_uid_component: true,
},
FieldSchema {
name: "filter_name",
value_type: ValueType::Text,
description: "__EventFilter instance name — the trigger. Names the persistence entry",
is_uid_component: true,
},
FieldSchema {
name: "filter_query",
value_type: ValueType::Text,
description: "__EventFilter Query (WQL) — the event that fires the payload (e.g. an __InstanceModificationEvent on Win32_LocalTime for time-based triggering, or process/logon events). The query encodes the trigger condition",
is_uid_component: false,
},
FieldSchema {
name: "consumer_type",
value_type: ValueType::Text,
description: "__EventConsumer subclass — CommandLineEventConsumer (runs a command), ActiveScriptEventConsumer (runs VBScript/JScript), LogFileEventConsumer, SMTPEventConsumer, etc. CommandLine and ActiveScript are the offensive-favourite payload carriers",
is_uid_component: false,
},
FieldSchema {
name: "consumer_name",
value_type: ValueType::Text,
description: "__EventConsumer instance name — the payload object bound to the filter",
is_uid_component: false,
},
FieldSchema {
name: "consumer_payload",
value_type: ValueType::Text,
description: "The executed content: CommandLineEventConsumer CommandLineTemplate (the command line) or ActiveScriptEventConsumer ScriptText (the inline script). This is the highest-signal field — the actual code run on trigger",
is_uid_component: false,
},
FieldSchema {
name: "binding",
value_type: ValueType::Text,
description: "__FilterToConsumerBinding — the link joining one __EventFilter to one __EventConsumer. A subscription is active only when all three objects (filter, consumer, binding) exist; the binding is what makes the pair fire",
is_uid_component: false,
},
FieldSchema {
name: "wmi_activity_operation",
value_type: ValueType::Text,
description: "SEPARATE SOURCE (not the CIM repository): the Microsoft-Windows-WMI-Activity/Operational event-log trace of subscription operations (e.g. Event ID 5861 records permanent-consumer registration), corroborating when the persistence was installed or fired",
is_uid_component: false,
},
];
pub(crate) static WMI_PERSISTENCE_CIM_REPOSITORY: ArtifactDescriptor = ArtifactDescriptor {
id: "wmi_persistence_cim_repository",
name: "WMI Persistence (CIM Repository Event Subscription)",
artifact_type: ArtifactLocation::File,
hive: None,
key_path: "",
value_name: None,
file_path: Some("%SystemRoot%\\System32\\wbem\\Repository\\OBJECTS.DATA"),
scope: DataScope::System,
os_scope: OsScope::All,
decoder: Decoder::Identity,
meaning: "WMI permanent event subscription persistence recovered from the on-disk CIM \
repository. The mechanism is a triple: an __EventFilter (WQL trigger query) linked by a \
__FilterToConsumerBinding to an __EventConsumer (payload — CommandLineEventConsumer runs a command, \
ActiveScriptEventConsumer runs an inline script). All three objects live in the CIM repository \
files OBJECTS.DATA (object store), INDEX.BTR (B-tree index), and MAPPING[1-3].MAP (page maps) under \
%SystemRoot%\\System32\\wbem\\Repository. It is often used as fileless persistence when a standard \
consumer stores an inline command/script payload; custom consumers may rely on registered \
COM/executable components. It is reboot-surviving, and the execution context depends on the \
consumer/provider configuration (commonly the WMI service context for standard consumers). \
Recovery parses the CIM repository (settled reference: Mandiant flare-wmi / python-cim) to \
enumerate the filter query, consumer subclass, and consumer payload (CommandLineTemplate or \
ScriptText — the actual code run), and correlates with the Microsoft-Windows-WMI-Activity/\
Operational event log (e.g. Event ID 5861 records permanent-consumer registration), which is a \
SEPARATE runtime source, not the persistence definition. A subscription is active only when the \
filter, consumer, AND binding all exist. Cross-reference evtx_sysmon (Sysmon Event IDs 19/20/21 \
log WMI filter/consumer/binding activity) for a corroborating live-log view.",
mitre_techniques: &[
"T1546.003", "T1047", ],
fields: WMI_PERSISTENCE_CIM_REPOSITORY_FIELDS,
retention: Some("Persistent in the CIM repository until the subscription is removed; WMI-Activity/Operational log entries rotate"),
triage_priority: TriagePriority::Critical,
related_artifacts: &["evtx_sysmon"],
sources: &[
"https://learn.microsoft.com/en-us/windows/win32/wmisdk/monitoring-events",
"https://learn.microsoft.com/en-us/windows/win32/wmisdk/receiving-a-wmi-event",
"https://github.com/mandiant/flare-wmi/tree/master/python-cim",
],
evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
evidence_caveats: &[
"Legitimate software and management tools (SCCM, antivirus, monitoring agents) also create permanent subscriptions — the payload content, not the mere presence of a subscription, is the signal",
"A subscription is inert without the binding; a stray filter or consumer alone is not active persistence",
"CIM repository parsing recovers deleted/partial objects that may be stale — corroborate a recovered binding against the WMI-Activity log before concluding it was active",
],
volatility: Some(crate::volatility::VolatilityClass::Persistent),
volatility_rationale: "CIM repository objects persist on disk until the subscription is explicitly removed; the mechanism survives reboots by design",
};