OPNsense WAF Wazuh integration
As a security operations centre (SOC) professional, preventing and stopping web attacks is one of the most significant challenges we face on a daily basis. In a previous article, I discussed the effectiveness of the OPNsense NGINX plugin while defending web servers against attacks. I also highlighted this plugin in my book — OPNsense Beginner to Professional.
While the OPNsense + NGINX + NAXSI bundle blocks known attacks automatically, it’s impossible to expect a 100% accuracy rate in attack detection and prevention. To approach this rate, an effective strategy is to monitor and correlate events, and this is where Wazuh excels.
At Cloudfence we have been using Wazuh for years, and we are impressed with the project’s exceptional improvements through these years. However, despite its wide range of features, decoders, and rules, there are specific cases when it’s necessary to customize or create your own decoders and rules. In this article, I’ll explain how to do just that.
Wazuh and NGINX + NAXSI rules
While Wazuh does contain rules that are capable of reading NGINX + NAXSI events, the implementation in OPNsense differs slightly in terms of log format. Thus, a few adjustments are necessary. While there are existing decoders and rules in the stock Wazuh rules, it is important to note that they may require some modification to work with the specific implementation used in OPNsense and also to extract some fields.
Wazuh + OPNsense
Requirements
To follow the following steps you will need an installed and configured Wazuh manager and an at least one OPNsense agent with NGINX plugin installer and configured with NAXSI rules installed. If you need help with Wazuh and OPNsense, a good starting point is the official documentation. Both projects have extremely rich and detailed documentation:
- Wazuh official documentation
- OPNsense official documentation
- OPNsense NGINX + NAXSI configuration article
OPNsense has a native Wazuh agent package. In this tutorial, I'll not cover its installation and configuration process.
Wazuh Group configuration for OPNsense endpoints
First, we need to create a new group to deploy the configuration to our OPNsense-based agents.
- Create a group called opnsense in the Wazuh Web UI: Management > Groups > Add new group
After creating, click on the pencil icon to edit the group’s configuration and add these lines:
<agent_config>
<localfile>
<log_format>syslog</log_format>
<location>/var/log/nginx/*.log</location>
<out_format>Cloudfence-WAF: $(log)</out_format>
</localfile>
</agent_config>As Wazuh has an NGINX stock decoder, I am using the <out_format> to insert a tag at the beginning of each log file to match our custom decoder, which we will create later.
2. Add an existing OPNsense agent to the new group by clicking on the group's name (opnsense):
Creating the decoder
To create a new custom decoder file go to Management > Decoders and click on the Custom decoders button. Next click on the + Add new decoders file:
Copy and paste the following content to the new decoder file (naxsi-opnsense):
<!-- NAXSI OPNsense: Cloudfence (c)2023 -
https://cloudfence.com.br / Julio Camargo -->
<!-- NAXSI OPNsense
Cloudfence-WAF: 2023/03/16 09:46:51 [error] 72753#110979: *453734 NAXSI_FMT: ip=200.1.2.3&server=200.10.020.3&uri=/%C0&vers=1.3&total_processed=170236&total_blocked=17328&config=drop&zone0=URL&id0=20&var_name0=, client: 200.1.2.3, server: cloudfence.eu, request: "POST /%C0 HTTP/1.1", host: "200.10.20.30" -->
<decoder name="naxsi-opnsense-parent">
<prematch>^Cloudfence-WAF</prematch>
</decoder>
<decoder name="naxsi-opnsense-child">
<parent>naxsi-opnsense-parent</parent>
<prematch>NAXSI_FMT</prematch>
<regex offset="after_prematch">ip=(\S+)\pserver=(\S+)\puri=(\S+)\pvers=(\S+)\ptotal_processed=(\d+)\ptotal_blocked=(\d+)\pconfig=(\w+)\p</regex>
<order>srcip,server,uri,naxsi_version,processed_requests,blocked_requests,mode</order>
</decoder>
<!--
Cloudfence-WAF: 2023/03/16 11:36:12 [error] 72753#110979: *454250 NAXSI_FMT: ip=200.1.2.3&server=fw.cloudfence.eu&uri=/api/ids/settings/set&vers=1.3&total_processed=22531&total_blocked=722&config=learning&cscore0=$policy3dc4de357fc54ccfa0ffd272b08420b7&score0=6&cscore1=$policy323ed56953ea44a695002c72b0a8cd15&score1=8&zone0=BODY&id0=1206&var_name0=homenet&zone1=BODY&id1=1015&var_name1=homenet, client: 200.1.2.3, server: fw.cloudfence.eu, request: "POST /api/ids/settings/set HTTP/2.0", host: "fw.cloudfence.eu", referrer: "https://fw.cloudfence.eu/ui/ids"
-->
<decoder name="naxsi-opnsense-child">
<parent>naxsi-opnsense-parent</parent>
<regex>cscore\d=(\d+)\p</regex>
<order>score_tag</order>
</decoder>
<decoder name="naxsi-opnsense-child">
<parent>naxsi-opnsense-parent</parent>
<regex>score\d=(\d+)\p</regex>
<order>score</order>
</decoder>
<decoder name="naxsi-opnsense-child">
<parent>naxsi-opnsense-parent</parent>
<regex>zone\d=(\S+)\p</regex>
<order>zone</order>
</decoder>
<decoder name="naxsi-opnsense-child">
<parent>naxsi-opnsense-parent</parent>
<regex>id\d=(\d+)\p</regex>
<order>rule_id</order>
</decoder>
<decoder name="naxsi-opnsense-child">
<parent>naxsi-opnsense-parent</parent>
<regex>request: "(\.+)"</regex>
<order>request</order>
</decoder>
<decoder name="naxsi-opnsense-child">
<parent>naxsi-opnsense-parent</parent>
<regex>referrer: "(\.+)"</regex>
<order>referrer</order>
</decoder>In the first block <naxsi-opnsense-parent> the <prematch> matches with our <out_format> used previously in the group configuration file.
Next, in the <naxsi-opnsense-child> blocks extract the fields using regex.
TODO: parse the dynamic fields that can occur more than once in the same log line.
Save it by clicking on the Save button.
Creating the rules
Finally, we create the rules to use the new decoder: Go to Management > Rules and click on the Custom rule button. Next click on the + Add new rules file and create the rules file named custom-naxsi-opnsense:
<!-- NAXSI custom rules IDs: 100100 - 100199 -->
<group name="nginx,web,">
<rule id="100100" level="0" noalert="1">
<decoded_as>naxsi-opnsense-parent</decoded_as>
<description>OPNsense NAXSI events grouped.</description>
</rule>
<rule id="100101" level="6">
<if_sid>100100</if_sid>
<field name="mode">drop|block</field>
<description>OPNsense NAXSI - event blocked by WAF</description>
<mitre>
<id>T1083</id>
</mitre>
<group>naxsi,attack,gpg13_10.1,</group>
</rule>
<rule id="100102" level="10">
<if_sid>100100</if_sid>
<field name="mode">learning</field>
<description>OPNsense NAXSI - event passed by WAF in $(mode) mode</description>
<group>naxsi,attack,</group>
</rule>
</group>The first rule (id 100100) will group the messages to the next two rules (100101 and 100102) will match blocked and passed events from NAXSI respectively.
Testing
After saving the new rules file, restart your Wazuh manager, and using a sample log file click on the Ruleset Test option:
We can use the loglines samples inside the decoder file to test:
The complete output of the ruleset test:
**Phase 1: Completed pre-decoding.
full event: 'Cloudfence-WAF: 2023/03/16 09:46:51 [error] 72753#110979: *453734 NAXSI_FMT: ip=200.1.2.3&server=200.10.020.3&uri=/%C0&vers=1.3&total_processed=170236&total_blocked=17328&config=drop&zone0=URL&id0=20&var_name0=, client: 200.1.2.3, server: cloudfence.eu, request: "POST /%C0 HTTP/1.1", host: "200.10.20.30"'
**Phase 2: Completed decoding.
name: 'naxsi-opnsense-parent'
parent: 'naxsi-opnsense-parent'
blocked_requests: '17328'
mode: 'drop'
naxsi_version: '1.3'
processed_requests: '170236'
request: 'POST /%C0 HTTP/1.1'
rule_id: '20'
server: '200.10.020.3'
srcip: '200.1.2.3'
uri: '/%C0'
zone: 'URL'
**Phase 3: Completed filtering (rules).
id: '100101'
level: '6'
description: 'OPNsense NAXSI - event blocked by WAF'
groups: '["nginx","web","naxsi","attack"]'
firedtimes: '2'
gpg13: '["10.1"]'
mail: 'false'
mitre.id: '["T1083"]'
mitre.tactic: '["Discovery"]'
mitre.technique: '["File and Directory Discovery"]'
**Alert to be generated.As we can see, the both decoder and rule are working well!
Final Thoughts
By creating custom rules tailored to your specific needs, you can further enhance the security of your web applications. With the adjustments made to the Wazuh rules for the OPNsense implementation, you now have the flexibility to create new rules that align perfectly with your security requirements. Strengthen your defences today with Wazuh and OPNsense!
If you need additional help with Wazuh and OPNsense we can always count on Cloudfence Professional Services: https://cloudfence.com.br/en/contact/
GitHub Repository with files used in this article: https://github.com/cloudfence/opnsense-naxsi-decoder
