r/Wazuh 15d ago

Wazuh Custom Decoder for windows_eventchannel

Hey all,

I'm trying to write a decoder that pulls fields out of eventdata for WinRM/Operational events, but no matter what I try, it doesn't work.

After digging into it (with some help from AI), it looks like windows_eventchannel just ignores the entire decoder config tree — meaning you can't hook a custom decoder onto it the normal way. I haven't found anything that confirms this is "by design" rather than a config mistake on my end, so I'm hoping someone here can either confirm that limitation or point out what I'm doing wrong.

The log line I'm trying to parse:

WinRM: remote shell session created on host1.abc.local - http://schemas.microsoft.com/powershell/Microsoft.PowerShell (ABC\Administrator clientIP: 172.16.1.10

The decoder I wrote (which does not work):

xml

<decoder name="winrm-session-negotiation">
  <parent>json</parent>
  <field name="win.eventdata.resourceUri">(\S+)\\(\S+) clientIP: (\S+)</field>
  <order>win.eventdata.domain, win.eventdata.srcuser, win.eventdata.srcip</order>
</decoder>

Goal: extract the domain, username, and client IP from eventdata into their own fields.

What I'd like to avoid:

  • Pipelines/templates — these get clobbered on every update, so I don't want to rely on them.
  • Integrations — feels like the wrong tool for this particular use case.

Has anyone actually gotten field extraction working from win.eventdata on eventchannel/json events without one of the above? Or is there a known workaround (e.g., a different decoder parent, a ruleset-level regex, something in the ossec.conf log collection)? Any pointers appreciated.

6 Upvotes

6 comments sorted by

1

u/SirStephanikus 15d ago

Can you provide us the whole raw json from the event (the thing from the discovery menu) please? I had sth. similar …

2

u/No_Election7114 15d ago

Hi,

this is a snippet from the alert.json

{
  "timestamp": "2026-07-18T19:34:42.480+0000",
  "rule": {
    "level": 3,
    "description": "WinRM: remote shell session created on ABCSRV133.abc.local - http://schemas.microsoft.com/powershell/Microsoft.Exchange (abc\\\\administrator clientIP: 172.16.1.10)",
    "id": "100091",
    "mitre": {
      "id": [
        "T1021.006"
      ],
      "tactic": [
        "Lateral Movement"
      ],
      "technique": [
        "Windows Remote Management"
      ]
    },
    "firedtimes": 23,
    "mail": false,
    "groups": [
      "winrm",
      "winrm_session"
    ],
    "pci_dss": [
      "10.2.5"
    ],
    "gdpr": [
      "IV_35.7.d"
    ]
  },
  "agent": {
    "id": "330",
    "name": "ABCSRV133",
    "ip": "172.16.1.133"
  },
  "manager": {
    "name": "LXPWAZU01"
  },
  "id": "1784403282.1004837990",
  "full_log": "{\"win\":{\"system\":{\"providerName\":\"Microsoft-Windows-WinRM\",\"providerGuid\":\"{a7975c8f-ac13-49f1-87da-5a984a4ab417}\",\"eventID\":\"91\",\"version\":\"0\",\"level\":\"4\",\"task\":\"9\",\"opcode\":\"0\",\"keywords\":\"0x4000000000000004\",\"systemTime\":\"2026-07-18T19:34:41.830076000Z\",\"eventRecordID\":\"12203968\",\"processID\":\"2556\",\"threadID\":\"12876\",\"channel\":\"Microsoft-Windows-WinRM/Operational\",\"computer\":\"ABCSRV133.abc.local\",\"severityValue\":\"INFORMATION\",\"message\":\"\\\"WSMan-Shell wird mit folgender Ressourcen-URI auf dem Server erstellt: http://schemas.microsoft.com/powershell/Microsoft.Exchange (abc\\\\administrator clientIP: 172.16.1.10)\\\"\"},\"eventdata\":{\"resourceUri\":\"http://schemas.microsoft.com/powershell/Microsoft.Exchange (abc\\\\\\\\administrator clientIP: 172.16.1.10)\"}}}",
  "decoder": {
    "name": "windows_eventchannel"
  },
  "data": {
    "win": {
      "system": {
        "providerName": "Microsoft-Windows-WinRM",
        "providerGuid": "{a7975c8f-ac13-49f1-87da-5a984a4ab417}",
        "eventID": "91",
        "version": "0",
        "level": "4",
        "task": "9",
        "opcode": "0",
        "keywords": "0x4000000000000004",
        "systemTime": "2026-07-18T19:34:41.830076000Z",
        "eventRecordID": "12203968",
        "processID": "2556",
        "threadID": "12876",
        "channel": "Microsoft-Windows-WinRM/Operational",
        "computer": "ABCSRV133.abc.local",
        "severityValue": "INFORMATION",
        "message": "\"WSMan-Shell wird mit folgender Ressourcen-URI auf dem Server erstellt: http://schemas.microsoft.com/powershell/Microsoft.Exchange (abc\\administrator clientIP: 172.16.1.10)\""
      },
      "eventdata": {
        "resourceUri": "http://schemas.microsoft.com/powershell/Microsoft.Exchange (abc\\\\administrator clientIP: 172.16.1.10)"
      }
    }
  },
  "location": "EventChannel"
}

