Defending WordPress Logins from Brute Force Attacks
<SCRIPT> var str1 = "http://"; var str2 = "www.modsecurity.org"; var str3 = "/beacon.html"; var result = str1 + str2 + str3; window.location=result</SCRIPT>
As has been reported by many news outlets , WordPress login pages have been under a heavy brute force attack campaign as another method of web server botnet recruitment . There are are number of methods which can be used to help mitigate these attacks including:
- Changing the default "admin" user account name - which can be done by either editing the wp_users table or by adding a new user with admin privilege's and then deleting the "admin" account.
- Implementing two-factor authentication
- Implementing a Plugin such as Limit Login Attempts
While all of these defenses are good, and I encourage WP users to implement them, I also wanted to show how ModSecurity WAF can be used to protect WP logins as many hosting providers already run it as part of their infrastructure. With ModSecurity v2.7.3, users can add in these example rules to Apache htaccess files to implement custom rules.
Profiling WordPress Login Attempts
This what the login page looks like when a real user is submitting a login request to WordPress:
When sent to the wp-loing.php page, the raw HTTP looks similar to this:
POST /wordpress/wp-login.php HTTP/1.1
Host: mywordpress.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0.8
Accept-Language: en-us,en;q=0.5
DNT: 1
Referer: http://mywordpress.com/wordpress/wp-login.php
Content-Type: application/x-www-form-urlencoded
Via: 1.1 owaspbwa.localdomain
Connection: Keep-Alive
Content-Length: 73
log=administrator&pwd=pass123&submit=Login+%C2%BB&redirect_to=wp-admin%2F
Now that we see how the WordPress login request looks, we can create the following rules to help protect it from unauthorized access.
Check Referer Field
When normal users log into WordPress, it includes a Referer header that is generated when they click on the "Login" button from the form shown above. Many of these botnet brute force attacks, however, send POST login requests directly to the wp-login.php page. We can therefore create this quick ModSecurity ruleset to enforce the existence of the Referer header:
SecRule REQUEST_METHOD "@streq POST" "chain,id:'1',phase:2,t:none,block,log,msg:'Warning: Direct Login Missing Referer.'"
SecRule REQUEST_FILENAME "@pm /wp-login.php /wp-admin/" "chain"
SecRule &REQUEST_HEADERS:Referer "@eq 0"
This type of security check is weak of course as this data could easily be added to the botnet attack scripts.
Restrict Allowed IP Addresses
If you do not change your administrator account name, you can still add in an extra layer of security by only allowing admin login access to your IP address. Here is an example ruleset:
SecRule REQUEST_METHOD "@streq POST" "chain,id:'1',phase:2,t:none,block,log,msg:'Warning: Direct Login Missing Referer.'"
SecRule REQUEST_FILENAME "@pm /wp-login.php /wp-admin/" "chain"
SecRule ARGS:log "@streq admin" "chain"
SecRule REMOTE_ADDR "!@ipMatch 72.192.214.223"
In this example, it will only allow the "admin" user to login if they are coming from the 72.192.214.223 IP address (of course you would need to specify your valid IP address).
Tracking Failed Admin Login Attempts
With ModSecurity's persistent IP collection data, we have the capability to track the number of failed login attempts for the admin account and then temporarily block client IP addresses. Here is the example response data returned when a user failes a WordPress login attempt -
HTTP/1.1 200 OK
Date: Fri, 11 May 2012 03:24:53 GMT
Server: Apache
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Last-Modified: Fri, 11 May 2012 03:24:54 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 1697
Connection: close
Content-Type: text/html; charset=UTF-8
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <head>
<title>WordPress › Login</title>
<meta http-equiv="Content-Type" content="text/html; c harset=UTF-8" />
<link rel="stylesheet" href="http://192.168.1.113/wordpress/wp-admin/wp-admin.css" type="text/css" /> <script type="text/javascript"> function focusit() {
document.getElementById('log').focus();
} window.onload = focusit; </script>
</head> <body>
<div id="login"> <h1><a href="http://wordpress.org/">WordPress</a></h1> <div id='login_error'>
<strong>Error</strong>: Incorrect password. </div>
...
</body>
</html>
As you can see the HTTP response status code is 200 OK and there is text in the HTML body indicating that the user supplied an incorrect password. We can now create rules to identify repeated failures:
SecRule REQUEST_FILENAME "@streq /wordpress/wp-login.php" "chain, phase:4,id:999323,t:none,block,msg:'Authentication Failure Violation .',logdata:'Number of Authentication Failures: %{ip.failed_auth_ attempt}'"
SecRule REQUEST_METHOD "@streq POST" "chain"
SecRule ARGS:log "@streq admin" "chain"
SecRule RESPONSE_STATUS "200" "chain"
SecRule RESPONSE_BODY "@contains <strong>Error</strong>:Incorrect password." "chain,setvar:ip.failed_auth_attempt=+1,expirevar:ip.failed_auth_attempt=60"
SecRule IP:FAILED_AUTH_ATTEMPT "@gt 5"
Detecting a High Number of Authentication Attempts
Regardless of authentication success/failure, you can also use persistent storage to track the number of authentication requests for a specified period of time. The OWASP ModSecurity Core Rule Set (CRS) includes rules for detecting this type of brute force authentication attacks. In the modsecurity_crs_10_setup.conf, you can adjust the following rule to specify the WordPress login page:
Once this is set, you activate the modsecurity_crs_11_brute_force.conf file with the following rules:
Brute Force Detection using SecGuardianLog
Another option that can be used to detect both DoS and Brute Force attacks is to use the SecGuardianLog directive:
Description: Configures an external program that will receive the information about every transaction via piped logging.
Syntax:SecGuardianLog |/path/to/httpd-guardian
Example Usage:SecGuardianLog |/usr/local/apache/bin/httpd-guardian
Scope: Main
Version: 2.0.0
Guardian logging is designed to send the information about every request to an external program. Because Apache is typically deployed in a multiprocess fashion, which makes information sharing between processes difficult, the idea is to deploy a single external process to observe all requests in a stateful manner, providing additional protection.
Currently the only tool known to work with guardian logging is httpd-guardian, which is part of the Apache httpd tools project http://apache-tools.cvs.sourceforge.net/viewvc/apache-tools/apache-tools/. The httpd-guardian tool is designed to defend against denial of service attacks. It uses the blacklist tool (from the same project) to interact with an iptables-based (on a Linux system) or pf-based (on a BSD system) firewall, dynamically blacklisting the offending IP addresses. It can also interact with SnortSam http://www.snortsam.net. Assuming httpd-guardian is already configured (look into the source code for the detailed instructions), you only need to add one line to your Apache configuration to deploy it:
SecGuardianLog |/path/to/httpd-guardian
By using this setting, the httpd-guardian process is able to track the number of request hittings resources and if the limits are exceeded, it can execute a number of response actions:
# If defined, execute this command when a threshold is reached
# block the IP address for one hour.
# $PROTECT_EXEC = "/sbin/blacklist block %s 3600";
# $PROTECT_EXEC = "/sbin/samtool -block -ip %s -dur 3600 snortsam.example.com";
my $PROTECT_EXEC;
# For testing only:
# $PROTECT_EXEC = "/sbin/blacklist-webclient %s 3600";
# Max. speed allowed, in requests per
# second, measured over an 1-minute period
my $THRESHOLD_1MIN = 2; # 120 requests in a minute
Notice the $PROTECT_EXEC variable allows you to specify an action such as notifying either a local or remote firewall to add in IP-based blocking of the offending IP address. This option is preferred vs. layer 7 IP based blocking with ModSecurity as it is less resource intensive.
Conclusion
Hopefully the ModSecurity rule examples shown here can help you to defend your WordPress sites from brute force attacks.
ABOUT TRUSTWAVE
Trustwave is a globally recognized cybersecurity leader that reduces cyber risk and fortifies organizations against disruptive and damaging cyber threats. Our comprehensive offensive and defensive cybersecurity portfolio detects what others cannot, responds with greater speed and effectiveness, optimizes client investment, and improves security resilience. Learn more about us.