Custom Decoder for pfSense with Suricata

291 views
Skip to first unread message

Lukas Fritzsche

unread,
Oct 20, 2025, 3:59:46 AM10/20/25
to Wazuh | Mailing List
Hello everyone,

since this is my first time trying to create a custom decoder I am having a rather rough time trying to get them to work (evenwith chatgpt and the official documents i just dont get the hang of it).
Basically I tried to install the wazuh agent on pfSense (version 25.07.1) which doesnt work because for the FreeBSD port of the wazuh agent 4.12.0, pkg needs to update to 2.3.1 which results in pkg breaking and becoming unusable, but thats a thing of its own.

There for I am now forwarding the pfSense logs via syslog to the wazuh-manager. These pfSense logs contain also the suricata logs in json format.
They look something like this (example):

{"timestamp":"2025-10-20T09:21:37.153+0200","agent":{"id":"000","name":"wazuh-server"},"manager":{"name":"wazuh-server"},"id":"1760944897.274871891","full_log":"Oct 20 09:21:37 suricata[57535]: {\"timestamp\":\"2025-10-20T09:21:36.676057+0200\",\"flow_id\":84474839395842,\"in_iface\":\"vtnet1.195\",\"event_type\":\"krb5\",\"src_ip\":\"SOURCEIP\",\"src_port\":88,\"dest_ip\":\"DEST-IP\",\"dest_port\":54591,\"proto\":\"TCP\",\"pkt_src\":\"wire/pcap\",\"krb5\":{\"msg_type\":\"KRB_TGS_REQ\",\"cname\":\"<empty>\",\"realm\":\"DOMAIN\",\"sname\":\"host/SOURCEHOST\",\"encryption\":\"<none>\",\"weak_encryption\":false}}","predecoder":{"timestamp":"Oct 20 09:21:37","hostname":"suricata[57535]:"},"decoder":{},"location":"pfSense-IP"}

So from my understanding the suricata log (json) is nested inside the pfSense log (syslog).

And since no prebuilt decoders can work with this type of log i only see them in archives.log.

I would greatly appreciate any help with creating a decoder for this.
If I have a decoder for this log, I believe the rest (custom rules etc.) I should be able to get.

Thank you very much in advance!

Greetings,

Lukas

Md. Nazmur Sakib

unread,
Oct 20, 2025, 9:03:23 AM10/20/25
to Wazuh | Mailing List

Hello,

The log you have shared is from the archives.json file.

This is the logs after Unescaped JSON.



{"timestamp":"2025-10-20T09:21:37.153+0200","agent":{"id":"000","name":"wazuh-server"},"manager":{"name":"wazuh-server"},"id":"1760944897.274871891","full_log":"Oct 20 09:21:37 suricata[57535]: {"timestamp":"2025-10-20T09:21:36.676057+0200","flow_id":84474839395842,"in_iface":"vtnet1.195","event_type":"krb5","src_ip":"SOURCEIP","src_port":88,"dest_ip":"DEST-IP","dest_port":54591,"proto":"TCP","pkt_src":"wire/pcap","krb5":{"msg_type":"KRB_TGS_REQ","cname":"<empty>","realm":"DOMAIN","sname":"host/SOURCEHOST","encryption":"<none>","weak_encryption":false}}","predecoder":{"timestamp":"Oct 20 09:21:37","hostname":"suricata[57535]:"},"decoder":{},"location":"pfSense-IP"}


You can check this website for Unescape and Escape  JSON.

https://www.freeformatter.com/json-escape.html#before-output


You need to test the logs inside the full_log section.



Oct 20 09:21:37 suricata[57535]: {"timestamp":"2025-10-20T09:21:36.676057+0200","flow_id":84474839395842,"in_iface":"vtnet1.195","event_type":"krb5","src_ip":"SOURCEIP","src_port":88,"dest_ip":"DEST-IP","dest_port":54591,"proto":"TCP","pkt_src":"wire/pcap","krb5":{"msg_type":"KRB_TGS_REQ","cname":"<empty>","realm":"DOMAIN","sname":"host/SOURCEHOST","encryption":"<none>","weak_encryption":false}}

This is the actual log your endpoint is sending, and the engine matches the decoders and rules based on this log.

So you need to write your decoder and rules based on this.

It is difficult to use a prematch for this log pattern, as this part cannot be used this part as it is a part of the predecoder.


Oct 20 09:21:37 suricata[57535]:


We can make a decoder for this log with a generic pre-match, but it can match with other logs from other sources and create conflict.

Follow this to forward the logs to the Wazuh manager using rsyslog. Install rsyslog on the Wazuh manager to save the logs in a log file instead of using Wazuh remote syslog collecting capability.

https://wazuh.com/blog/monitoring-network-devices/
https://documentation.wazuh.com/current/cloud-service/your-environment/send-syslog-data.html

