ModSecurity not working?

Damlhen

Member
Sep 18, 2017
5
0
1
Bhutan
cPanel Access Level
Root Administrator
I have been using a custom rule to block Wordpress wp-login.php bruteforce attacks, but recently it has stopped working and the server load is going through the roof. As per my rules hit list page from WHM, the last block was on June 7, 2019 (just after midnight).

I have been using this same configuration for the last 2 years and haven't made any changes to the server recently.

Something tells me that a cPanel update messed it up.

Am using Engintron + Apache mod_ruid2 (I know there were permission issues with this setup, but fixed it with a cron job setting 777 permission to /var/cpanel/secdatadir)

Anyone having the same issues?
 

gramzon

Member
Dec 4, 2017
23
3
3
Croatia
cPanel Access Level
Root Administrator
I just came here to post the same question. I am not using nginx though but EA4.
WHM v78.0.27

I am using these rules: deano.me/2016/08/protecting-wordpress-wp-admin-server-wide-in-whm-with-cpanel-modsecurity-and-configserver-firewall/

Even after bf_counter exceeds 10, the rule SecRule "ip:bf_counter" "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0" returns 0

Here is a part of the log, you can see bf_counter is already 12 but this rule returns 0:

Code:
Recipe: Invoking rule 55606d88c470; [file "/etc/apache2/conf.d/modsec/modsec2.user.conf"] [line "14"] [id "5000136"].
Rule 55606d88c470: SecRule "RESPONSE_STATUS" "@rx ^302" "phase:5,auditlog,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
Transformation completed in 1 usec.
Executing operator "rx" with param "^302" against RESPONSE_STATUS.
Target value: "200"
Operator completed in 3 usec.
Rule returned 0.
No match, not chained -> mode NEXT_RULE.
Recipe: Invoking rule 55606d8817f8; [file "/etc/apache2/conf.d/modsec/modsec2.user.conf"] [line "16"] [id "5000137"].
Rule 55606d8817f8: SecRule "RESPONSE_STATUS" "@rx ^200" "phase:5,auditlog,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
Transformation completed in 1 usec.
Executing operator "rx" with param "^200" against RESPONSE_STATUS.
Target value: "200"
Operator completed in 3 usec.
Setting variable: ip.bf_counter=+1
Recorded original collection variable: ip.bf_counter = "0"
Relative change: bf_counter=0+1
Set variable "ip.bf_counter" to "1".
Deprecating variable: ip.bf_counter=1/180
Rule returned 1.
Match -> mode NEXT_RULE.
Recipe: Invoking rule 55606d8cf638; [file "/etc/apache2/conf.d/modsec/modsec2.user.conf"] [line "17"].
Rule 55606d8cf638: SecRule "ip:bf_counter" "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"
Transformation completed in 1 usec.
Executing operator "gt" with param "10" against IP:bf_counter.
Target value: "1"
Operator completed in 1 usec.
Rule returned 0.
No match, not chained -> mode NEXT_RULE.
collection_store: Retrieving collection (name "ip", filename "/var/log/secdatadir/rafocorp-ip")
collection_store: Re-retrieving collection prior to store: ip
collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name "ip", filename "/var/log/secdatadir/rafocorp-ip")
collection_unpack: Read variable: name "__expire_KEY", value "1560165731".
collection_unpack: Read variable: name "KEY", value "46.188.154.23".
collection_unpack: Read variable: name "TIMEOUT", value "600".
collection_unpack: Read variable: name "__key", value "46.188.154.23".
collection_unpack: Read variable: name "__name", value "ip".
collection_unpack: Read variable: name "CREATE_TIME", value "1560165130".
collection_unpack: Read variable: name "UPDATE_COUNTER", value "11".
collection_unpack: Read variable: name "bf_counter", value "11".
collection_unpack: Read variable: name "LAST_UPDATE_TIME", value "1560165131".
collection_retrieve_ex: Retrieved collection (name "ip", key "46.188.154.23").
collection_store: Delta applied for ip.UPDATE_COUNTER 0->1 (1): 11 + (1) = 12 [12,2]
collection_store: Delta applied for ip.bf_counter 0->1 (1): 11 + (1) = 12 [12,2]
collection_store: Wrote variable: name "__expire_KEY", value "1560165739".
collection_store: Wrote variable: name "KEY", value "46.188.154.23".
collection_store: Wrote variable: name "TIMEOUT", value "600".
collection_store: Wrote variable: name "__key", value "46.188.154.23".
collection_store: Wrote variable: name "__name", value "ip".
collection_store: Wrote variable: name "CREATE_TIME", value "1560165138".
collection_store: Wrote variable: name "UPDATE_COUNTER", value "12".
collection_store: Wrote variable: name "bf_counter", value "12".
collection_store: Wrote variable: name "LAST_UPDATE_TIME", value "1560165139".
collection_store: Persisted collection (name "ip", key "46.188.154.23").
Recording persistent data took 0 microseconds.
Audit log: Ignoring a non-relevant request.
 
