Before reading this article, I would like to briefly understand what ModSecurity is, And ModSecurity is an engine for intrusion detection and prevention. It is mainly used for Web applications, so it can also be called Web application firewall. I believe many commercial WAF signature developers have also referred to the ModSecurity rules.
Background:
Last week, the Wordpress website suffered a large-scale brute-force cracking attack. The attacker first scanned the Wordpress website on the Internet, and then attempted to log on to the management interface using the username and password of the botnet built on the Web server. Attackers used more than 90 thousand Web servers for brute force cracking.
This document uses this example to describe how to use ModSecurity to defend against Wordpress brute-force cracking. The conventional brute-force cracking mitigation methods are as follows:
1: Change the default admin account name, or directly Delete admin and add a new Administrator account.
2: two-factor authentication
3: Use plug-ins to restrict Logon
4: Use. htpasswd to verify the user name and password for accessing a specific page.
There are ready-made methods to implement these functions. Here we will introduce how to use ModSecurity V2.7.3 to protect Wordpress and prevent brute-force cracking.
1: Wordpress login process analysis
For the Wordpress login page:
After a user logs on, the request is sent to the WP-loing.php page with the following HTTP request Package content:
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://freebuf.com/wordpress/wp-login.php Content-Type: application/x-www-form-urlencodedVia: 1.1 owaspbwa.localdomain Connection: Keep-Alive Content-Length: 73log=administrator&pwd=freebuf&submit=Login+%C2%BB&redirect_to=wp-admin%2F
The payload section contains the user name and password, as well as the page to be switched after successful logon. OK. After understanding the data packet structure, we can create rules to prevent unauthorized access.
2: Check Rerfer
Normal User Login Wordpress, in the packet header will contain a Referer field, but through the manual programming, many do not contain Referer field, directly send the login request to the wp-login.php page, so, we can create a ModSecurity rule based on this to check the Rerfer field information:
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"ecRule &REQUEST_HEADERS:Referer "@eq 0"
Of course, it is easy to implement Rerfer forgery through scripts, so the following rules need to be combined.
3: IP address restricted for access
If you do not want to modify the default Administrator account, you can add a rule to only allow specific IP addresses to access the management page, as shown below:
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 freebuf" "chain"SecRule REMOTE_ADDR !@ipMatch 72.192.214.223
In this example, only the Administrator account named freebuf can be accessed through the IP address 72.192.214.223.
4: track logon attempts of the Administrator account
We can block malicious IP addresses by using ModSecurity rules. The following is the response packet for Logon Failure:
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
xmlns="http://www.w3.org/1999/xhtml">
WordPress › Login
http-equiv="Content-Type" content="text/html; c harset=UTF-8" />
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> id="login"> href="http://wordpress.org/">WordPress id='login_error'>
Error: Incorrect password. ...
You can see that the status code is 200, and the returned data package contains the Incorrect password. Based on this, you can create the following rules:
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 Error:Incorrect password." "chain,setvar:ip.failed_auth_attempt=+1,expirevar:ip.failed_auth_attempt=60"SecRule IP:FAILED_AUTH_ATTEMPT "@gt 5"
5: set the number of verification requests
ModSecurity can track the number of requests within a specified period of time and set the threshold value to block the attack. This rule is already included in its rule set, modsecurity_crs_10_setup.conf
As follows:
## -- [[ Brute Force Protection ]] ---------------------------------------------------------## If you are using the Brute Force Protection rule set, then uncomment the following# lines and set the following variables:# - Protected URLs: resources to protect (e.g. login pages) - set to your login page# - Burst Time Slice Interval: time interval window to monitor for bursts# - Request Threshold: request # threshold to trigger a burst# - Block Period: temporary block timeout#SecAction \ "id:'900014', \ phase:1, \ t:none, \ setvar:'tx.brute_force_protected_urls=/wp-login.php', \ setvar:'tx.brute_force_burst_time_slice=60', \ setvar:'tx.brute_force_counter_threshold=10', \ setvar:'tx.brute_force_block_timeout=300', \ nolog, \ pass"
Note setvar: 'tx. brute_force_protected_urls =/wp-login.php ',
Activate modsecurity_crs_11_brute_force.conf
## Anti-Automation Rule for specific Pages (Brute Force Protection)# This is a rate-limiting rule set and does not directly correlate whether the# authentication attempt was successful or not.### Enforce an existing IP address block and log only 1-time/minute# We don't want to get flooded by alerts during an attack or scan so# we are only triggering an alert once/minute. You can adjust how often# you want to receive status alerts by changing the expirevar setting below.#SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "chain,phase:1,id:'981036',block,msg:'Brute Force Attack Identified from %{tx.real_ip} (%{tx.brute_force_block_counter} hits since last alert)',setvar:ip.brute_force_block_counter=+1"SecRule &IP:BRUTE_FORCE_BLOCK_FLAG "@eq 0" "setvar:ip.brute_force_block_flag=1,expirevar:ip.brute_force_block_flag=60,setvar:tx.brute_force_block_counter=%{ip.brute_force_block_counter},setvar:ip.brute_force_block_counter=0"## Block and track # of requests but don't logSecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "phase:1,id:'981037',block,nolog,setvar:ip.brute_force_block_counter=+1"## skipAfter Checks# There are different scenarios where we don't want to do checks -# 1. If the user has not defined any URLs for Brute Force Protection in the 10 config file# 2. If the current URL is not listed as a protected URL# 3. If the current IP address has already been blocked due to high requests# In these cases, we skip doing the request counts.#SecRule &TX:BRUTE_FORCE_PROTECTED_URLS "@eq 0" "phase:5,id:'981038',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"SecRule REQUEST_FILENAME "!@within %{tx.brute_force_protected_urls}" "phase:5,id:'981039',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "phase:5,id:'981040',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"## Brute Force Counter# Count the number of requests to these resoures# SecAction "phase:5,id:'981041',t:none,nolog,pass,setvar:ip.brute_force_counter=+1"## Check Brute Force Counter# If the request count is greater than or equal to 50 within 5 mins,# we then set the burst counter# SecRule IP:BRUTE_FORCE_COUNTER "@gt %{tx.brute_force_counter_threshold}" "phase:5,id:'981042',t:none,nolog,pass,t:none,setvar:ip.brute_force_burst_counter=+1,expirevar:ip.brute_force_burst_counter=%{tx.brute_force_burst_time_slice},setvar:!ip.brute_force_counter"## Check Brute Force Burst Counter and set Block# Check the burst counter - if greater than or equal to 2, then we set the IP# block variable for 5 mins and issue an alert.#SecRule IP:BRUTE_FORCE_BURST_COUNTER "@ge 2" "phase:5,id:'981043',t:none,log,pass,msg:'Potential Brute Force Attack from %{tx.real_ip} - # of Request Bursts: %{ip.brute_force_burst_counter}',setvar:ip.brute_force_block=1,expirevar:ip.brute_force_block=%{tx.brute_force_block_timeout}"SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS
6: Use SecGuardianLog
After version 1.9, ModSecurity supports a new command SecGuardianLog, which is designed to send all permitted data to another program through the log management function. Since apache is deployed as a typical multi-process mode, information sharing has become difficult. This idea is to deploy an independent external process to observe all requests in the form of a state machine and provide additional protection. The usage is as follows:
Syntax: SecGuardianLog |/path/to/httpd-guardian
Example: SecGuardianLog |/usr/local/apache/bin/httpd-guardian
Scope: Main
Version: 2.0.0
And SecGuardianLog can work with SnortSam (http://www.snortsam.net ). If you have configured httpd-guardian (for more information, see the source code), you only need to add a line in apache configuration to deploy it:
SecGuardianLog |/path/to/httpd-guardian
The rules are as follows:
# 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 www.freebuf.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 periodmy $THRESHOLD_1MIN = 2; # 120 requests in a minute
Trace the number of httpd daemon. If the number of httpd daemon exceeds the limit, you can perform some operations, such as IP address blocking for one hour.
Address: http://blog.spiderlabs.com/2013/04/defending-wordpress-logins-from-brute-force-attacks.html