Now, while forwarding the logs to the rule engine, you will be able to add additional text with the logs that you can use in the pre-match for creating decoders.

<localfile>

  <log_format>syslog</log_format>

  <location>/var/log/suricata.log</location>

  <out_format>suricata-logs: $(log)</out_format>

</localfile>


Now you will write a parent decoder like this.

<decoder name="suricata">

  <prematch>^suricata-logs: </prematch>

</decoder>

You can follow this document for writing the other child decoders.
Decoders Syntax
Regular Expression Syntax
Custom decoders



Let me know if you need any further assistance.

Lukas Fritzsche

unread,
Oct 22, 2025, 1:40:07 AM10/22/25
to Wazuh | Mailing List
Hello,

thank you very much for your answer.

thats a great idea, i will try from there.
thank you very much!

Lukas Fritzsche

unread,
Oct 22, 2025, 6:00:10 AM10/22/25
to Wazuh | Mailing List
Hello,

using your described method the logs arrive at wazuh inside a new folder and file via rsyslog.
we have our pfSense send the logs to graylog, and graylog send them to the wazuh-manager where we put them into a file via rsyslog.
the logs still look like this: 
2025-10-22T11:54:19.870427+02:00 source-ip {"timestamp":"2025-10-22T11:54:19.669437+0200","flow_id":904885600146364,"in_iface":"vtnet1.195","event_type":"dns","src_ip":"source-ip","src_port":63045,"dest_ip":"destination-ip","dest_port":53,"proto":"UDP","pkt_src":"wire/pcap","dns":{"version":2,"type":"query","id":64256,"rrname":"microsoft-fqdn","rrtype":"A","tx_id":0,"opcode":0}}

i've tested a couple logs without the prefix, so json only, and wazuh is able to decode those natively.
but how do i get rid of the prefix "2025-10-22T11:54:19.870427+02:00 source-ip" ? 

or do i really have to create custom decoders now because of the prefix, eventhough decoders and rules for the json part already exist, since its suricata.

Thank you in advance!

Lukas

Md. Nazmur Sakib

unread,
Oct 23, 2025, 12:49:39 AM10/23/25
to Wazuh | Mailing List
Wazuh JSON decoder is able to read this log with the JSON decoder, as you can see in the screenshot.

log.png

And it is triggering a level 0 alert with the rule ID 86603 as it is considering it an information-level log for  Suricata: DNS.
Current Wazuh rules for Suricata
https://github.com/wazuh/wazuh/blob/master/ruleset/rules/0475-suricata_rules.xml

You can change the rule level to 3 or above to see 86603 alerts on the dashboard, as by default, level 3 and above logs are displayed in the dashboard.

You can follow this document to overwrite the rule level.

But this can lead to heavy noise as you are allowing information-level logs on the dashboard.


You can make some custom rules considering 86603 as a parent rule to get a specific alert. For example, you want to get an alert when the source IP has a bad reputation.
These documents can be useful for writing custom rules 


Let me know if you need any further information.

Lukas Fritzsche

unread,
Oct 27, 2025, 3:49:26 AM10/27/25
to Wazuh | Mailing List
Hello, thank you very much.

I now got it to work using mmjsonparse to refine the logs. 
The wazuh-logtests are successul.

Last but not least probably a more general question:
How exactly do I view the alerts in the dashboard? Since there's no agent to see them on and if im filtering in "Discover" using the suricata groups, i get no results.
Or is this just for e-mail alerts etc.
Im just curious

Thanks for your help!

Md. Nazmur Sakib

unread,
Oct 27, 2025, 4:17:30 AM10/27/25
to Wazuh | Mailing List
You can filter with rule.groups or rule.id in the Discover or Threat Hunting. Check the screenshot for reference.

d12.png

d13.png

If the logs are comminmg direectiry to the manager without any agent, they should be listed under agent.id 000, which is the wazuh-manager's agent ID.


Let me know if you need any further information.


Lukas Fritzsche

unread,
Oct 27, 2025, 4:32:41 AM10/27/25
to Wazuh | Mailing List
Hi,

i have to ask again, how exactly do I have to include the log-file from syslog in the ossec.conf on the wazuh-manager?
I currently have:
  <localfile>
    <log_format>json</log_format>
    <location>/var/log/graylog.log</location>
  </localfile>

