How to block IPs with Brute Force Monitor in DirectAdmin using CSF

CSF when coupled with BFM is configured to ignore failed AUTH attempts only. All other features are working as usual.
[cut]
Do you use cluster mode of CSF/LFD?

Thank you for the information. Then I might consider using BFM + CSF. No, I don't use the cluster mode. So with "global", I am only talking about global per server.
 
@Ditto:

I use this in /csf/regex.custom.pm
Code:
 # WP-LOGINS
if (($globlogs{CUSTOM1_LOG}{$lgfile}) and ($line =~ /(\S+).*] "\w*(?:GET|POST) \/wp-login\.php.*" /)) {
    return ("Get lost please",$1,"WPLOGINorWHATEVER","10","80,443","14400");
    }

Works like a charm, server wide. Is that what you're looking for?

That looks very interesting. What else is needed? Maybe you could share what you have in CUSTOM1_LOG? Also I would need to modify it to also block failed attempts on xmlrpc.php
 
@Ditto: Oh sure I'm sorry, I forgot to add that.
Nothing else is needed, just the custom1 log indeed. I've got it like this:
Code:
CUSTOM1_LOG = "/var/log/httpd/domains/*"
You can change the login times and ban time to your needs (10=attempts and 14400 is ban time in seconds)

For xmlrpc.php I have a code, too, but I rather use the server wide code with the virtual custom .post templates:
https://forum.directadmin.com/showthread.php?t=55276&page=2

However, there is a regexp for xmlrpc.php too.
But I'm not sure if this one is really working, because the attacks are not continuously and now I'm using the server wide block with the custom .post templatse.
Code:
# XMLRPC
if (($globlogs{CUSTOM1_LOG}{$lgfile}) and ($line =~ /(\S+).*] "\w*(?:GET|POST) \/xmlrpc\.php.*" /)) {
    return ("Get lost please",$1,"XMLRPCorWHATEVER","10","80,443","14400");
    }

Ah I found them again. I'm just not sure if I didn't slightly adjust them:
https://forum.directadmin.com/showthread.php?t=53911
and
https://forum.configserver.com/viewtopic.php?t=7517

At least I'm sure the custom regexp for wp-login I posted here is working, I've seen various ip's blocked this week by this custom regexp.
 
Last edited:
Thank you very much for sharing Richard! I will study and test this. However regarding the custom1 log path you have:

Code:
CUSTOM1_LOG = "/var/log/httpd/domains/*"

I see that in /var/log/httpd/domains/... there are three kind of log files:

Code:
domain.com.bytes.1
domain.com.error.log
domain.com.log

So I am thinking it might be better to only let CSF scan .log, and not .errror.log and .bytes.1, maybe it will use less server resources? However I am not sure how the custom1 path should look like? Maybe like this?:

Code:
CUSTOM1_LOG = "/var/log/httpd/domains/_*log"

If anybody know the answer to how to write the custom1_log path so that only domain.com.log files are scanned, I would be very happy for any help.
 
Last edited:
So I am thinking it might be better to only let CSF scan .log, and not .errror.log and .bytes.1, maybe it will use less server resources?
I don't know if it would use beneficial less server resources because most of those logfiles are not very big, most nog even bigger then 200 K. On our server the biggest is 477K. I also had a look at this when I implemented this to see if this could be limited to the domain logfiles only. But I couldn't find it and *.log would also include the domein error log so would not make that much difference.

I don't think your last suggestion would work because how should CSF know that the _ stands for a domain names?
But if somebody would know a way to limit it to domain.*.log files that would be nice.
 
Thank you Richard. After looking at this Plesk example wich block both attacks on wp-login.php and xmlrpc.php: https://forum.configserver.com/viewtopic.php?t=8886#p27857 - I have attempted to modify your code to become like this:

Code:
if (($globlogs{CUSTOM1_LOG}{$lgfile}) and ($line =~ /^(\S+).*\w*(?:GET|POST).*(wp-login\.php|xmlrpc\.php).* /)) {
return ("Failed wordpress login from",$1,"wordpress","10","80,443","1");
}

However I am not sure if the regex is syntactical correct or not. I could not just use the Plesk example, because it only did blocking on POST request, but your code did both POST and GET request. So I attempted to add the bits from your code that I needed, into the example code for Plesk. And the above is the result. Lets hope it is correct. Any help from regex experts are welcome!

Also I am using this CUSTOM1_LOG path:
Code:
CUSTOM1_LOG = "/var/log/httpd/domains/*.log"

On each server I have almost 5000 files in /var/log/httpd/domains/, so I am a little worried about what kind of resource usage I will see after implementing this. Let's hope the load does not go high because of this. Then I would need to use BFM instead.

Edit: I am trying to figure out what the scan interval is on the CUSTOM1_LOG path in CSF. How often does it scan the log files? Also I have not figured out what interval is used when blocking the IP from the wp-login.php bruteforce attacks, I mean if a bruteforce attack from one single IP for example make 10 attempts within 23 hours, are they still blocked? Or is it a lower interval? It must be a setting for this in csf.conf in regard to CUSTOM1_LOG path, but I have not found it yet.
 
Last edited:
To answer one of my own questions regarding interval, it seems it is this setting in csf.conf that control it:

Code:
LF_INTERVAL =

Also it seems to work:
Code:
46.105.154.69 # lfd: (wordpress) Failed wordpress login from 46.105.154.69: 10 in the last 300 secs - Sat Apr 27 08:01:47 2019

Now only one question remain: In the Plesk example at https://forum.configserver.com/viewtopic.php?t=8886#p27857 the regex has these apache status codes at the end: (200|401) , however they are missing i Richard regex. I have yet to understand what role they play?
 