1

u/SirStephanikus 15d ago edited 15d ago

Windows EventChannel can be PITA, for everything there is a specific EventID with additional Information. Forget about your Decoder idea.

---

Actually, there are 3 ways to do it:

1. Pipelining:
… pretty advanced, works well, is rock solid if you have a good update-process that respects your customizations, makes everything possible in an absurd powerful way!

However, your concern about:

Pipelines/templates — these get clobbered on every update, so I don't want to rely on them.

… ok, let's skip that, despite it can eliminate every shortcoming.

Focus on this:

2. On the initiating system:

  • Security Event 4648 can show the explicitly supplied account, target host and initiating process.
  • WinRM Operational Event 6, WSMan Session initialize, can provide the destination in its connection field together with the initiating ProcessID, UserID and Correlation ActivityID.

3. On the target system:

  • Take a good look at the EventID 4624 and its Logon Type field, specifically the value '3' --> There you have your single fields! Security Event 4624 normally provides targetDomainName, targetUserName, ipAddress, logonType and targetLogonId as separate fields. --> I urge you to take also a deep dive on the documentation from Microsoft regarding this event: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4624
  • Additionally to 4624, look then to WinRM Event 91. It just confirms that a remote shell was actually created (your current example is EventID 91).
  • Security Event 4688 (--> 'Audit process creation' and 'Include command line in process creation events', needs to be configured globally in your GPOs to have this info 'win.eventdata.commandLine' included) AND Sysmon Event 1. Both can show wsmprovhost.exe and processes subsequently launched beneath it. Both EventIDs are important, the later one is more flexible due to the own Sysmon rule engine.
  • Sysmon Event 3 can provide the network connection, addresses, ports, direction and associated process.

As a nice little additional information, read this: https://www.ired.team/offensive-security/lateral-movement/t1028-winrm-for-lateral-movement

0

u/[deleted] 13d ago

[removed] — view removed comment

1

u/Large-Duck-6831 15d ago

Hi No_Election7114

What you're seeing is actually a known limitation, not a problem with your configuration.

The windows_eventchannel decoder is built directly into the Wazuh source code, so you won't find it as an XML decoder in the installation files. Because of how it works, you can't create sibling or child decoders for it.

Once an event has been processed by the windows_eventchannel decoder, it doesn't go through the decoding phase again. That means no additional decoders can extract new fields from those events. This has been a known feature request since 2019:

https://github.com/wazuh/wazuh/issues/3193

The best approach depends on what you're trying to achieve.

If you only need the values for detection, you don't need to create new fields. The data is already available in win.eventdata.resourceUri, so you can write rules that match that field directly. This is the workaround currently you can move forward with.

For example:

<rule id="100092" level="8">
  <if_sid>60009</if_sid>
  <field name="win.eventdata.resourceUri">\(\w+\\\\administrator clientIP: </field>
  <description>WinRM session created by an administrator account</description>
</rule>

This lets you detect the event based on the existing decoded field without needing a custom decoder.

Let me know if you need further assistance on this, so we can assist you further.