I run several hosting servers and recently I have experienced a lot of bruteforce attacks against joomla-based websites. Attackers seem to try a bruteforce against administrator/index.php page.

I usually lock away IPs when they try to bruteforce Wordpress logins with the following ruleset:

SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},id:5000134
<Locationmatch "/wp-login.php">
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.'"
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"

But I can't find a similar rule for Joomla!, since response status is "303 see other" both with valid password and invalid password.

Any help? Thanks in advance!

  • 1
    in phase 4 you can inspect response body of HTTP server; so instead of matching HTTP code you should look for words like wrong password or login failed which is characteristic for Joomla failed login attempt (note that I made those up, and you'd need to check for exact response strings on some joomla install your self) – Hrvoje Špoljar Nov 24 '14 at 10:22
  • thanks Hrvoje, it's a good idea but it would work in English only. I studied a little bit and maybe I found a better solution that I'm testing right now :-) – godzillante Nov 24 '14 at 11:17

So, here's my answer.

By ispecting the return headers I noticed that Joomla! backend returns some HTTP headers when login is correct, and doesn't return them when login is invalid.

e.g., the P3P header is returned after a successful login, so I just look for its length being > 0:

SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},id:5000144
<Locationmatch "/administrator/index.php">
    SecRule ip:bf_block "@gt 0" "deny,status:401,log,id:5000145,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
    SecRule RESPONSE_HEADERS:P3P "streq 0" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000146"
    SecRule RESPONSE_HEADERS:P3P "!streq 0" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000147"
    SecRule ip:bf_counter "@gt 10" "t:none,setvar:ip.bf_block=1,expirevar:ip.bf_block=300,setvar:ip.bf_counter=0"
| improve this answer | |

The problem with the accepted answer is that it doesn't take into consideration when a refresh of the login page takes place. So, when the person refreshes the login page, it will either: 1) reset the counter (which is bad) or 2) count the refresh as a failed login (which is also bad).

We have just devised a rule for handling brute force attacks on Joomla which is based on the "com_login" post value. If the value is in the post value, then this means that it was failed login, if not then the login is successful. The rule can be found here.

| improve this answer | |
  • If you have an issue with the accepted answer, comment under it. Don't post as an answer. As far as your rule, you should post some type of excerpt of the rule, vs just a link. – David Makogon Jun 24 '16 at 0:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.