Fail2Ban filter for NinjaFirewall log files

OVERVIEW

The NinjaFirewall WP plugin is a very fast, reliable Web Application Firewall for WordPress. Fail2Ban is a daemon that scans a server’s log files once per second. If it finds evidence of an attack on the server, it can ban the IP address that the attack is coming from. This article outlines how to add a log file filter to Fail2Ban that detects critical, and high level security events written to NinjaFirewall’s log file directory so that it can ban the attacker’s IP address.

This filter differs from the NinjaFirewall Fail2Ban AUTH log filter and the NinjaFirewall Fail2Ban syslog filter articles in that it operates directly on the log data that Ninjafirewall stores in its /wp-content/nfwlog/ directory.

tl;dr version: You can get all the files you need in the fail2ban-filter-ninjafirewall-logs files Github repository.

BACKGROUND

Ninjafirewall stores firewall event data in your WordPress installation’s /wp-content/nfwlog/ directory in a series of PHP files with a naming convention of firewall_.php (e.g. firewall_20200601.php). Events in these files appear in the following form…

[1592563704] [0.01517] [mydomain.com] [#1937399] [1515] [3] [168.61.187.205] [403] [GET] [/index.php] [Unauthorized action] [hex:4745543a712305f6175746f5fab2f67203d2074727565]
  • The first variable, [1592563704] is an Epoch timestamp. Fail2Ban will recognize this without having to add it to our filter’s regular expression.
  • The second variable, [0.01517] appears to be a record of how long it took to process the event.
  • The third variable, [mydomain.com] is the web site host name.
  • The fourth variable, is Ninjafirewall’s Incident number for the event.
  • The fifth variable, [1515] is the “Rule” number that was violated.
  • The sixth variable, [3] is the security level for this event. The security levels are numbered 1 to 6 with 1 being the most serious. For example, 1=Critical, 2=High, 3=Medium, and the last being, 6=Information. The filter described below will only act on Critical and High security events.
  • The seventh variable, is the IP address of the attacker.
  • The remainder of the variables are HTTP response status code, HTTP method used, URL, rule violation description, and some hex encoded data (probably the snippet of info displayed at the end of the line in the log file viewer of the Ninjafirewall admin interface.

PROCEDURE

Log in into your web server (assuming you have Fail2Ban already installed and working) and create a new recipe file with the following command…

sudo vi /etc/fail2ban/filter.d/ninjafirewall-logs.conf

Insert the following text…

[INCLUDES]
after = common.conf

[Definition]

_daemon = ninjafirewall-logs

# Option:  failregex
# Notes:   regex to match events marked Critical and High in ninjafirewall log files.
#          fail2ban automatically detects and translates the Epoch timestamp at the
#          start of each log file line even though it is not specified in failregex.
#
#          Samples:
#          [1592563704] [0.01517] [mydomain.com] [#1937399] [1515] [3] [168.61.187.205] [403] [GET] [/index.php] [Unauthorized action] [hex:4745543a712305f6175746f5fab2f67203d2074727565]
#          [1592843376] [0.0003] [mydomain.com] [#2350962] [0] [1] [45.152.182.137] [404] [GET] [/wp-login.php] [Blocked access to the login page] [hex:62612320646574656fca374696f6e20697320656e61626c6564]
#          [1592824252] [0] [mydomain.com] [#7248950] [0] [2] [192.168.0.62] [403] [GET] [/index.php] [User enumeration scan (WP REST API)] [hex:2f2f7abe2d6a7123452f77702f76322f75736572732f]
#          [1592870815] [0] [mydomain.com] [#7392965] [0] [6] [10.0.0.207] [403] [POST] [/wp-login.php] [Logged in user] [hex:736afb61646d696e202861646d696e6973123451746f7229]
#
# Values:  TEXT
#
failregex = \[(?:[\d\.]{1,8})\] \[(?:[a-z\.\d]{5,80})\] \[\#(?:(\d){5,9})\] \[(?:(\d){1,6})\] \[[12]\] \[\] \[(?:(\d){3})\] \[(?:(POST|GET|PUT|PATCH|DELETE))\] \[

# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =

You can change what level of security event the filter will act on by changing \[[12]\] in the failregex line. If you only want to act on Critical events, change it to \[[1]\]. If you want it to act on Critical, High, and Medium events, change it to \[[123]\] in the failregex line.

Note that \[(?:[\d\.]{1,8})\] \[(?:[a-z\.\d]{5,80})\] in failregex does not do any rigorous testing of the timing and domain values. If you are worried about log file poisoning and exploits, you might want to use a better regex here, but you most likely have nothing to worry about here.

Next, enable the filter by editing or creating a jail.local file with…

sudo vi /etc/fail2ban/jail.local

and insert the following text…

[ninjafirewall-logs]
port = http,https
filter = ninjafirewall-logs
logpath = /var/www/vhosts/mydomain.com/public_html/wp-content/nfwlog/firewall_*.php
enabled = true

Keep the maxretry override value low; 3 is good, 1 is probably too low. Attacks are often distributed, with each IP address only being used once. This will create a lot of unnecessary IP bans. Heavier attacks, or smaller bot-nets, will reuse IP addresses, so a setting of 2 or 3 will block those attackers.

Finally, restart the service…

sudo service fail2ban restart

TESTING

To test the new filter run this command (replacing the example log file directory with your own)…

sudo fail2ban-regex /var/www/vhosts/mydomain.com/public_html/wp-content/nfwlog/firewall_*.php /etc/fail2ban/filter.d/ninjafirewall-logs.conf

If there are any Critical or High events in the NinjaFirewall log files, fail2ban-regex will show you the number of matches.

If there are any IP addresses that are currently banned you can see them by running this command…

sudo iptables -L

PRECAUTIONS FOR CACHING AND PROXY SERVICES

When your web server is accessed through a caching or proxy service, such as CloudFlare, the connecting IP address in an attack will be a proxy server IP address. Banning the connecting IP address could result in your web site becoming inaccessible to some or all of the internet. Simply banning the true client IP address will not help either, since that IP address most likely would never connect directly to your web site. In this case, you may not want to use this Fail2Ban filter at all.

Another possibility is to setup cloudflare action for the ninjafirewall-logs filter. See the example implementation in the CloudFlare REST API V4 Fail2Ban filter and NinjaFirewall Fail2Ban AUTH log filter articles.

DEBUGGING

If fail2ban won’t restart after you have edited configuration files, you can try manually starting it with verbose messaging enabled to find out where it is failing as it is starting up.

fail2ban-client -vvv -x start

Once you have fixed all errors in your configuration files, restart it as a service.

fail2ban-client -x stop
service fail2ban start

You can get the latest version of the Fail2Ban NinjaFirewall WP in the GitHub Repository.