Einleitung
HTTP-Access-Logs sind in Wazuh häufig der Einstiegspunkt für Web- und AppSec-Korrelationen: Brute-Force, Scans, verdächtige User-Agents, Exploit-Versuche und Policy-Verstöße werden oft erst durch sauber extrahierte Felder wirklich auswertbar. In der Praxis scheitert die Erweiterung bestehender Decoder jedoch oft an einem Detail: der Decoder-Pipeline und der Art, wie Wazuh Parent-, Child- und „Sibling“-Decoder auswertet. Dieser Beitrag zeigt, warum ein scheinbar korrekt definierter Custom-Decoder nicht greift – und welche belastbaren Wege es gibt, Referer und User-Agent zuverlässig zu extrahieren.
Ausgangslage / Problemstellung
Eine Umgebung verarbeitet klassische Nginx/Apache-Access-Logs im Combined-Format, z. B.:
192.168.17.250 - - [13/Jan/2026:19:23:45 +0000] "POST /zabbix.php?action=notifications.get&output=ajax HTTP/1.1" 200 565 "https://zabbix.example.com/..." "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0"
Ziel: Referer und User-Agent als zusätzliche Felder extrahieren, wenn die Standard-Regel/Decoder-Familie für web-accesslog bereits matched.
Ein Custom-Decoder wird unter local_decoders.xml angelegt, mit Parent web-accesslog. In wazuh-logtest erscheint jedoch kein neues Feld – als ob der Decoder nie geladen oder nie ausgewertet würde.
Technische Analyse
1) Decoder-Auswertung: „Ein Treffer – und Schluss“
Wazuh-Decoder sind hier nicht wie viele Parser-Pipelines („mehrere Decoder matchen nacheinander“) aufgebaut. Bei Web-Access-Logs passiert typischerweise Folgendes:
- Ein Parent-Decoder (
web-accesslog) führt zum passenden Decoder-„Stamm“. - Danach greifen Child-Decoder, um Varianten abzudecken (z. B. IP-basiert, Hostname-basiert, spezielle Formate).
- Sobald ein passender Child-Decoder gefunden wurde (z. B.
web-accesslog-ip), wird nicht automatisch noch ein weiterer „Sibling“ ausgewertet.
Das erklärt den Effekt: Wenn dein Log bereits von einem bestehenden Child-Decoder wie web-accesslog-ip erkannt wird, kommt dein zusätzlicher Decoder nicht mehr zum Zug.
2) „Sibling“-Decoder sind keine name-freien Geschwister, sondern dieselbe Decoder-Identität
In Wazuh ist „Sibling“ nicht „anderer Decoder mit anderem Namen“, sondern eine Gruppe mehrerer Decoder-Definitionen, die denselben name tragen. Diese Technik wird genutzt, um mehrere Regex-Varianten unter einem Decoder-Namen bereitzustellen (optional vorhandene Felder, leicht wechselnde Feldreihenfolgen etc.).
Ein Decoder mit neuem Namen wie web-accesslog-referer ist damit kein Sibling, sondern ein normaler zusätzlicher Child-Decoder – und wird in der Praxis nur dann geprüft, wenn vorherige Child-Decoder nicht matchen.
3) Datei-Reihenfolge und „Decoder Family“-Grenzen
Decoder werden zudem in Dateireihenfolge geladen und ausgewertet. Das erlaubt einen pragmatischen Workaround: Eine frühere Datei (alphabetisch kleiner) kann einen passenderen Decoder bereitstellen, bevor der Standard-Decoder greift.
Lösung / Best Practices
Es gibt drei robuste Strategien – je nach gewünschtem Eingriffstiefen- und Wartungsniveau.
Option A: Custom-Decoder vor Standard-Decodern auswerten (empfohlen, minimal-invasiv)
Lege eine zusätzliche Decoder-Datei an, die vor der Standard-Datei geladen wird, z. B.:
/var/ossec/etc/decoders/0374-web-accesslog-ext-decoders.xml
Dort definierst du einen präzisen Decoder, der Combined-Logs (inkl. Referer/User-Agent) sauber matcht und Felder extrahiert. Wichtig: Möglichst spezifische prematch/Regex, damit du keine anderen Weblog-Varianten störst.
Beispiel (an Combined-Format orientiert, mit klarer Feldextraktion):
<decoder name="web-accesslog-ip-referer">
<type>web-log</type>
<prematch>^\S+ \S+ \S+ \[.*\] "\w+ \S+ HTTP\/[0-9.]+" \d+ \d+ ".*" ".*"</prematch>
<regex>^(\S+) \S+ \S+ \[.*\] "(\w+) (\S+) HTTP\/[0-9.]+" (\d+) \d+ "(.*)" "(.*)"$</regex>
<order>srcip, protocol, url, id, referer, user-agent</order>
</decoder>
Zusatz: Stelle sicher, dass Datei und Inhalt dem Wazuh-User gehören:
- Owner/Group:
wazuh:wazuh
Anschließend:
systemctl restart wazuh-manager- Test mit
/var/ossec/bin/wazuh-logtest
Vorteil: Du musst Standard-Dateien nicht anfassen und gewinnst trotzdem Kontrolle über die Decoder-Priorität.
Option B: Standard-Decoder ersetzen (sauber, aber wartungsintensiver)
Wenn du den Standard-Decoder wirklich umbauen willst (z. B. mehrere Varianten als Siblings innerhalb derselben Decoder-Familie), dann ist der belastbare Weg:
- Standard-Datei aus dem Ruleset nach
etc/decoderskopieren (niemals im Ruleset selbst ändern). - Original-Datei per
<decoder_exclude>inossec.confdeaktivieren. - In der kopierten Datei gezielt Decoder erweitern oder Sibling-Varianten hinzufügen.
Beispiel-Konzept:
- Datei kopieren nach:
/var/ossec/etc/decoders/web-accesslog_decoders.xml - In
/var/ossec/etc/ossec.conf:
<ruleset>
<decoder_dir>etc/decoders</decoder_dir>
<rule_dir>etc/rules</rule_dir>
<decoder_exclude>0375-web-accesslog_decoders.xml</decoder_exclude>
</ruleset>
Dann in der kopierten Decoder-Datei eine zusätzliche Regex-Variante als Sibling unter gleichem Namen platzieren (gleicher name, mehrere Definitionen).
Vorteil: Vollständige Kontrolle.
Nachteil: Du trägst die Decoder-Familie selbst und musst bei Upgrades vergleichen/mergen.
Option C: out_format nutzen und komplett eigene Decoder-Familie aufbauen
Das ist sinnvoll, wenn du die Standard-web-accesslog-Kette bewusst umgehen willst. Per out_format kannst du das Log „präfixen“ oder normalisieren, sodass es nicht mehr auf die Standard-Decoder passt. Dann baust du eine eigene Decoder-Pipeline (und ggf. eigene Regeln). Das ist die flexibelste, aber auch aufwendigste Variante.
Lessons Learned / Best Practices
- Decoder-Matching ist nicht additiv: Ein früher Treffer verhindert spätere Decoder-Auswertung.
- „Sibling“ bedeutet: gleicher Decoder-Name, nicht „gleicher Parent“ oder „gleiches Thema“.
- Nutze Dateipriorität (alphabetische Reihenfolge), um Custom-Decoding „vor“ Standard-Decoding zu erzwingen.
- Verwende
prematchso spezifisch wie möglich, um Seiteneffekte zu vermeiden. - Änderungen an Decodern sind immer ein Manager-Thema (nicht Agent): Decoder laufen serverseitig, daher
wazuh-managerneu starten. - Teste Änderungen konsequent mit
wazuh-logtestund halte ein Set repräsentativer Beispielzeilen vor (mit/ohne Referer, mit/ohne UA).
Fazit
Wenn dein Custom-Decoder bei web-accesslog nicht greift, liegt das in der Regel nicht an „nicht geladen“, sondern an der Decoder-Logik: Ein vorhandener Child-Decoder matcht bereits, und Wazuh wertet keine weiteren Decoder in dieser Kette aus. Der pragmatischste Weg ist, einen spezifischen Custom-Decoder in einer früher geladenen Datei zu platzieren. Alternativ kannst du die Standard-Decoder-Familie kontrolliert ersetzen oder komplett eigene Decoder mit out_format aufbauen. So bekommst du Referer und User-Agent zuverlässig in die Eventfelder – und damit die Grundlage für aussagekräftigere Detection- und Hunting-Workflows.
Mehr zu Wazuh …
https://wazuh.com/?utm_source=ambassadors&utm_medium=referral&utm_campaign=ambassadors+program
Mehr zum Wazuh Ambassador Program …
https://wazuh.com/ambassadors-program/?utm_source=ambassadors&utm_medium=referral&utm_campaign=ambassadors+program
https://wazuh.slack.com/archives/C0A933R8E/p1768485481774999