wp-login.php and mod security

quizknows

Well-Known Member
Oct 20, 2009
1,008
87
78
cPanel Access Level
DataCenter Provider
I've attempted adding these to the file:
/usr/local/apache/conf/modsec2.user.conf however I am not seeing any effect. I have some earlier logs from mod_security from earlier this morning, however there is an ongoing bruteforce attack going, and adding this rule has had no effect. I have restarted the webserver (running Litespeed). I have confirmed the there is a huge number of login attempts on the same site from the same IP address.

The rules show up (although not as one but several) in the ModSecurity Tools rules list. I use CSF and cpHulk is disabled.

Any idea why this is not working as intended?
It is possible/probable the attackers are using a referring URL. If you can post some of the domlogs (you can remove identifying domains or IPs) I can take a look. Logins with no referrer should be blocked by the first rule, the 2nd rule will only work if certain IPs are hitting the server repeatedly.

It's also worth noting that litespeed has its own engine for processing modsecurity rules which is not always 100% functional. Unfortunately, the documentation on litespeed's implementation of ModSecurity is non-existent last I checked.
 

JacobHansen

Member
Mar 20, 2013
13
0
1
cPanel Access Level
Root Administrator
It is possible/probable the attackers are using a referring URL. If you can post some of the domlogs (you can remove identifying domains or IPs) I can take a look. Logins with no referrer should be blocked by the first rule, the 2nd rule will only work if certain IPs are hitting the server repeatedly.

It's also worth noting that litespeed has its own engine for processing modsecurity rules which is not always 100% functional. Unfortunately, the documentation on litespeed's implementation of ModSecurity is non-existent last I checked.
I did not note which sites were being attacked at the time, and the attack seem to have stopped now. So I do not really have the logs. However I stopped it by blocking a few IPs that were repeatedly hitting the server. After blocking these 2-3 IPs in CSF the load of the server dropped from 2.5 to 0.5.

I thought the point of the modsecurity rule quoted in my original thread was the block IPs that repeatedly failed to login, so it should work well in this case.

Update: I think it may have been a Litespeed issue (updated now), or possibly a conflicting mod_security rule on the server i Originally tried it on.

It works correctly on two other servers I have deployed it to at least. Thanks for the help and posting the rule in the first place, it seems to work well!
 
Last edited:

quizknows

Well-Known Member
Oct 20, 2009
1,008
87
78
cPanel Access Level
DataCenter Provider
Yes, one of the rules is there for blocking repeat logins from one IP. The code I provided had that in addition to another rule that drops invalid logins (ones that lack referring URLs), so I was talking about that one too.

Glad they're helping :)
 

rregister

Member
Aug 10, 2015
12
0
1
Texas
cPanel Access Level
Root Administrator
I'm having a bit of trouble with this and would appreciate any help you have to offer, though I'm using apache 2.4 and not litespeed. My understanding is that it should work the same...apologies if that is incorrect.

Here's what I'm using currently. The first rule, which blocks logins with no referer, works perfectly and I can find it in the apache error_log file. The problem is that the other rule to limit login attempts never seems to process. I've tested it using another IP address that is not whitelisted in CSF (my main IP is) and nothing ever happens. The third rule just does the same thing and is based on the second rule, but applies to xmlrpc.php instead of wp-login.php

Code:
SecUploadDir /tmp
SecTmpDir /tmp
SecDataDir /tmp
SecRequestBodyAccess On

#Block WP logins with no referring URL
<Locationmatch "/wp-login.php">
SecRule REQUEST_METHOD "POST"  "deny,status:401,id:5000130,chain,msg:'wp-login request blocked, no referer'"
SecRule &HTTP_REFERER "@eq 0"
</Locationmatch>

#Wordpress Brute Force detection
SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR},id:5000134
<Locationmatch "/wp-login.php">
SecRule user:bf_block "@gt 0" "deny,status:401,log,id:5000135,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
SecRule ip:bf_counter "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"
</Locationmatch>

