In this article
Build an investigation route, not another archive
A suspicious process runs, Windows records it, yet the administrator sees nothing. Let’s build Sysmon → WEF → Wazuh and validate every stage rather than the agent’s green status.
Hello, colleagues. I’m Maksim, a systems administrator. I want signals that answer specific questions: who launched remote management, why rphost created a shell, what accessed LSASS and who changed the sensor itself. Another question matters just as much: will the record reach us after its source has been temporarily disconnected?
We will start with a small pilot, not a promise to detect everything: one or two domain computers, a dedicated Windows Event Collector, its Wazuh agent and eight local rules extending the stock ruleset. We will retain process context, collect selected connections and evidence of logging interference, then trace a harmless command to the manager.
The example targets Windows Server 2022 and Windows PowerShell 5.1, Sysmon15.22 and rule parents from Wazuh4.14.0 source. These are selected versions, not a latest-version claim. Check schema acceptance with the installed Sysmon binary and record Windows patches and the actual ruleset before piloting. References checked23October2026.
Download the configuration and validation kit: Sysmon XML, two WEF subscriptions, an ossec.conf fragment, eight rules, two PowerShell helpers and a local validator. The configuration and expected outcomes are explained below.
Architecture: where events and source identity can disappear
Sysmon writes Microsoft-Windows-Sysmon/Operational at the source; Windows produces Security and System events. WEF selects records and delivers them into ForwardedEvents on WEC. A Wazuh agent reads that channel as eventchannel; the manager decodes records and applies rules. Indexing and notification are further stages requiring validation.

