TP-Link Access-Point-Logs in Wazuh dekodieren: Vom „archive.json“-Event zum sauberen Custom-Decoder

Einleitung

Netzwerkgeräte wie Access Points liefern häufig sehr hilfreiche Telemetrie: MAC-Adressen, Quell-/Ziel-IP, Protokoll und Ports. Für Security-Teams sind das ideale Datenpunkte, um laterale Bewegung, ungewöhnliche Verbindungen oder auffällige Client-Aktivität frühzeitig zu erkennen. Damit Wazuh diese Informationen regelbasiert auswerten kann, müssen die Rohlogs jedoch korrekt dekodiert werden. In der Praxis scheitert das oft daran, dass statt der Roh-Syslog-Zeile nur bereits verarbeitete JSON-Ausgaben (z. B. aus archives.json) geteilt werden – und darauf basierend Decoder gebaut werden, die später nicht matchen.

Ausgangslage / Problemstellung

Im Thread lagen Ereignisse vor, die bereits als JSON-Objekte in Wazuh vorlagen (typisch für archives.json/Indexer-Pipeline). Innerhalb dieser JSON-Struktur stand das eigentliche Geräteereignis im Feld full_log, z. B.:

[1767608555.624117131] AP MAC=60:a4:b7:47:8a:56 MAC SRC=7a:1a:09:3e:2b:00 IP SRC=192.168.100.170 IP DST=65.20.88.174 IP proto=6 SPT=64362 DPT=443

Der Wunsch: Ein Decoder, der diese Felder extrahiert (AP-MAC, Client-MAC, Src/Dst-IP, Proto, Src/Dst-Port), damit daraus Regeln und Alarme entstehen können.

Technische Analyse

Wazuh dekodiert Events in einer festen Pipeline:

  1. Logcollect (Agent/Manager) liest Rohzeilen.
  2. Predecoder erkennt ggf. Header (z. B. Syslog-Timestamp/Hostname/Program).
  3. Decoder matcht mit prematch/program_name und extrahiert Felder via regex + order.
  4. Rules werten die extrahierten Felder aus.

Entscheidend:

  • Logs in archives.json sind bereits Ergebnis dieser Pipeline (inkl. Wrapping in JSON mit timestamp, agent, location, full_log usw.). Decoder sollten daher auf die Rohzeile angewendet werden, nicht auf das JSON-Wrapper-Objekt, es sei denn, man nutzt bewusst den JSON-Decoder-Pluginweg. Für klassische Syslog-/Datei-Logs ist die Rohzeile in /var/log/tp-link.log maßgeblich.
  • Ein regex-Block in einem Decoder benötigt ein prematch oder program_name (direkt oder vom Parent) und muss mit order kombiniert werden, sonst ist die Extraktion nicht sauber definiert.
  • Wenn PCRE2 verwendet werden soll, muss type="pcre2" gesetzt werden.

Im Thread war außerdem ein Stolperstein sichtbar: Eine der Zeilen enthielt zusätzliche Prefix-Daten (Timestamp/Host vor der Klammer). Solche Variationen führen dazu, dass ein zu „strenger“ Regex nicht matcht, wenn er exakt am Anfang der Zeile startet.

Lösung / Best Practices

1) Decoder-Strategie: Parent + Child (robust und wartbar)

Ein bewährtes Muster ist:

  • Parent-Decoder: grobes Matching über prematch (z. B. „AP MAC“)
  • Child-Decoder: präzise Extraktion per PCRE2-Regex

Das entspricht der im Thread vorgeschlagenen Lösung und folgt der empfohlenen Decoder-Hierarchie in Wazuh.

2) Robustes Regex-Design: Optionaler Syslog-/Prefix-Teil

Da die Rohzeile je nach rsyslog-Template oder Logquelle optional zusätzliche Header haben kann, sollte der Regex so gebaut werden, dass er nicht zwingend am Zeilenanfang starten muss. Statt ^\[ ist oft besser: „irgendwo kommt [ gefolgt von Zahlen ] AP MAC=“.

Beispiel (konzeptionell) für einen robusteren Child-Decoder:

  • Suche \[\] AP MAC= als Anker
  • Extrahiere danach die Schlüsselwerte

Wichtig: Die Reihenfolge der Capture-Gruppen muss exakt der <order>-Liste entsprechen, damit Felder korrekt zugeordnet werden.

3) Feldnamen an Wazuh-Konventionen anlehnen

Für Regeln und Integrationen ist es sinnvoll, Standardfelder zu verwenden, wo möglich:

  • srcip, dstip, srcport, dstport, protocol
    Eigene Felder (z. B. ap_mac, src_mac) sind ebenfalls möglich, sollten aber konsistent benannt werden.

4) Testen mit wazuh-logtest – aber mit der echten Rohzeile

Für Decoder-/Rule-Debugging ist wazuh-logtest das Standardwerkzeug. Wichtig ist, dass man die Roh-Logzeile (so wie sie aus /var/log/tp-link.log kommt) testet, nicht das JSON aus archives.json.

5) Alternative: JSON-Decoder nur, wenn wirklich JSON „die Quelle“ ist

Falls die Quelle tatsächlich JSON pro Zeile liefert (nicht Wazuh-internes Wrapper-JSON), kann man statt Regex-Decodern den JSON-Decoder einsetzen und Felder direkt aus JSON extrahieren. Das spart Regex-Wartung, setzt aber voraus, dass die Logquelle echtes, einzeiliges JSON liefert.

Lessons Learned / Best Practices

  • Decoder werden gegen Rohlogs gebaut; archives.json ist ein Analyse-Artefakt, kein Decoder-Input.
  • Variierende Prefixe (Syslog-Header, zusätzliche Timestamps) sind der häufigste Grund für „Decoder matcht nicht“. Regex daher auf den stabilen Teil des Events ankern.
  • Parent/Child-Decoder erhöhen Robustheit und erleichtern Erweiterungen (z. B. Varianten mit/ohne Ports).
  • PCRE2 explizit aktivieren (type="pcre2"), wenn man erweiterte Regex-Funktionen benötigt.
  • Immer mit wazuh-logtest iterieren und dabei genau die Logzeile testen, die der Logcollector wirklich liest.

Fazit

Für TP-Link-AP-Logs (oder ähnliche Access-Point-Telemetrie) ist ein Custom-Decoder in Wazuh der Schlüssel, um aus Rohtext verwertbare Security-Signale zu machen. Entscheidend ist, den Decoder auf Basis der echten Rohereignisse aus der Logdatei zu entwickeln, Variationen in Prefix/Headers einzuplanen und die Extraktion per Parent/Child-Ansatz sauber zu strukturieren. Mit wazuh-logtest lässt sich der Decoder anschließend reproduzierbar validieren und zur Grundlage belastbarer Regeln ausbauen.

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/p1767608617853699