#XMLRPC Protection
SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR},id:5000234
<Locationmatch "/xmlrpc.php">
SecRule user:bf_block "@gt 0" "deny,status:401,log,id:5000235,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000237"
SecRule ip:bf_counter "@gt 5" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"
</Locationmatch>
thank you for your time!
 

quizknows

Well-Known Member
Oct 20, 2009
1,008
87
78
cPanel Access Level
DataCenter Provider
3 things:

You should only need to initialize the collection once (initcol). Try commenting out the 2nd instance of
SecAction phase:1,nolog,pass,initcol{snip}, restart apache, and see if that helps.

Otherwise (this is just guessing) the 2 rules using both user and ip may conflict a bit. I'd have to check the rule logic on the xmlrpc one. If it doesn't work right after the first advice above, try commenting out the whole xmlrpc block of code and making sure that at least the wp-login stuff works.

Last but not least your wp-login block of code is using 2 collections (ip and user) and actually only needs one (ip). Check the revised version I posted on the last page.
 

rregister

Member
Aug 10, 2015
12
0
1
Texas
cPanel Access Level
Root Administrator
3 things:

You should only need to initialize the collection once (initcol). Try commenting out the 2nd instance of
SecAction phase:1,nolog,pass,initcol{snip}, restart apache, and see if that helps.

Otherwise (this is just guessing) the 2 rules using both user and ip may conflict a bit. I'd have to check the rule logic on the xmlrpc one. If it doesn't work right after the first advice above, try commenting out the whole xmlrpc block of code and making sure that at least the wp-login stuff works.

Last but not least your wp-login block of code is using 2 collections (ip and user) and actually only needs one (ip). Check the revised version I posted on the last page.
thank you for your suggestions! I've updated my code as follows (and saw your advice on the xmlrpc on the previous page). I still can't get it to lock me out after 10 attempts though. The other 2 blocks are working perfectly. This particular server is using mod_ruid2...could that be a problem? Thanks again.

Code:
#Block WP logins with no referring URL
<Locationmatch "/wp-login.php">
SecRule REQUEST_METHOD "POST"  "deny,status:401,id:5000130,chain,msg:'wp-login request blocked, no referer'"
SecRule &HTTP_REFERER "@eq 0"
</Locationmatch>

#Block XMLRPC no referring URL
SecRule REQUEST_METHOD "POST"  "deny,status:401,id:4784627,chain,msg:'xmlrpc request blocked, no referer'"
SecRule &HTTP_REFERER "@eq 0" "chain"
SecRule REQUEST_URI "xmlrpc.php"

#Wordpress Brute Force detection
SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},id:5000134
<Locationmatch "/wp-login.php">
# Setup brute force detection.
# React if block flag has been set.
SecRule ip:bf_block "@gt 0" "deny,status:401,log,id:5000135,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
# Setup Tracking.  On a successful login, a 302 redirect is performed, a 200 indicates login failed.
SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
SecRule ip:bf_counter "@gt 10" "t:none,setvar:ip.bf_block=1,expirevar:ip.bf_block=300,setvar:ip.bf_counter=0"
</locationmatch>
 

quizknows

Well-Known Member
Oct 20, 2009
1,008
87
78
cPanel Access Level
DataCenter Provider
Without access to the server itself to check logs and use debug settings it would be hard for me to fix that. Humor me though... in the site's .htaccess, add this line:

ErrorDocument 401 default

This should bypass custom 404 handling for 401 responses which can sometimes interfere with this. Also check for the existence of files called ip.dir and ip.pag in these locations (they should be in one of them and recently modified):

/tmp/
/var/cpanel/secdatadir/
 

rregister

Member
Aug 10, 2015
12
0
1
Texas
cPanel Access Level
Root Administrator
Without access to the server itself to check logs and use debug settings it would be hard for me to fix that. Humor me though... in the site's .htaccess, add this line:

ErrorDocument 401 default

This should bypass custom 404 handling for 401 responses which can sometimes interfere with this. Also check for the existence of files called ip.dir and ip.pag in these locations (they should be in one of them and recently modified):

