195 lines
7.0 KiB
XML
195 lines
7.0 KiB
XML
<!-- Local Decoders -->
|
|
<!-- Modify it at your will. -->
|
|
<!-- Copyright (C) 2015, Wazuh Inc. -->
|
|
|
|
<!--
|
|
================================================================
|
|
Local decoders for Wittenberger.us Homelab
|
|
|
|
Allowed static fields (Wazuh reference):
|
|
location - where the log came from (only on FTS)
|
|
srcuser - extracts the source username
|
|
dstuser - extracts the destination (target) username
|
|
user - alias to dstuser (only one of the two can be used)
|
|
srcip - source IP
|
|
dstip - destination IP
|
|
srcport - source port
|
|
dstport - destination port
|
|
protocol - protocol
|
|
id - event ID
|
|
url - URL of the event
|
|
action - event action (deny, drop, accept, etc.)
|
|
status - event status (success, failure, etc.)
|
|
extra_data - any extra data
|
|
|
|
Custom fields extracted by decoders in this file:
|
|
src_subnet - first three octets of srcip (for /24 correlation)
|
|
|
|
Deploy procedure:
|
|
1. sudo cp local_decoder.xml /var/ossec/etc/decoders/
|
|
2. sudo /var/ossec/bin/wazuh-analysisd -t
|
|
3. sudo systemctl restart wazuh-manager
|
|
|
|
Author: Chris Berger
|
|
Last updated: 2026-07-31
|
|
================================================================
|
|
-->
|
|
|
|
|
|
<!--
|
|
================================================================
|
|
pfSense: wrapped filter log parser
|
|
|
|
Parses pfSense filterlog entries that arrive wrapped in
|
|
additional syslog headers from the pfSense box. Uses chained
|
|
child decoders with offset="after_regex" to extract fields
|
|
from the CSV-like filter log format.
|
|
|
|
All child decoders share the name "pfsense-wrapped-fields"
|
|
intentionally - Wazuh supports multiple same-named children
|
|
when each uses offset="after_regex" to continue from the
|
|
previous child's match position.
|
|
|
|
Referenced by rules 87699, 87761, 87762.
|
|
================================================================
|
|
-->
|
|
<decoder name="pfsense-wrapped">
|
|
<prematch>filterlog</prematch>
|
|
</decoder>
|
|
|
|
<!-- First extraction: rule ID and action -->
|
|
<decoder name="pfsense-wrapped-fields">
|
|
<parent>pfsense-wrapped</parent>
|
|
<regex>filterlog\S* \S*,\S*,\S*,(\S*),\S*,\S*,(\S*),</regex>
|
|
<order>id,action</order>
|
|
</decoder>
|
|
|
|
<!-- Second extraction: protocol and IP addresses -->
|
|
<decoder name="pfsense-wrapped-fields">
|
|
<parent>pfsense-wrapped</parent>
|
|
<regex offset="after_regex">\S*,\S*,\S*,\S*,\S*,\S*,\S*,\S*,\S*,(\S*),\S*,(\S*),(\S*),</regex>
|
|
<order>protocol,srcip,dstip</order>
|
|
</decoder>
|
|
|
|
<!-- Third extraction: source and destination ports -->
|
|
<decoder name="pfsense-wrapped-fields">
|
|
<parent>pfsense-wrapped</parent>
|
|
<regex offset="after_regex">(\d*),(\d*),\S*</regex>
|
|
<order>srcport,dstport</order>
|
|
</decoder>
|
|
|
|
<!-- Fourth extraction: packet length -->
|
|
<decoder name="pfsense-wrapped-fields">
|
|
<parent>pfsense-wrapped</parent>
|
|
<regex offset="after_regex">datalength=(\S*)|(\d*)</regex>
|
|
<order>length</order>
|
|
</decoder>
|
|
|
|
|
|
<!--
|
|
================================================================
|
|
Mailcow journald unwrap (reserved for future use)
|
|
|
|
Strips the outer journald syslog envelope from mailcow container
|
|
logs to expose the inner Postfix log for additional decoding.
|
|
Currently not actively referenced by rules; the
|
|
mailcow-postfix-sasl-fail decoder handles the specific
|
|
Postfix SASL case directly.
|
|
================================================================
|
|
-->
|
|
<decoder name="mailcow-journald-unwrap">
|
|
<prematch>postfix\(\d+\): \w+ \d+ \d+:\d+:\d+ \w+ \.+\(\d+\):</prematch>
|
|
</decoder>
|
|
|
|
<decoder name="mailcow-journald-unwrap-child">
|
|
<parent>mailcow-journald-unwrap</parent>
|
|
<regex offset="after_parent">\.+</regex>
|
|
<order>extra_data</order>
|
|
</decoder>
|
|
|
|
|
|
<!--
|
|
================================================================
|
|
Gitea: authentication event parser
|
|
|
|
Parses Gitea log lines from the syslog output. Referenced by
|
|
all Gitea rules (100400-100470 in local_rules.xml).
|
|
|
|
Sample logs this parses:
|
|
2026/05/29 14:19:59 routers/web/auth/auth.go:309:SignInPost()
|
|
[W] Failed authentication attempt for admin from 192.0.2.100
|
|
2026/05/29 14:19:59 HTTPRequest [I] router: completed POST
|
|
/user/login for 192.0.2.100
|
|
================================================================
|
|
-->
|
|
<decoder name="gitea">
|
|
<program_name>gitea</program_name>
|
|
</decoder>
|
|
|
|
<!-- gitea-auth-fail: extracts username and source IP from failed login events -->
|
|
<decoder name="gitea-auth-fail">
|
|
<parent>gitea</parent>
|
|
<prematch>Failed authentication attempt</prematch>
|
|
<regex>Failed authentication attempt for (\S+) from (\d+.\d+.\d+.\d+)</regex>
|
|
<order>user, srcip</order>
|
|
</decoder>
|
|
|
|
|
|
<!--
|
|
================================================================
|
|
Mailcow Dovecot: rip= field extractor
|
|
|
|
Extracts source IP from any Dovecot event containing "rip=IP,"
|
|
in the log line. Universally useful because rip= appears in
|
|
successful logins, disconnects, no-auth probes, and every other
|
|
connection-related Dovecot event.
|
|
|
|
Named "success" for historical reasons; actually captures on
|
|
ALL Dovecot rip= events. Consider renaming to
|
|
mailcow-dovecot-rip in a future refactor.
|
|
|
|
Referenced by rules 100200-100206 (suppression, recon) and
|
|
indirectly by rule 100311 via rule 100204 chain.
|
|
================================================================
|
|
-->
|
|
<decoder name="mailcow-dovecot-success">
|
|
<parent>dovecot</parent>
|
|
<regex>rip=(\S+),</regex>
|
|
<order>srcip</order>
|
|
</decoder>
|
|
|
|
|
|
<!--
|
|
================================================================
|
|
Mailcow Postfix SASL failure decoder
|
|
|
|
Extracts srcip, src_subnet, and dstuser from mailcow-wrapped
|
|
Postfix SASL authentication failure logs. The double timestamp
|
|
wrapping (journald + inner container timestamp) requires PCRE2
|
|
to match anywhere in the string rather than anchoring to start.
|
|
|
|
Fields extracted:
|
|
srcip full IPv4 source address (e.g., 192.0.2.100)
|
|
src_subnet first three octets (e.g., 192.0.2)
|
|
dstuser the sasl_username the attacker attempted
|
|
|
|
src_subnet enables /24 correlation via
|
|
<same_field>src_subnet</same_field> in rules like 100314.
|
|
Append ".0/24" in rule descriptions for human-readable notation.
|
|
|
|
Sample log this matches:
|
|
Jul 31 02:00:03 mailcow postfix[142]: Jul 30 21:00:03
|
|
e239f49ad459 postfix/submission/smtpd[19867]: warning:
|
|
unknown[92.118.39.225]: SASL LOGIN authentication failed:
|
|
(reason unavailable), sasl_username=ftpuser
|
|
|
|
Referenced by shipped rule 3332 and custom rules 100310-100316.
|
|
================================================================
|
|
-->
|
|
<decoder name="mailcow-postfix-sasl-fail">
|
|
<parent>postfix</parent>
|
|
<prematch type="pcre2">postfix/\S+smtpd\S*: warning: \S+: SASL </prematch>
|
|
<regex type="pcre2">unknown\[((\d+\.\d+\.\d+)\.\d+)\]: SASL \S+ authentication failed.*sasl_username=(\S+)</regex>
|
|
<order>srcip, src_subnet, dstuser</order>
|
|
</decoder>
|