Understanding Wazuh Decoders

SOCFortress
7 min readApr 23, 2022

Build custom decoders to ingest any type of log

Intro

Not all logs are built the same. Depending on the source of the logs you are looking to collect, can sometimes require you to build a custom Wazuh decoder. Wazuh provides an out-of-the-box set of decoders and rules, but often times users are left needing to create decoders/rules to handle their unique use case. Thankfully, Wazuh provides us the ability to create our own decoders and rules powered by a flexible regex library.

Wazuh Regex Syntax: https://documentation.wazuh.com/current/user-manual/ruleset/ruleset-xml-syntax/regex.html

Wazuh Decoders Syntax: https://documentation.wazuh.com/current/user-manual/ruleset/ruleset-xml-syntax/decoders.html

Building The Decoder

We can use Wazuh to build decoders that will match on ANYTHING. This flexibility allows us to ingest any type of log into Wazuh, which in turn is written into Elasticsearch and viewable within Kibana. Let’s take for example the below log:

Medium: SOCFortress is an awesome company, check them out at https://www.socfortress.co

Copy the above log and run the wazuh-logtest binary on your Wazuh Manager to see how Wazuh would currently process this received log.

/var/ossec/bin/wazuh-logtest

The above image shows that the Wazuh Manager does not understand how to read this log. Let us build a decoder to change that.

Parent Decoder

When designing the new decoders and rules, you should consider event samples. In the case of the example log above you can see the text Mediumis always present at the beginning of every message, so it can be used in the root decoder prematch. Again, we can use regex to build out our root decoder. The following decoder will attempt to find a match on every log for the expression defined (Medium) and decide whether the child decoders should be considered for triggering or not.

<decoder name="medium">
<prematch>^Medium:</prematch>
</decoder>

The above root decoder is set to a name of medium (this can be any name you want), and our prematch is set to a regex match of ^Medium:. So when Wazuh sees Medium: at the start of the log line (identified by the ^ ) our root decoder will trigger. Open the local_decoder.xml file on the Wazuh Manager and paste in the above decoder:

nano /var/ossec/etc/decoders/local_decoder.xml

Save the file and restart the manager service.

Now let’s run the wazuh-logtest again and see the results.

Notice we are now matching on the medium decoder.

Child Decoder

Now we need to build a child decoder that will allow us to parse out fields that can contain dynamic values to store them into Elasticsearch. The decoder below extracts the values for the headers company, and website. The regex option finds the fields of interest and extracts them through the () operator. The order option defines what the parenthesis groups contain and the order in which they were received.