/tmp/
/var/cpanel/secdatadir/
I did find both files /var/cpanel/secdatadir/. only ip.pag timestamp indicates that it was edited today. ip.dir was last edited several days ago. It's still not blocking, but I'm going to try the same code on another vps.

thanks for all the help regardless - just blocking the attempts without a referer will go a long way
 

rregister

Member
Aug 10, 2015
12
0
1
Texas
cPanel Access Level
Root Administrator
Just an update - I still can't get the blocking to work on repeated failed login attempts (with referer). I've now tried it on VPS servers with 3 different hosting companies, all of which are using apache 2.4 with modsecurity 2.9.
 

quizknows

Well-Known Member
Oct 20, 2009
1,008
87
78
cPanel Access Level
DataCenter Provider
That's odd. I'm using the same apache and modsecurity versions and the rule is still working fine.

Are you adding the rules yourself to modsec2.user.conf and restarting apache after? Are you adding them over a terminal or via WHM?
 

rregister

Member
Aug 10, 2015
12
0
1
Texas
cPanel Access Level
Root Administrator
That's odd. I'm using the same apache and modsecurity versions and the rule is still working fine.

Are you adding the rules yourself to modsec2.user.conf and restarting apache after? Are you adding them over a terminal or via WHM?
I was initially doing it via WHM, but have since tried it via terminal with the same result. The only thing I can possibly think of is that I'm using ruid2, but I thought those issues were resolved a long time ago... I'm using exactly the rules I posted above, with the only addition being

Code:
Include /usr/local/apache/conf/modsec2.whitelist.conf

SecUploadDir /tmp
SecTmpDir /tmp
SecDataDir /tmp
SecRequestBodyAccess On
 

quizknows

Well-Known Member
Oct 20, 2009
1,008
87
78
cPanel Access Level
DataCenter Provider
Can you humor me and check the ownership of the ip.dir and ip.pag files? That could help indicate if RUID2 is causing an issue. Also have you tried tailing the apache error log while you attempt to get blocked?
 

rregister

Member
Aug 10, 2015
12
0
1
Texas
cPanel Access Level
Root Administrator
Can you humor me and check the ownership of the ip.dir and ip.pag files? That could help indicate if RUID2 is causing an issue. Also have you tried tailing the apache error log while you attempt to get blocked?
On the main server I've been testing this on (as well as the other 3 like it from the same provider) it's showing the owner and group as 'nobody' with 640 permissions. On a set of VPS servers from another hosting company that I also tried this on, I'm not seeing any ip.dir and ip.pg files at all. The secdatadir directory appears to be empty. o_O I've been monitoring the apache error log pretty closely but it logs nothing using that rule ID.
 

GrandAdmiral

Active Member
May 21, 2014
28
0
51
cPanel Access Level
Root Administrator
RUID2 and bruteforce rules (using the ip.dir and ip.pag) files is notoriously unreliable due to ownership conflicts. Apparently the most reliable way you can get around this is by using CageFS and a per-user virtual mount point containing the ip.dir and ip.pag files although I have not tried it myself.

For a fully supported high-performance solution I recommend trying FCGI as your PHP handler. The configuration is not as scary as you'd think and I ended up spending far less time on it than I ever did trying to fix the RUID2 conflict.
 

WorkinOnIt

Well-Known Member
Aug 3, 2016
312
54
78
UK
cPanel Access Level
Root Administrator
Referring to this thread, wp-login.php and mod security

And using the mod sec rules suggested by the very helpful @quizknows

I have a similar issue to @rregister - all rules work fine - but not the brute force detection.

Just wondering if you managed to solve this ?

Here are my rules in modsec/modsec2.user.conf
- using EA4 / CENTOS 6.9 x86_64 cPanel & WHM build 64

Code:
SecUploadDir /tmp
SecTmpDir /tmp
SecDataDir /tmp
SecRequestBodyAccess On

