├── opnsense_naxsi_waf_event.yaml
├── opnsense_naxsi_logs.yaml
└── README.md
/opnsense_naxsi_waf_event.yaml:
--------------------------------------------------------------------------------
1 | type: trigger
2 | name: ls111/opnsense_naxsi_waf_event
3 | description: "Detects if NAXSI has triggered a security event in accordance with its WAF policies"
4 | filter: evt.Meta.log_type == 'waf_attack_event'
5 | groupby: evt.Meta.source_ip
6 | labels:
7 | service: naxsi
8 | type: waf_security_event
9 | remediation: true
10 | scope:
11 | type: Ip
12 | expression: evt.Meta.source_ip
13 |
--------------------------------------------------------------------------------
/opnsense_naxsi_logs.yaml:
--------------------------------------------------------------------------------
1 | name: ls111/opnsense_naxsi_logs
2 | description: "Parse NAXSI error logs on OPNSense firewall"
3 | filter: "evt.Parsed.program == 'naxsi'"
4 | onsuccess: next_stage
5 | nodes:
6 | - grok:
7 | pattern: '%{DATESTAMP:timestamp} \[error] %{NUMBER}\#%{NUMBER}: \*%{NUMBER} NAXSI_FMT: ip=%{IPORHOST}&server=%{IPORHOST:serverip}&uri=%{URIPATHPARAM:server_uri}&vers=%{NUMBER}&total_processed=%{NUMBER}&total_blocked=%{NUMBER}&config=block&cscore0=%{DATA}&score0=%{NUMBER:score}&zone0=%{DATA}&id0=%{NUMBER:rule_id}&var_name0=%{DATA}&zone1=%{DATA}&id1=%{NUMBER}&var_name1=%{DATA}, client: %{IPORHOST:source_ip}, server: %{IPORHOST:server_hostname}, request: "%{DATA:request}", host: %{DATA}, referrer: "%{DATA:referrer}"'
8 | apply_on: message
9 | statics:
10 | - meta: log_type
11 | value: waf_attack_event
12 | - target: evt.StrTime
13 | expression: evt.Parsed.timestamp
14 | - meta: source_ip
15 | expression: evt.Parsed.source_ip
16 | - meta: http_request
17 | expression: evt.Parsed.request
18 | - meta: service
19 | value: naxsi
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OPNSense + CrowdSec + NAXSI WAF Integration
2 | Parsers and scenarios to allow CrowdSec to ban threat actors caught by NAXSI WAF on a OPNSense firewall deployment.
3 | ________
4 |
5 | **Step 1:** Setup NAXSI WAF on your OPNSense firewall, you can follow this video for guidance:
6 | [OPNSense - Web Application Firewall (WAF) configuration using NAXSI](https://www.youtube.com/watch?v=IYDoQmUVdvU)
7 |
8 | **Step 2:** Install the CrowdSec plugin on your OPNSense firewall (I will be releasing a video about this and subsequent steps soon)
9 |
10 | **Step 3:** SSH into your OPNSense firewall head over to the following directory:
11 |
12 | ```cd /usr/local/etc/crowdsec```
13 |
14 | **Step 4:** Edit and prepend the following to the top of your acquis.yaml (log acquisition) file:
15 |
16 | ```
17 | filenames:
18 | #note: this below will need to point to your web app error log file.
19 | - /var/log/nginx/www.dvwa.local.error.log
20 | labels:
21 | type: naxsi
22 | ---
23 | ```
24 | **Step 5:** Go to ```cd /usr/local/etc/crowdsec/parsers/s01-parse``` this is where we are going to create the custom parser .yaml file that parses through the NAXSI log file we included above, and matches the Grok pattern in the log. This will save you the efforts of doing this somewhat tedious task yourself.
25 |
26 | ```
27 | name: ls111/opnsense_naxsi_logs
28 | description: "Parse NAXSI error logs on OPNSense firewall"
29 | filter: "evt.Parsed.program == 'naxsi'"
30 | onsuccess: next_stage
31 | nodes:
32 | - grok:
33 | pattern: '%{DATESTAMP:timestamp} \[error] %{NUMBER}\#%{NUMBER}: \*%{NUMBER} NAXSI_FMT: ip=%{IPORHOST}&server=%{IPORHOST:serverip}&uri=%{URIPATHPARAM:server_uri}&vers=%{NUMBER}&total_processed=%{NUMBER}&total_blocked=%{NUMBER}&config=block&cscore0=%{DATA}&score0=%{NUMBER:score}&zone0=%{DATA}&id0=%{NUMBER:rule_id}&var_name0=%{DATA}&zone1=%{DATA}&id1=%{NUMBER}&var_name1=%{DATA}, client: %{IPORHOST:source_ip}, server: %{IPORHOST:server_hostname}, request: "%{DATA:request}", host: %{DATA}, referrer: "%{DATA:referrer}"'
34 | apply_on: message
35 | statics:
36 | - meta: log_type
37 | value: waf_attack_event
38 | - target: evt.StrTime
39 | expression: evt.Parsed.timestamp
40 | - meta: source_ip
41 | expression: evt.Parsed.source_ip
42 | - meta: http_request
43 | expression: evt.Parsed.request
44 | - meta: service
45 | value: naxsi
46 | ```
47 |
48 | **Step 6:** We now have to create the scenario .yaml file in ```cd /usr/local/etc/crowdsec/scenarios``` which takes the parsed log info and determines how CrowdSec should deal with it, in this case we are going to remediate the event by passing the source_ip (attacker ip) over to the firewall bouncer, which will then action the ban.
49 | ```
50 | type: trigger
51 | name: ls111/opnsense_naxsi_waf_event
52 | description: "Detects if NAXSI has triggered a security event in accordance with its WAF policies"
53 | filter: evt.Meta.log_type == 'waf_attack_event'
54 | groupby: evt.Meta.source_ip
55 | labels:
56 | service: naxsi
57 | type: waf_security_event
58 | remediation: true
59 | scope:
60 | type: Ip
61 | expression: evt.Meta.source_ip
62 | ```
63 |
64 | **Step 7:** We are now going to edit our profile.yaml file ```/usr/local/etc/crowdsec/profile.yaml``` and change the ban duration to 5 min for lab purposes so that you dont accidently lock yourself out for extended periods, the default for a production environment is 4 hours, but this can be anything you like. The profile controls how we should remediate an attack event and passes the source_ip over to the bouncer which creates the deny rules in PF which is the default firewall OPNSense/BSD uses
65 |
66 | ```
67 | name: default_ip_remediation
68 | #debug: true
69 | filters:
70 | - Alert.Remediation == true && Alert.GetScope() == "Ip"
71 | decisions:
72 | - type: ban
73 | duration: 5m #duration of the ban set to 5 min, default is 4 hours, changed this for lab purposes.
74 | #duration_expr: Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 4)
75 | # notifications:
76 | # - slack_default # Set the webhook in /usr/local/etc/crowdsec/notifications>
77 | # - splunk_default # Set the splunk url and token in /usr/local/etc/crowdsec/>
78 | # - http_default # Set the required http parameters in /usr/local/etc/crowd>
79 | # - email_default # Set the required email parameters in /usr/local/etc/crow>
80 | on_success: break
81 | ```
82 |
83 | **Step 8:** You need to restart the CrowdSec service: ```service crowdsec restart``` so that all the changes can take effect.
84 |
85 | If you attempt to simulate an injection attack against your web app, you will note that NAXSI intercepts this as well as bans the attacker IP address for the duration you specified making the WAF solution more complete.
86 |
87 | While OPNSense allows you to install the CrowdSec plugin using the GUI, you can only make partial changes to it using the GUI hence why we need to do everything in shell. CrowdSec comes with its own built in command line tool, access it by typing ```cscli -h``` and you will have full control over your CrowdSec deployment.
88 |
89 | ```
90 | cscli is the main command to interact with your crowdsec service, scenarios & db.
91 | It is meant to allow you to manage bans, parsers/scenarios/etc, api and generally manage you crowdsec setup.
92 |
93 | Usage:
94 | cscli [command]
95 |
96 | Available Commands:
97 | alerts Manage alerts
98 | bouncers Manage bouncers [requires local API]
99 | capi Manage interaction with Central API (CAPI)
100 | collections Manage collections from hub
101 | completion Generate completion script
102 | config Allows to view current config
103 | console Manage interaction with Crowdsec console (https://app.crowdsec.net)
104 | dashboard Manage your metabase dashboard container [requires local API]
105 | decisions Manage decisions
106 | explain Explain log pipeline
107 | help Help about any command
108 | hub Manage Hub
109 | hubtest Run functional tests on hub configurations
110 | lapi Manage interaction with Local API (LAPI)
111 | machines Manage local API machines [requires local API]
112 | metrics Display crowdsec prometheus metrics.
113 | notifications Helper for notification plugin configuration
114 | parsers Install/Remove/Upgrade/Inspect parser(s) from hub
115 | postoverflows Install/Remove/Upgrade/Inspect postoverflow(s) from hub
116 | scenarios Install/Remove/Upgrade/Inspect scenario(s) from hub
117 | simulation Manage simulation status of scenarios
118 | version Display version and exit.
119 |
120 | Flags:
121 | -c, --config string path to crowdsec config file (default "/usr/local/etc/crowdsec/config.yaml")
122 | -o, --output string Output format : human, json, raw.
123 | --debug Set logging to debug.
124 | --info Set logging to info.
125 | --warning Set logging to warning.
126 | --error Set logging to error.
127 | --trace Set logging to trace.
128 | -h, --help help for cscli
129 | ```
130 |
--------------------------------------------------------------------------------