Keep three identities distinct: the source computer authenticating to WEC, the source-side service context reading logs, and the Wazuh agent identifying the collector. Consequently, agent.name is not every original host’s name. Rules use win.system.computer; indexed documents expose data.win.system.computer. The ForwardedEvents destination must not replace the event’s original System/Channel value.
Inspect actual XML and decoder Phase2. Otherwise hundreds of source hosts can be attributed to one WEC, and apparent cross-host repetition becomes repetition from one agent. The providerName, channel and computer fields come from the event’s system section: Wazuh v4.14.0 decoder.
One collector agent replaces this forwarded-event ingestion path only. It does not install endpoint FIM, SCA, inventory, vulnerability detection or active response on remote sources. Consider endpoint agents separately when those capabilities are required. WEC itself is critical infrastructure: observe availability, queues and disk capacity too.
The minimum includes context, not just existing alerts
The obvious solution collects everything. The opposite extreme retains only records already producing alerts. That leaves little process ancestry to investigate: useful predecessors were discarded before the incident.
I distinguish detection signals from investigation context. This pilot retains process creation and narrows more expensive classes by purpose. Expand scope and choose retention after measuring the workload. The selection does not cover every ATT&CK technique or establish sufficient protection.
| Source / ID | Purpose | Inference limit |
|---|---|---|
| Sysmon1 | Process tree, command, image, ProcessGuid | A command can be legitimate; one record is not compromise |
| Sysmon3, selected images | Process-to-destination context, including internal traffic | No content decryption or RMM ownership verdict |
| Sysmon10 → lsass.exe | Identify access to a sensitive process | Access does not prove memory reading or stolen passwords |
| Sysmon4,16,255 | Sensor stop, configuration change and errors | The final event may never leave the source |
| Security4698,4702 | Task creation and modification | Needs advanced auditing; tasks can be legitimate |
| Security5136 | AD object changes on a DC | Needs auditing/SACL; not complete SYSVOL file auditing |
| Security1102; System104,7045 | Security/other-log clearing and service installation | Requires actor and maintenance context |
An RMM launch does not establish unauthorized management; LSASS access does not establish stolen passwords; a new service is not necessarily malicious. A useful detection produces an investigation queue with source, process, actor and maintenance context rather than an automatic verdict.
Wazuh already ships detections. A level0 Sysmon classifier does not make the entire ruleset alert-free: rule61620, for example, has level12. Our rules extend rather than replace that coverage. Inspect the Sysmon ruleset Wazuh v4.14.0 instead of relying on IDs from someone else’s installation.
Level1. Sysmon: keep ancestry and internal-network visibility
Start with one workstation and one application server. Collect process creation across that pilot to retain parent, command and ProcessGuid context. Select network events for AnyDesk, TeamViewer, client32 and rphost, and LSASS access for source/GrantedAccess investigation. These names are neither a complete RMM inventory nor protection against every renamed binary.
Do not globally exclude internal addresses. Lateral activity and RMM using an internal intermediary would disappear with RFC1918 exclusions. Reduce volume through pilot scope and process selection first, then evidence-backed exceptions.
<Sysmon schemaversion="4.82">
<HashAlgorithms>SHA256</HashAlgorithms>
<EventFiltering>
<!-- All process creation on the PILOT; retain parent/command-line context. -->
<RuleGroup name="Process context" groupRelation="or">
<ProcessCreate onmatch="exclude" />
</RuleGroup>
<!-- Internal connections deliberately remain visible. -->
<RuleGroup name="Selected network" groupRelation="or">
<NetworkConnect onmatch="include">
<Image condition="end with">\AnyDesk.exe</Image>
<Image condition="end with">\TeamViewer.exe</Image>
<Image condition="end with">\client32.exe</Image>
<Image condition="end with">\rphost.exe</Image>
</NetworkConnect>
</RuleGroup>
<RuleGroup name="LSASS access context" groupRelation="or">
<ProcessAccess onmatch="include">
<TargetImage condition="end with">\lsass.exe</TargetImage>
</ProcessAccess>
</RuleGroup>
<!-- Explicitly disable selected high-volume/unneeded classes in this pilot. -->
<ProcessTerminate onmatch="include" />
<ImageLoad onmatch="include" />
<DriverLoad onmatch="include" />
<CreateRemoteThread onmatch="include" />
<RawAccessRead onmatch="include" />
<FileCreate onmatch="include" />
<RegistryEvent onmatch="include" />
<FileCreateStreamHash onmatch="include" />
<PipeEvent onmatch="include" />
<WmiEvent onmatch="include" />
<DnsQuery onmatch="include" />
</EventFiltering>
</Sysmon>
Schema4.82 comes from Microsoft’s published example. Schema and binary versions are distinct: -? config displays installed configuration information and -s displays its schema. Generic XML parsing does not establish Sysmon acceptance. Explicit groupRelation avoids relying on implicit grouping, but verify mixed-field and nested-rule behavior in the actual version. Sysmon — Microsoft Learn.
Warning: installation adds a service/driver; replacing XML can remove existing coverage. Preserve the original deployment file, binary signature/version and service state. The -c display is useful inspection, not an assured replacement for the original rollback XML. Use an official binary only on the approved pilot.
# Windows Server 2022 / Windows PowerShell 5.1, approved elevated pilot console.
# Inspect first. Keep the exact previous deployment XML before applying a change.
.\Sysmon64.exe -? config
.\Sysmon64.exe -s
.\Sysmon64.exe -c
# First installation ONLY after approval and review of the supplied XML:
.\Sysmon64.exe -accepteula -i .\sysmon-minimal.xml
# Existing deployment: use -c instead of -i, with a preserved rollback config.
# .\Sysmon64.exe -c .\sysmon-minimal.xml
Get-Service Sysmon64
wevtutil.exe qe Microsoft-Windows-Sysmon/Operational /c:3 /rd:true /f:xml
Expect accepted configuration, a running service and Operational records. ID16 concerns configuration changes and ID4 service state; both are not guaranteed after every invocation. Preserve configuration and observed output with the pilot version. Roll back an update using the previous XML and -c. Uninstalling a pre-existing sensor is not a universal rollback.
Level2. WEF starts with source identities and reading authority
Use source-initiated subscriptions within a working domain. A dedicated pilot-OU GPO supplies the collector FQDN. Configure Computer Configuration → Administrative Templates → Windows Components → Event Forwarding → Configure target Subscription Manager with Server=http://wec01.example.com:5985/wsman/SubscriptionManager/WEC,Refresh=60. Replace the example FQDN with the approved collector.
Refresh=60 concerns subscription-configuration refresh, not guaranteed one-minute event delivery. The XML uses MinLatency; Microsoft describes a30-second batch timeout for that mode. Queues and outages add their own delays. WEF performance guidance.
With domain Kerberos authentication, WinRM HTTP can protect message content without TLS. That is not permission to enable Basic or AllowUnencrypted. Check naming, time, trust and actual authentication independently. Non-domain or different-trust deployments need their own HTTPS/certificate design rather than a mechanical copy of this pilot.
Security reading authority belongs at the source. For a member server, inspect NETWORK SERVICE membership in Event Log Readers or approved channel access. Adding that identity only on WEC cannot repair remote Security access. Treat DCs separately; do not apply local-group automation to them. Microsoft source-initiated setup.
Inspect-WefPilot.ps1 reads state using Source/Collector roles. New-WefPilotFiles.ps1 only generates SID-specific XML and supports -WhatIf. Neither silently enables auditing, changes ACLs or opens firewall exposure. Inspection and mutation deliberately remain separate.
Collector and subscriptions: authorize only the pilot computers
Before WEC setup, record existing listeners, services, firewall and log settings. Restrict collector WinRM exposure to approved sources. Quickconfig changes services and may affect listeners/firewall; it is not read-only inspection. Run from an approved pilot-WEC administrative console with a prepared return path.
# Isolated, approved WEC pilot; elevated Windows PowerShell 5.1.
# Save existing WinRM/WEC/firewall state and limit the listener to pilot sources FIRST.
winrm.exe quickconfig -q
if ($LASTEXITCODE -ne 0) { throw 'WinRM setup failed' }
wecutil.exe qc /q
if ($LASTEXITCODE -ne 0) { throw 'WEC setup failed' }
.\Inspect-WefPilot.ps1 -Role Collector
# Save exact old log settings before resizing; 1 GiB is a PILOT assumption.
wevtutil.exe gl ForwardedEvents
wevtutil.exe sl ForwardedEvents /ms:1073741824
if ($LASTEXITCODE -ne 0) { throw 'Log resizing failed' }
One GiB of ForwardedEvents is an initial assumption, not a capacity calculation. Never shrink an existing larger log merely to match the example. Preserve its original setting and assess retention before any size-reducing rollback.
The main subscription follows. Do not import it with the SID placeholder intact:
<Subscription xmlns="http://schemas.microsoft.com/2006/03/windows/events/subscription">
<SubscriptionId>AF-Sysmon-Pilot</SubscriptionId>
<SubscriptionType>SourceInitiated</SubscriptionType>
<Description>Admin Future pilot: process, selected network, LSASS and sensor state</Description>
<Enabled>true</Enabled>
<Uri>http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog</Uri>
<ConfigurationMode>MinLatency</ConfigurationMode>
<Query><![CDATA[
<QueryList><Query Id="0" Path="Microsoft-Windows-Sysmon/Operational">
<Select Path="Microsoft-Windows-Sysmon/Operational">*[System[(EventID=1 or EventID=3 or EventID=4 or EventID=10 or EventID=16 or EventID=255)]]</Select>
</Query></QueryList>
]]></Query>
<ReadExistingEvents>false</ReadExistingEvents>
<TransportName>http</TransportName>
<ContentFormat>RenderedText</ContentFormat>
<Locale Language="en-US" />
<LogFile>ForwardedEvents</LogFile>
<AllowedSourceDomainComputers>O:NSG:NSD:(A;;GA;;;__PILOT_GROUP_SID__)</AllowedSourceDomainComputers>
</Subscription>
The second downloadable subscription selects Security4698,4702,5136,1102 and System7045,104. Both use ReadExistingEvents=false to start with new records rather than uncontrolled historical replay. RenderedText is an initial pilot choice. Events is more compact but is not a mandatory Wazuh decoder format; validate either across the complete route.
Create an AD group of authorized computer accounts and obtain its real SID. The helper requires a domain SID and a new output directory, but cannot validate the group’s membership for you. A syntactically valid SID does not repair a group containing the wrong principals.
# Replace the SID with YOUR approved AD group of pilot computer accounts.
.\New-WefPilotFiles.ps1 -PilotGroupSid 'S-1-5-21-111-222-333-4444' -OutputDirectory C:\WEF-Pilot-Generated -WhatIf
.\New-WefPilotFiles.ps1 -PilotGroupSid 'S-1-5-21-111-222-333-4444' -OutputDirectory C:\WEF-Pilot-Generated
wecutil.exe es
# Import only if these IDs do NOT already exist; never overwrite another subscription.
wecutil.exe cs C:\WEF-Pilot-Generated\wef-sysmon.xml
if ($LASTEXITCODE -ne 0) { throw 'Sysmon subscription import failed' }
wecutil.exe cs C:\WEF-Pilot-Generated\wef-security-system.xml
if ($LASTEXITCODE -ne 0) { throw 'Security subscription import failed' }
wecutil.exe gs AF-Sysmon-Pilot
wecutil.exe gr AF-Sysmon-Pilot
wecutil.exe gr AF-Security-Pilot
Before cs, use es to establish that these subscription IDs are absent. Following import, gs describes configuration and gr reports source status after GPO application and connection. Subscription existence does not establish access to every selected channel. Syntax: wecutil.
Security events cannot be enabled by XPath alone
WEF does not generate missing audit records. Events4698/4702 require Other Object Access Events with appropriate success auditing. Read auditpol /get /category:* first, then approve a precise pilot-policy change. Auditpol names are localized; enabling every category is not required.
Event5136 concerns AD object changes on a DC and requires Directory Service Changes plus appropriate object SACLs. A directory GPC modification and a GPT file change in SYSVOL are distinct audit surfaces. Do not describe a5136 subscription as comprehensive GPO monitoring. Add appropriate file/permission auditing and evidence of client application when that investigation requires it.
Security clearing produces1102; System104 does not replace it. Wazuh4.14.0 contains stock rule60117 for1102,60228 for4698 and60229 for5136. Use the real installed branch rather than assuming every release shares an ID list. Wazuh4.14.0 Security rules, task auditing, directory-change auditing.
Start with member computers. Add DCs after reviewing volume, channel permissions and the approved SACL policy, not as interchangeable Windows hosts. Absence of5136 on an ordinary member server does not establish WEF failure.
Level3. Wazuh: read ForwardedEvents and observe the queue
The collector needs an already enrolled, healthy Wazuh agent. Add the ForwardedEvents localfile to its existing ossec.conf and merge client_buffer with the existing section. Never replace the complete configuration with this fragment: connection, groups and other settings would disappear. Avoid duplicate sections and duplicate collection of the same channel.
<!-- MERGE into existing ossec_config on the WEC agent. Do not replace the file. -->
<ossec_config>
<localfile>
<location>ForwardedEvents</location>
<log_format>eventchannel</log_format>
</localfile>
<client_buffer>
<disabled>no</disabled>
<queue_size>20000</queue_size>
<events_per_second>500</events_per_second>
</client_buffer>
</ossec_config>
queue_size is measured in events; events_per_second in events per second. Documented defaults are5000 and500. The example raises queue capacity to20000 but retains500EPS. This does not “speed up the SIEM.” The collector agent has other inputs and the manager has additional queues and limits. client_buffer, agent queue and antiflooding.
Apply changes in an approved window with the original ossec.conf retained and post-restart service verification. Eventchannel names a Windows channel; it is not an instruction to submit an arbitrary XML file. Validate WEF format and decoded fields separately. Wazuh Windows eventchannel collection.
A larger queue absorbs a finite burst. Sustained input above output still fills it. Observe antiflooding signals and delivery cessation; otherwise increasing capacity merely postpones loss.
Eight local rules with explicit parents
Install adminfuture_rules.xml as a separate custom file under /var/ossec/etc/rules/ on the manager. Preserve local_rules.xml and vendor rules. The100000–120000 custom range does not guarantee these particular1105xx IDs are unused locally.
| Rule | Wazuh4.14.0 parent | Signal meaning |
|---|---|---|
| 110501 / 110502 | sysmon_event1 → 110501 | RMM name / higher-priority execution path; verify owner |
| 110510 | sysmon_event1 | Server process spawned an interpreter/tool |
| 110511 | sysmon_event3 | Selected-connection context, not a verdict |
| 110520 | sysmon_event_10 | LSASS access requiring investigation, not proven dumping |
| 110542 | 60117 | Raise priority of the stock Security-clear signal |
| 110543 | sysmon_event4 | Sysmon stopped |
| 110544 | 61644 (sysmon_event_16) | Sysmon configuration changed |
Notice the underscores: sysmon_event_10 and sysmon_event_16 differ from sysmon_event1 and sysmon_event3. Event16 uses the actual61644 parent. A plausible but nonexistent group name can break detection even when its regex is correct. Parents are pinned to tag4.14.0, not moving master.
<!-- Wazuh 4.14.0 parents. Check IDs against the INSTALLED complete ruleset. -->
<group name="adminfuture,windows,">
<rule id="110501" level="7">
<if_group>sysmon_event1</if_group>
<field name="win.eventdata.image" type="pcre2">(?i)\\(?:AnyDesk|TeamViewer|client32)\.exe$</field>
<description>AF: RMM process on $(win.system.computer); verify deployment and management owner</description>
<mitre><id>T1219</id></mitre>
</rule>
<rule id="110502" level="9">
<if_sid>110501</if_sid>
<field name="win.eventdata.image" type="pcre2">(?i)^[A-Z]:\\(?:Users\\|ProgramData\\|Windows\\Temp\\|PerfLogs\\|\$Recycle\.Bin\\)</field>
<description>AF: RMM from a review-priority path on $(win.system.computer); establish actual ACLs</description>
</rule>
<rule id="110510" level="12">
<if_group>sysmon_event1</if_group>
<field name="win.eventdata.parentImage" type="pcre2">(?i)\\(?:rphost|ragent|rmngr|w3wp|httpd|nginx|sqlservr|php-cgi)\.exe$</field>
<field name="win.eventdata.image" type="pcre2">(?i)\\(?:cmd|powershell|pwsh|certutil|mshta|wscript|cscript)\.exe$</field>
<description>AF: server process spawned an interpreter/tool on $(win.system.computer); investigate integration versus abuse</description>
</rule>
<rule id="110511" level="5">
<if_group>sysmon_event3</if_group>
<field name="win.eventdata.image" type="pcre2">(?i)\\(?:AnyDesk|TeamViewer|client32|rphost)\.exe$</field>
<description>AF: selected-process connection on $(win.system.computer); context, not compromise proof</description>
</rule>
<rule id="110520" level="7">
<if_group>sysmon_event_10</if_group>
<field name="win.eventdata.targetImage" type="pcre2">(?i)\\lsass\.exe$</field>
<description>AF: process accessed LSASS on $(win.system.computer); inspect source, access mask and call trace</description>
</rule>
<rule id="110542" level="12">
<if_sid>60117</if_sid>
<description>AF: Security log cleared on $(win.system.computer); preserve available evidence</description>
</rule>
<rule id="110543" level="10">
<if_group>sysmon_event4</if_group>
<field name="win.eventdata.state" type="pcre2">(?i)^Stopped$</field>
<description>AF: Sysmon stopped on $(win.system.computer); distinguish maintenance and interference</description>
</rule>
<rule id="110544" level="5">
<if_sid>61644</if_sid>
<description>AF: Sysmon configuration changed on $(win.system.computer); verify approved change</description>
</rule>
</group>
PCRE2 sees decoded field values. Two backslashes in an XML regex represent one Windows-path separator; displayed JSON escaping belongs to another layer. Do not replace separators with arbitrary punctuation just to match a UI copy: that broadens the predicate to unrelated strings.
We checked field predicates independently. Validate actual parent hierarchy, competing-rule order and final alerts on the installed Wazuh live-event route. XML parsing, PCRE2 and logtest over transformed JSON do not substitute for an end-to-end eventchannel test. Reference: Wazuh rule syntax.
Investigate signals without creating exception-shaped gaps
Rule110510 means a server process spawned an interpreter or tool. Review the child command, identity, ParentProcessGuid/ProcessGuid, timing and integration context. For rphost, investigate external processing and application authority; for w3wp, examine publication and web evidence. “Servers never launch cmd” is false: legitimate integrations may do so and need identification.
Rule110501 identifies an RMM-like filename, not ownership of its management plane. Program Files does not establish authorization, a vendor signature does not identify the tenant owner, and an attacker may use the same legitimate binary hash. Therefore this kit has no global “approved hash, ignore everything” suppression. Scope exceptions by purpose, hosts, deployment, management owner and review date.
Rule110502 prioritizes selected Users/ProgramData/Temp-style paths. They are review candidates, not proof that every user can write there; actual ACLs vary. For110520, inspect sourceImage, GrantedAccess and available CallTrace. Security software and approved maintenance can also access LSASS.
Do not describe different_field=win.system.computer as a count of ten distinct hosts. Many events from A plus one from B are not ten different computers. If the requirement is distinct hosts by taskName, implement and test an explicit unique-value aggregation and time window. Otherwise the proposed mass-GPO detection rests on incorrect counting.
Install rules: validate before restarting
Preserve current custom manager configuration. The next block requires Bash, systemd and ripgrep; missing rg stops it rather than skipping ID review. Check conflicts across the complete installed ruleset and confirm real groups/parents. An example ID is not a compatibility guarantee for another release or an already customized installation.
Warning: restarting the Wazuh manager affects event processing. Use an approved window and validate first. On error, restore prior custom-file state rather than repairing syntax while the service is down. Match approved custom-rule ownership/permissions; never use chmod777.
# Linux Wazuh MANAGER only. Separate custom rule file; retain original configuration.
command -v rg >/dev/null || { printf '%s\n' 'ripgrep is required for these review commands; stop here.' >&2; exit 2; }
# Review all installed IDs, not just local_rules.xml.
rg -n 'id="(110501|110502|110510|110511|110520|110542|110543|110544)"' /var/ossec/etc/rules /var/ossec/ruleset/rules
# No matches before installation is expected. Check the pinned parents on YOUR version:
rg -n 'sysmon_event_10|sysmon_event_16|id="60117"|id="61644"' /var/ossec/ruleset/rules
# Place the reviewed kit file at /var/ossec/etc/rules/adminfuture_rules.xml.
# Match approved ownership/permissions of existing custom rules; do not use chmod 777.
# Only after successful validation AND a scheduled change with rollback:
if /var/ossec/bin/wazuh-analysisd -t; then
systemctl restart wazuh-manager && systemctl is-active wazuh-manager
else
printf '%s\n' 'Validation failed. Restore the previous custom rule state; DO NOT restart.' >&2
fi
Successful analysisd -t establishes configuration/loading validation, not every behavioral scenario. Following restart, inspect service state, ossec.log, real ingestion and decoding. Where active response exists, separate new rules from automatic actions initially: a diagnostic pilot must not isolate a server merely because of a filename match.
Stock and custom rules may compete for the final branch. Check the final rule for positive and negative actual events rather than merely finding the desired ID in XML.
A harmless canary checks delivery, not compromise
Activate subscriptions first. ReadExistingEvents=false is not intended to replay records created before connection. On the source, launch a harmless nested command; it creates no task, installs no RMM and does not access LSASS.
# SOURCE, Windows PowerShell 5.1: harmless process-creation canary; no scheduled task.
cmd.exe /d /c "powershell.exe -NoProfile -NonInteractive -Command Write-Output 'AF-WEF-CANARY'"
$Since = (Get-Date).AddMinutes(-10)
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Sysmon/Operational'; Id=1; StartTime=$Since} | Where-Object { $_.ToXml().Contains('AF-WEF-CANARY') } | Select-Object -First 3 TimeCreated, Id, MachineName, RecordId
On WEC, perform this separate read check; do not launch the canary again on the collector:
# COLLECTOR only, Windows PowerShell 5.1; read after source canary and delivery.
$Since = (Get-Date).AddMinutes(-10)
Get-WinEvent -FilterHashtable @{LogName='ForwardedEvents'; Id=1; StartTime=$Since} | Where-Object { $_.ToXml().Contains('AF-WEF-CANARY') } | Select-Object -First 3 TimeCreated, Id, MachineName, RecordId
Find ID1 with the marker in CommandLine at the source, then trace the same chain at WEC. Compare original computer, time and ProcessGuid, not event number alone. RecordId helps local inspection but is not a global identifier and can reset following a cleared log.
This canary has no dedicated rule among the eight. No1105xx alert is required, and its absence does not establish delivery loss. Observe raw manager events in a constrained test window. Temporarily enabling logall_json in the existing global section requires disk/access/retention review; restore its prior value afterward and verify the service. Do not create an indefinite archive of sensitive commands for one check. Wazuh event logging.
# Wazuh manager, approved temporary raw-event capture window; jq must be installed.
# Replace the source name. Use the real full_log string, not the entire archive wrapper.
jq -r 'select(.data.win.system.computer == "LAB-WS01.example.com") | select(.data.win.system.eventID == "1") | select(.full_log | contains("AF-WEF-CANARY")) | .full_log' /var/ossec/logs/archives/archives.json
/var/ossec/bin/wazuh-logtest
# Paste ONE actual full_log line and inspect Phase 2: normalized JSON may use decoder json.
# This is NOT native Windows eventchannel replay or proof of stock-parent matching.
# Do NOT change rule 60000 on production to force a logtest match.
# This canary has NO dedicated custom detection rule: no 1105xx alert is required.
Important boundary: archived full_log may already contain normalized JSON. Ordinary logtest can then report decoder json rather than reproduce the special Windows eventchannel processing used by stock parents. Fields and matching predicates do not prove the same rule will fire on the live route. Wazuh maintainers discuss this limitation; tag4.14.0 exposes the separate path in winevtchannel.c. Never change production rule60000 merely to obtain a successful logtest result. Establish final rule IDs and negative outcomes through an isolated real agent route, not attacks on production.
Capacity: a buffer is not a sizing or observability plan
Size logs from measured ingress and the delivery interruption you must tolerate. WEF uses the source log as its outage buffer. When records are overwritten before delivery, the collector receives no notification identifying that gap. This does not mean all WEF errors are silent: its Operational channel records states, warnings and failures. Microsoft: WEF для обнаружения вторжений.
For example,256MiB at a source and1GiB at WEC are pilot assumptions, not blanket assignments. Assuming2kB/event and100EPS gives720MB/hour before overhead, representation differences and other channels. This is arithmetic, not a measured collector result.
A20000-event queue with900EPS ingress and500EPS egress would theoretically fill in50seconds from empty. Different rates invalidate that interval. More capacity cannot repair sustained throughput deficit.
Measure source, WEC, agent and manager separately: events/bytes per window, actual latency, occupancy, reconnect and catch-up. There is no universal3000EPS collector guarantee here. Test delayed delivery and retention separately after interruption; a healthy-network canary cannot establish them.
What was checked, and how to locate a gap
The kit includes reproducible local validation: five XML files and embedded QueryList documents parse; eight IDs are unique; fourteen positive/negative field-predicate checks run using real PCRE2 through ripgrep. Those checks were actually performed while preparing this article.
# LOCAL validation machine: Python 3 and ripgrep built with PCRE2 are required.
python3 validate-kit.py
# Expected: 5 XML files + embedded queries; 8 unique IDs; 14 PCRE2 checks passed.
# This is NOT a Wazuh, WEF, PowerShell or Sysmon runtime test.
A complete Windows/WEF/Wazuh lab, Sysmon’s own XML acceptance, PowerShell execution, full rule-tree testing and load testing were not performed. Local validation does not make this a production-validated detection package. Deployment requires your pilot and end-to-end evidence.
| Symptom | Inspect | Avoid |
|---|---|---|
| No source canary | Config acceptance, ID1, time window and reading authority | Do not fix Wazuh before the source event exists |
| Source event, no WEC event | SubscriptionManager, runtime status, channel access, Kerberos/WinRM | Do not enable TrustedHosts=* or AllowUnencrypted |
| WEC event, no manager record | Agent, localfile, queue, connection and raw capture | Do not confuse no alert with no received event |
| Received event, missing rule | Phase2, fields, group/parent and competing rules | Do not tune regex against UI-escaped strings |
| Everything attributed to WEC | data.win.system.computer and source XML | Do not substitute agent.name for source identity |
| Event flow disappears | Expected activity, heartbeat, delivery logs and queues | Do not depend only on a sensor-stop event |
Sensor stop and configuration changes are useful signals, but the final record may never leave. Independently observe expected event flow, source state and delivery. A WEF heartbeat concerns subscription connectivity, not complete application-event ingestion. Silence cannot automatically mean no attacks.
Pilot, rollback and the next level
Start with a dedicated OU, restricted computer group and two sources with understandable workloads. Preserve Sysmon, agent and manager configuration, original log settings and affected policy/permissions. Define a window, operator, abort condition and post-rollback check.
Remove only confirmed-owned AF-Sysmon-Pilot and AF-Security-Pilot subscriptions using wecutil ds; restore previous configuration and validate collection. Preserve logs. Never broadly disable WinRM, firewall or Event Log Readers: other services may depend on them. Shrinking a log is not an automatically safe reverse operation. To unload the new custom-rule file, preserve it outside the included directory and restore known-good configuration before restarting.
Pilot success is not a rule count. It is several demonstrated routes: the record exists, arrives with correct source identity, follows the intended decoder and produces an explainable signal, plus understood behavior during outage, capacity pressure and maintenance.
Next I would add PowerShell4104, DNS22, ProcessTampering25, SYSVOL file changes and a dedicated correlation scenario one at a time, measuring volume and negative cases. Investigation context has purpose and cost even without an immediate alert.
How do you establish legitimate RMM management ownership and detect a lost flow after the sensor stops reporting? Share approaches without secrets or customer data. Download the pilot kit here; begin with its README and checks rather than mass deployment.