Update to my own questions. The way Richard code work, is that it will block anybody doing more then 10 page views on wp-login.php, so I ended up removing replacing this code:

Code:
\w*(?:GET|POST)

with this
Code:
POST

And finally I added this at the end (without those, you would get blocked after 10 successful logins):
Code:
(200|401)

So now users are only getting blocked after 10 failed login attempts.
 
@Ditto: Thank you for figuring this out, because I did not now about the (200|401) statement. It was not mentioned on the pages I found the regexp settings on.

I did not have people being blocked from WP-Login yet, because my timeout is at 300 seconds and no normal user would login in 10 times in a row within 5 minutes which would be every 30 seconds. It is possible however with testing users so indeed removing the GET is better.

Could you share your exact line please? That can see how you don't it and also I'm sure not to make mistakes where to put the (200|401) in the line.
 
This is the code I am using on my production servers now (/usr/local/csf/bin/regex.custom.pm). I have tested it thorough and it works without any problems (a tip is to use a VPN service when testing, so that your IP can be blocked without trouble):

Code:
if (($globlogs{CUSTOM1_LOG}{$lgfile}) and ($line =~ /^(\S+).*POST.*(wp-login\.php|xmlrpc\.php).* (200|401)/)) {
return ("Failed wordpress login from",$1,"bruteforce","5","80,443","1");
}

In addition to the 200 Apache status, the 401 is also nice to have, because some customers can install a captcha or maybe a .htaccess password protection, wich might trigger 401 status.

And I use this path so that at least .bytes files is not scanned (it seems impossible to avoid the error logs because we do not have any unique way of identifying the access logs as they only contain the domain name):


Code:
CUSTOM1_LOG = "/var/log/httpd/domains/*.log"

Even though I have thousands of log files in /var/log/httpd/domains/... it does not seem to slow down the server and does not seem to give any higher load. Actually the load is lower now, likely because the blocking of bruteforce. However I am still wondering it this was the right choice, maybe DirectAdmin BFM would scan the log files with even lesser resource usage. However I like to keep CSF for AUTH blocking on other services, and with BFM I would be forced to let BFM do all that instead of CSF.
 
Last edited:
Thank you for sharing Ditto.

That looks nice indeed. I see you give them a definate block instead of a temp block. Since you were cautious about system resources and have to many domains, is this wise? Because this could create a very lot of iptables lines (depending on what you've configured) which also can cost resources. And there are often so many ip's they can change to or what can become bots. That's why I choose for the temp ban for some time (or days, depening on my mood).

The 200 and 401 are indeed fine. I'm just still wondering. I'm missing ] hook in your line.
Just found the line you used on the configserver forum too... missed it before.

Strange my line did work, because I discovered an error in it:
Code:
if (($globlogs{CUSTOM1_LOG}{$lgfile}) and ($line =~ /(\S+).*] "\w
Almost at the end, you see a closing hook ] while there is no opening hook [ in that line. Seems wrong to me.

I'm just wondering about something... where is the \w* for? I've seen that in the line I used:
Code:
"\w*(?:GET|POST)
I see it's gone now in the line you used, but I'm wondering what's it for? Any clue?
 
Yes, I do permanent block because it will only last for about 4-5 hours anyway, because I have set a limit in DENY_IP_LIMIT and when that limit is reached, then the oldest blocked IP is automatically removed. For my amount of blocking and my setting of DENY_IP_LIMIT (700), it will as said only take 4-5 hours and the IP is removed. So no point for me in setting a temporary block.

Regarding your questions, I am not able to help, as I am not soo good in this regex world. My code is from this example https://forum.configserver.com/viewtopic.php?t=8886#p27857 with only small modifications to the settings and text, but the regex itself I am using exactly the same as in that link.
 
Oke thank you for the explanation.
I've used the same line now, so just that should be oke now.

Maybe if somebody with regex knowledge passes by this topic in time, he/she can explain the \w* instruction.
 
Hello and thanks for this valuable post.

I have hostbill setup on DA server. When i install this, it blocks hostbill from checking domain registration.
Once i stop CSF, hostbill can check domain and provide correct details if domain is available or not.

Any idea on how to resolve?
 
Try this:

Code:
perl -pi -e 's/^UDP_OUT = ".*"/UDP_OUT = "20,21,43,53,113,123,24441"/' /etc/csf/csf.conf
perl -pi -e 's/^UDP6_OUT = ".*"/UDP6_OUT = "20,21,43,53,113,123,24441"/' /etc/csf/csf.conf

it should fix your issue.
 
Last edited:
Try this:

Code:
perl -pi -e 's/^UDP_OUT = ".*"/UDP_OUT = "20,21,53,113,123,24441"/' /etc/csf/csf.conf
perl -pi -e 's/^UDP6_OUT = ".*"/UDP6_OUT = "20,21,53,113,123,24441"/' /etc/csf/csf.conf

it should fix your issue.

Thank you, i tried this but same result. For my domain search to work, I had to enable test MODE on CSF.
Not sure what else to try but incase this does not work. How can i remove?
 
please try again, the commands used to be missing 43 port.

Thanks again for helping. Its now working great.
Really appreciate all you have done for this community.

Thanks
 
Last edited:
please try again, the commands used to be missing 43 port.

https://help.poralix.com/articles/ho...irectadmin-bfm . already i setup this. after this setup my client ip automatic doing block. whith any reason.. but i can not find that ip in block list.. but when i am alowing permanent ip from csf then he can login
main problem is how i can unblock that. i can not find that csf deny ip list or any other.
 
Back
Top