I have written about the excellent and lightweight (unlike fail2ban which is more popular but too resource consuming and 3rd party tools dependent) tool BFD earlier. This tool is actually the set of bash scripts that looks for known pattern in the logs and executes actions against offending IPs based on the configuration. Little is known that it’s also modular and allows to extend it’s behavior by writing custom rules to assist with more uncommon situations.
I’ve also written about widespread WordPress brute force attacks that targets wp-logon.php script. The solution I’ve offered there takes care of single WordPress site. It’s getting more difficult to mitigate the attack in case you have multiple servers with multiple WordPress sites. So I decided to come up with more general approach.
I’ve created separate rule script to detect ‘POST /wp-login.php’ requests via Apache server-status page and pass the list of IP addresses to BFD to process.
You will have to enable server-status related parts of apache configuration.
- Make sure that ExtendedStatus line in httpd.conf is set to “on” and uncommented
12345# ExtendedStatus controls whether Apache will generate "full" status# information (ExtendedStatus On) or just basic information (ExtendedStatus# Off) when the "server-status" handler is called. The default is Off.#ExtendedStatus On
- Look for “server-status” location and configure it as follows:
12345678910# Allow server status reports generated by mod_status,# with the URL of http://servername/server-status# Change the ".example.com" to match your domain to enable.#<Location /server-status>SetHandler server-statusOrder deny,allowDeny from allAllow from 127.0.0.1</Location>
- Save modified httpd.conf, check for the syntax validity with “apachectl configtest” command and if everything checked out restart with “apachectl restart” command
- Now we need to extract the information out of status page – with this task I went the least waste of energy way – I tried Lynx text browser in “dump” mode – didn’t like the output, tested Elinks since it the default text mode web browser in CentOS, found output of “dump mode” to my satisfaction and used it to create my BFD rule script
- Below is the first working version of apache wordpress protection rule
1234567891011121314# failed logins from a single address before ban# uncomment to override conf.bfd trig valueTRIG="5"# file must exist for rule to be activeREQ="/usr/bin/links"if [ -f "$REQ" ]; then## cpanel server status URL# ARG_VAL=`elinks -dump http://localhost/whm-server-status | grep 'POST /wp-login.php' | awk '{print $11}'| sort -n `## regular server status URLARG_VAL=`elinks -dump http://localhost/server-status | grep 'POST /wp-login.php' | awk '{print $11}'| sort -n `fi
There are 2 possible ARG_VAL lines – in case you have cPanel server you will have to use the one with whm-server-status. Just save this into ap_wp file and copy it into /usr/local/bfd/rules directory. BFD will take care of the rest. - Next time you will run bfd -a from command line to see the attack statistics you will see IPs with the comment “ap_wp” which means that BFD takes care of IPs attacking WordPress sites. If you will still experience the attacks try to run ARG_VAL command manually and look for output. You may want to reduce TRG variable value down to 1 or 2. Don’t forget to configure your white list IPs in BFD
0 Comments.