#Block WP logins with no referring URL
<Locationmatch "/wp-login.php">
SecRule REQUEST_METHOD "POST"  "deny,status:401,id:5000130,chain,msg:'wp-login request blocked, no referer'"
SecRule &HTTP_REFERER "@eq 0"
</Locationmatch>

#Wordpress Brute Force detection
SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},id:5000134
<Locationmatch "/wp-login.php">
# Setup brute force detection.
# React if block flag has been set.
SecRule ip:bf_block "@gt 0" "deny,status:401,log,id:5000135,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
# Setup Tracking.  On a successful login, a 302 redirect is performed, a 200 indicates login failed.
SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
SecRule ip:bf_counter "@gt 10" "t:none,setvar:ip.bf_block=1,expirevar:ip.bf_block=900,setvar:ip.bf_counter=0"
</locationmatch>
#900 = block for 15 minutes

# check bots by user agent and match to included file
# block bad bots
SecRule REQUEST_HEADERS:User-Agent "@pmFromFile /etc/apache2/conf.d/blackbots.txt" "id:980001,rev:1,severity:2,log,msg:'Bot Rule: Black Bot detected.'"

#XMLRPC block
SecRule REQUEST_LINE "POST .*xmlrpc.*" "pass,initcol:ip=%{REMOTE_ADDR},setvar:ip.maxlimit=+1,deprecatevar:ip.maxlimit=1/600,nolog,id:350201"
SecRule IP:MAXLIMIT "@gt 10" "log,deny,id:350202,msg:'wp-xmlrpc: denying %{REMOTE_ADDR} (%{ip.maxlimit} connection attempts)'"
Thanks for any advice!
 

joaosavioli

Well-Known Member
Feb 7, 2008
70
12
58
Hi,

I´m having a lot of attack in wp-login.php file of many site.
I have this protection in modsecurity WordPress ModSecurity Rules | Liquid Web Knowledge Base, but ins´t working because the attack is too large.

Is it possible to block in all server (httpd.conf) access on wp-login.php? I´ve tryed this, but didn´t work.
<Files wp-login.php>
Order allow, deny
Deny from all
</Files>

Do you have any other sugestion to help me?

Thank you!

Cheers,
Joao
 

joaosavioli

Well-Known Member
Feb 7, 2008
70
12
58
Hi,

I'm trying include some instructions in .htaccess, but iy works only without wordpress rules.
it works:
cat .htaccess
RewriteEngine On

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_USER_AGENT} ^(python|catexplorador) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule ^.* - [F,L]


it doesn't work:
cat .htaccess
RewriteEngine On

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_USER_AGENT} ^(python|catexplorador) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule ^.* - [F,L]

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress


Could you help me?

Cheers,
Joao
 

joaosavioli

Well-Known Member
Feb 7, 2008
70
12
58
Hello @akust0m, thank you for replying.

You created a very good way to fix it, but it doesn't work for me, because the attack was too large (more than 1000 ips).

I've fixed it with a global .htaccess file, blocking python requests:
[root@serv ]# cat /home/.htaccess
Options All -Indexes
RewriteEngine on

SetEnvIfNoCase user-agent bot\[.+\]|.*mj12bot.*|.*baiduspider.*|.*python-requests*. bad_bot=1
Order Allow,Deny
Allow from all
Deny from env=bad_bot
[root@serv ]# ls -la /home/.htaccess
-rw-r--r--. 1 root root 187 Mar 27 11:46 /home/.htaccess

Cheers!
Joao
 

joaosavioli

Well-Known Member
Feb 7, 2008
70
12
58
Hi!

I've fixed it with a global (users layer) .htaccess file, blocking python requests:
[root@serv ]# cat /home/users/.htaccess
Options All -Indexes
RewriteEngine on

SetEnvIfNoCase user-agent bot\[.+\]|.*mj12bot.*|.*baiduspider.*|.*python-requests*. bad_bot=1
Order Allow,Deny
Allow from all
Deny from env=bad_bot

Cheers!
Joao