<decoder name="medium_child">
<parent>medium</parent>
<regex offset="after_parent">^\s(\.+) is an awesome company, check them out at (https://\.+)</regex>
<order>company,website</order>
</decoder>

We first specify a name for our decoder with the <decoder name="medium_child"> (needs to be unique).

We specify who the parent is of our child decoder: <parent>medium</parent>

Now we build our regex match, and since we want this to child decoder to be compared after the parent decoder matches on Medium: , we use the after_parent option. Then we build out the rest of our regex match: ^ (stating that this is the beginning after our parent match), \s (match for a spacebar), (\.+) (match on anything and (SOCFortress) in our example), is an awesome company, check them out at (matches on the static text that will be present in every log that we receive from our medium parent decoder), (https://\.+) (matches on anything after https:// is observed).

Lastly we specify the fields that we want to capture and the key we want to set them to with <order>company,website</order> . These will be replaced by values that are picked up within the () operator. In our case this will be SOCFortress and https://www.socfortress.co .

nano /var/ossec/etc/decoders/local_decoder.xml

Save and restart the Wazuh Manager.

Run the wazuh-logtest again:

Notice SOCFortress is assigned to the key of company and https://www.socfortress.co is assigned to the key of website . Now since the contents of our logs will change, let’s see the () in action. Let’s change our log to:

Medium: OpenSecure is an awesome company, check them out at https://www.opensecure.co

Now OpenSecure is assigned to the key of company and https://www.opensecure.co is assigned to the key of website . And this dynamic change happened with the same two decoders :).

Creating Rules

Creating decoders is only half the battle, in order for the Wazuh Manager to write these logs to Elasticsearch, we need to create rules. Let’s create a rule that matches on the company key containing SOCFortress:

nano /var/ossec/etc/rules/local_rules.xml<group name="medium,socfortress">
<rule id="100021" level="5">
<decoded_as>medium</decoded_as>
<field name="company">SOCFortress</field>
<description>Go check out $(company) at $(website)!</description>
</rule>
</group>

Save and restart the Wazuh Manager.

We specify <decoded_as>medium</decoded_as> because the name of our PARENT decoder is medium .

<field name="company">SOCFortress</field> is set because we want the decoded company field to contain SOCFortress .

Lastly, we provide a description.

We see our rule matching!

Let’s create another rule to match on the company name, OpenSecure .

nano /var/ossec/etc/rules/local_rules.xml<group name="medium,socfortress">
<rule id="100022" level="5">
<decoded_as>medium</decoded_as>
<field name="company">OpenSecure</field>
<description>Go check out $(company) at $(website)!</description>
</rule>
</group>

Save and restart the Wazuh Manager.

Test with this log:

Medium: OpenSecure is an awesome company, check them out at https://www.opensecure.co

We see our new rule firing!

pfSense Firewall

Let’s build a decoder and rule set with a rule world example. Currently, our pfSense firewall is configured to send syslog output to the Wazuh Manager, our Wazuh Manager is receiving the logs:

However, they cannot be decoded or matched on:

1 2022-04-22T13:46:00.769161-05:00 router.localdomain filterlog 48244 - - 107,,,1000005911,mvneta0,match,pass,out,4,0x0,,64,62124,0,none,17,udp,78,104.181.152.45,205.251.194.94,13998,53,58

Parent Decoder

Looking at the raw log, we see 1 followed by the current date and timestamp: 2022–04–22T13:46:00.769161–05:00 . We can use that consistent pattern to create a parent decoder:

<decoder name="pfsense">
<prematch>^\d \d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\d\d\d\d\d\d-\d\d:\d\d</prematch>
</decoder>

\d in our regex above matches on any 0–9 character. More can be seen below:

Child Decoder

Our child decoder will now match on the rest of the log and parse out the router, firewallaction, direction, protocol, srcip, and dstip

<decoder name="pfsense_router">
<parent>pfsense</parent>
<regex offset="after_parent">^(\.+) filterlog \d\d\d\d\d - - \d\d\d,,,\d\d\d\d\d\d\d\d\d\d,\w\w\w\w\w\w\d,\w\w\w\w\w,(\w\w\w\w),(\.+),\d,\dx\d,,\d\d,\d\d\d\d\d,\d,\w\w\w\w,\d\d,(\.+),\d\d,(\.+),(\.+),</regex>
<order>router,firewallaction,direction,protocol,srcip,dstip</order>
</decoder>

Save and restart the Wazuh Manager.

Rerunning our rule test, we can see the decoded fields:

Rule

We can now create rules to match on any of these stripped out fields. Below we created a rule that matches on all traffic that was passed by the firewall.

nano /var/ossec/etc/rules/local_rules.xml<group name="pfsense,syslog">
<rule id="100023" level="5">
<decoded_as>pfsense</decoded_as>
<field name="firewallaction">pass</field>
<description>Traffic from $(srcip) to $(dstip) passed.</description>
</rule>
</group>

Results are now viewable within Kibana:

Conclusion

The ability to create custom Wazuh decoders gives us the ability to collect, parse, and store any type of log file. While the learning curve can be a little high, I hope this post helps to clarify how we can use Wazuh to build custom decoders and rules.

Need Help?

The functionality discussed in this post, and so much more, are available via the SOCFortress platform. Let SOCFortress help you and your team keep your infrastructure secure.

Website: https://www.socfortress.co/

Platform Demo: https://www.socfortress.co/demo_access.html

--

--

SOCFortress

SOCFortress is a SaaS company that unifies Observability, Security Monitoring, Threat Intelligence and Security Orchestration, Automation, and Response (SOAR).