Last edited:

Damlhen

Member
Sep 18, 2017
5
0
1
Bhutan
cPanel Access Level
Root Administrator
Following is my custom rule to block bruteforce on wp-login.php page:

Code:
SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR},id:6
<Locationmatch "/wp-login.php">
# Setup brute force detection.
# React if block flag has been set.
SecRule user:bf_block "@gt 0" "deny,status:401,log,id:7,msg:'ip address blocked for 5 minutes, more than 10 WordPress 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:8"
SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:9"
SecRule ip:bf_counter "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"
</locationmatch>
From the /var/cpanel/secdatadir/domain-ip.pag I can confirm that the bf_counter gets updated every time I access the wp-login.php but it does not seem to be blocking it after it crosses 10 as set in the rule.
 
Last edited by a moderator:

cPanelLauren

Product Owner
Staff member
Nov 14, 2017
13,297
1,259
313
Houston
I'm unaware of changes that would cause this though I do know there were some recent updates to ModSecurity. I'd suggest opening a ticket, while we'd be unable to troubleshoot the functionality of the specific custom rule we may be able to determine if there are issues with rules which use SecDataDir.
Once open please reply with the Ticket ID here so that we can update this thread with the resolution once the ticket is resolved.


Thanks!
 

Damlhen

Member
Sep 18, 2017
5
0
1
Bhutan
cPanel Access Level
Root Administrator
Thank you for the response. I haven opened a ticket (ID: 12555373)
The rule does in fact make use of SecDataDir. With this update, I have noticed that every user has its own file (username-ip.dir, username-ip.dir). Previously there were only two files (ip.pag and ip.pag).
 

cPanelLauren

Product Owner
Staff member
Nov 14, 2017
13,297
1,259
313
Houston
Hi Guys,

Our analyst has finished looking at this ticket and found that there is definitely an issue with the variable check/comparison being presented on systems running ruid2 w/ModSecurity 2.9.3. We've gone ahead and opened an internal tracking case for this but also we've opened a case on their GitHub for this: variable check/comparison isn't working in ruid2 · Issue #2117 · SpiderLabs/ModSecurity

I'd suggest following that case for updates to this issue as well.

For now, the suggestion is to monitor behavior without ruid2 or switch to event with mod_suexec


Thanks!
 

gramzon

Member
Dec 4, 2017
23
3
3
Croatia
cPanel Access Level
Root Administrator
Switching to mpm_event and mod_suexec fixed the issue for me.

Is there any mitigation with this configuration for the "Apache vhosts are not segmented or chroot()ed." warning in Security Advisor? I am not on CloudLinux so cant use CageFS.
 

cPanelLauren

Product Owner
Staff member
Nov 14, 2017
13,297
1,259
313
Houston
Hi @gramzon

Keep in mind that some of these items are purely suggestions and may not suite your individual needs. If your users don't have shell access this isn't really relevant for you but the suggestion does provide other options than just CageFS:

Apache vhosts are not segmented or chroot()ed.
Enable “Jail Apache” in the “Tweak Settings” area, and change users to jailshell in the “Manage Shell Access” area. Consider a more robust solution by using “CageFS on CloudLinux”. Note that this may break the ability to access mailman via Apache.
 

marcuszan

Well-Known Member
Apr 19, 2018
63
5
8
Netherlands
cPanel Access Level
Root Administrator
Hi @gramzon

Keep in mind that some of these items are purely suggestions and may not suite your individual needs. If your users don't have shell access this isn't really relevant for you but the suggestion does provide other options than just CageFS:
Hi @cPanelLauren ,

So to be sure here. mod_ruid2 protects against symlink. So if we have mod_ruid2 module compiled and enabled in EasyApache4, but disabled jail apache in Tweak Settings ( to get mod_sec working again , but triggering the warning in security advisor as described above ) , but ALSO disable all shell for all users ( options are, enable, jailed, disabled ) ,will the server still benefit from mod_ruid2 in some way regarding symlink protection ? Or is the server now vulnerable for symlink attacks ?

Thanks
 

gramzon

Member
Dec 4, 2017
23
3
3
Croatia
cPanel Access Level
Root Administrator
@cPanelLauren the github issue was closed by modsec team. They say it is a bug with the rule but the rule worked before.

@marcuszan this may not apply to you but if you are using kernelcare you can also enable symlink protection by activating the extra patch set
Code:
kcarectl --set-patch-type extra --update