since the logs in that file look like this:
{ "timestamp": "2025-10-27T09:30:30.133395+0100", "flow_id": 1698827100699344, "in_iface": "vtnet1.195", "event_type": "dns", "src_ip": "SRC-IP", "src_port": 51610, "dest_ip": "DEST-IP", "dest_port": 53, "proto": "UDP", "pkt_src": "wire\/pcap", "dns": { "version": 2, "type": "query", "id": 22803, "rrname": "RRNAME", "rrtype": "A", "tx_id": 0, "opcode": 0 } }
{ "rrname": "RRNAME, "rrtype": "CNAME", "ttl": 2687, "rdata": "RDATA" }
{ "timestamp": "2025-10-27T09:30:36.674801+0100", "flow_id": 1200683969031609, "in_iface": "vtnet1.195", "event_type": "krb5", "src_ip": "SRC-IP", "src_port": 88, "dest_ip": "DEST-IP", "dest_port": 58564, "proto": "TCP", "pkt_src": "wire\/pcap", "krb5": { "msg_type": "KRB_AS_REQ", "cname": "CNAME", "realm": "DOMAIN", "sname": "krbtgt\/DOMAIN", "encryption": "<none>", "weak_encryption": false } }
{ "timestamp": "2025-10-27T09:30:36.675257+0100", "flow_id": 1200683969031609, "in_iface": "vtnet1.195", "event_type": "krb5", "src_ip": "SRC-IP", "src_port": 58564, "dest_ip": "DEST-IP", "dest_port": 88, "proto": "TCP", "pkt_src": "wire\/pcap", "krb5": { "msg_type": "KRB_ERROR", "failed_request": "KRB_AS_REQ", "error_code": "KDC_ERR_PREAUTH_REQUIRED", "cname": "<empty>", "realm": "<empty>", "sname": "krbtgt\/DOMAIN", "encryption": "<none>", "weak_encryption": false } }

but i still can not see them in the dashboard, when filtering by groups i get no results.

Lukas Fritzsche

unread,
Oct 27, 2025, 4:36:16 AM10/27/25
to Wazuh | Mailing List
oh and in the wazuh-server security logs i can see that:
So they logs should appear in the dashboard right?
Oct 27, 2025 @ 10:26:44.000 wazuh-logcollector INFO (1950): Analyzing file: '/var/log/graylog.log'.

Md. Nazmur Sakib

unread,
Oct 28, 2025, 1:12:11 AM10/28/25
to Wazuh | Mailing List

The log collection configuration looks fine to me.
It seems to me the log collection is working correctly, but as they are information-level logs, they are not generating alerts as per the default rules.

Rules classification



If you want to see alerts for these logs or for testing, you can overwrite the rules level to a higher level and check if you can see them on the dashboard.


For these, add these two rules in the /var/ossec/etc/rules/local_rules.xml
file

<group name="ids,suricata,">

    <rule id="86600" level="5" overwrite="yes">

        <decoded_as>json</decoded_as>

        <field name="timestamp">\.+</field>

        <field name="event_type">\.+</field>

        <description>Suricata messages.</description>

        <options>no_full_log</options>

    </rule>


    <rule id="86603" level="5" overwrite="yes">

        <if_sid>86600</if_sid>

        <field name="event_type">^dns$</field>

        <description>Suricata: DNS.</description>

        <options>no_full_log</options>

    </rule>
</group>



And restart the Wazuh Manager or reload the analysisd engine.

systemctl restart wazuh-manager


Ref: Custom rules

Let me know if you are able to see the alerts in the dashboard for the new rules after adding the rules.

Lukas Fritzsche

unread,
Oct 29, 2025, 2:21:46 AM10/29/25
to Wazuh | Mailing List
Hello,

they are indeed showing up now, thank you very much!

One last question tho (because I don't see it in https://wazuh.com/blog/monitoring-network-devices/)
Right now all suricata logs are written in /var/log/graylog.log.
Is there any need to delete and recreate this file from time to time as it fills up? Or is that not needed, because I don't see anything about that in the wazuh blog.
I'm just curious.

Thank you very much for your help so far, you helped me a lot!

Md. Nazmur Sakib

unread,
Oct 29, 2025, 4:21:44 AM10/29/25
to Wazuh | Mailing List
If you do not want to keep the raw logs on that endpoint once they are forwarded to Wazuh, you can configure cron job and delete the old logs from the /var/log/graylog.log file periodically to make space.

Once the logs are forwarded to the manager, the alerts from the logs will be saved in alerts.json and alerts.log file on the Wazuh manager(/var/ossec/logs/alerts/alerts.json) and on the Wazuh indexer in the indices.



Let me know if you need any further information.

Md. Nazmur Sakib

unread,
Oct 29, 2025, 4:23:12 AM10/29/25
to Wazuh | Mailing List
You do not need to delete them, as the Wazuh agent only reads the new logs added to that file. But you can delete them if you want.

Lukas Fritzsche

unread,
Oct 29, 2025, 6:50:45 AM10/29/25
to Wazuh | Mailing List
since the file is already 3GB after 2 days of collecting now i figured it might be useful.
i now resorted to logrotate.

Thank you very much for your help, everything works as needed now!
Reply all
Reply to author
Forward
0 new messages