This is more a tale of an experience than a hardcoded howto. Fortunately, it does produce some hard numbers, so my experience may be of help for freebsdesians like meself to make a calculated decision. When I endeavoured on this journey, I did not know what the outcome would be.
It all started when I noticed that there's been an increase in bruteforce attacks on dovecot (I'm on 2.3.21) over the past few weeks. Most of them are harmless since the usernames / emailadresses used are in the guessed category (info, support, hr ...), and do not exist on my server. But it is kind of annoying, so I was wondering if there is a way to block connections using DNSBL's.
Dovecot supports an authentication policy that is supposed to prevent brute force attacks and that enables you to prevent certain users to connect to an emailaccount. That was not what I was looking for. Now you're all thinking "just use fail2ban", but - as usually - I could not help but wondering if there's a dovecot tailored RBL solution to be found, since RBL's work really nice for controlling other aspects in the mail-realm.
Surfing around a bit, I discovered Dovecot offers a little less than perfect solution to prevent logins from certain IP-numbers via the passdb argument in dovecot.conf. This feature allows you to run a script when a connection is made to your imap/pop-ports.
In the same thread on the dovecot-mailinglist there's a script that uses the remote-ip to do a lookup in a blocklist. I extended that to lookups in 3 RBL's
(bl.blocklist.de, auth.spamrats.com and xbl.spamhaus.org). I just copied that (with the stated adaptations) and it actually delivered as promised.
These blocklists perform brilliantly in preventing SMTP bruteforce attacks, but not so with IMAP/POP. Initially only about 20-30% of the illegitimate requests was blocked. So being at this stage, I decided to dream up my own little personal fail2ban-like blocklist extracting the ip-numbers from all login errors in /var/log/maillog where my dovecot installation logs it's errors to.
I edited the mailinglist-script to include a lookup in my own list before the requests to the RBL's are made:
To extract the ip-numbers I run a crontabbed script (there's a lot of temporal unique sorting going on that undoubtebly can be improved upon - I'm not aspiring to be a bash guru!) every 20 minutes (not realtime, but still). The below grepped errors are generated by dovecot. The script produces a daily log with the bruteforce ip numbers (i.e. all failed logins - it's extremely strict; you will have to adapt this to be more tolerant if you're running a server with loads of usermutations!) used that day and adds them to the general log that is being used to block new requests. (It requires an extra crontab to clean up the daily log).
After a few frustrating days with no hits at all on my growing private blocklist, since yesterday hits went through the roof.
These are my current stats (halfway through the day):
POP/IMAP logins:
-----------------------------------------------------
Total ip-numbers blocked: 1006
-----------------------------------------------------
bl.blocklist.de: 46
auth.spamrats.com: 0
xbl.spamhaus.org: 3
Blocked by local dc-rbl: 957
Unblocked failed logins from 29 different IP-numbers
There are currently some 530 IP-numbers in my local blocklist (ipnumbers previously blocked by RBL's are included). The moderate advantage it has over fail2ban (except from requiring no firewall) is that it also uses input from these 3 realtime blocklists, but that advantage sort of pales in comparison to what the local list currently blocks. I had no idea in advance what the yield would be, so I thought it was a nice idea to share the outcome here.
And BTW: the blocked requests are not really blocked by dovecot; they produce a "received no input" in the checkpassword-function that follows the exit 0 command if a blocklist-hit occured.
As far as I can see this is the best dovecot can do - at least it makes life a bit more difficult for the scriptkiddies out there.
Summarizing I guess that if you have a supported firewall set up, fail2ban is probably the easiest option to go for in this case.
But this works for me and the blocklists still contribute some odd %, so I'll just leave it at that.
Hope this inspires someone.
It all started when I noticed that there's been an increase in bruteforce attacks on dovecot (I'm on 2.3.21) over the past few weeks. Most of them are harmless since the usernames / emailadresses used are in the guessed category (info, support, hr ...), and do not exist on my server. But it is kind of annoying, so I was wondering if there is a way to block connections using DNSBL's.
Dovecot supports an authentication policy that is supposed to prevent brute force attacks and that enables you to prevent certain users to connect to an emailaccount. That was not what I was looking for. Now you're all thinking "just use fail2ban", but - as usually - I could not help but wondering if there's a dovecot tailored RBL solution to be found, since RBL's work really nice for controlling other aspects in the mail-realm.
Surfing around a bit, I discovered Dovecot offers a little less than perfect solution to prevent logins from certain IP-numbers via the passdb argument in dovecot.conf. This feature allows you to run a script when a connection is made to your imap/pop-ports.
passdb { args = /usr/local/bin/dovecot_rbl_protect.sh driver = checkpassword result_success = continue-fail result_failure = return-fail }src (read carefully):https://dovecot.org/mailman3/archives/list/dovecot@dovecot.org/message/4VD3GBK5CP5IFGLCSYMBNQEBXHIXTJZO/In the same thread on the dovecot-mailinglist there's a script that uses the remote-ip to do a lookup in a blocklist. I extended that to lookups in 3 RBL's
(bl.blocklist.de, auth.spamrats.com and xbl.spamhaus.org). I just copied that (with the stated adaptations) and it actually delivered as promised.
src:https://dovecot.org/mailman3/archives/list/dovecot@dovecot.org/message/U7CJL7BPN3UDNYCG7VWW5GVUTH6VPGO2/These blocklists perform brilliantly in preventing SMTP bruteforce attacks, but not so with IMAP/POP. Initially only about 20-30% of the illegitimate requests was blocked. So being at this stage, I decided to dream up my own little personal fail2ban-like blocklist extracting the ip-numbers from all login errors in /var/log/maillog where my dovecot installation logs it's errors to.
I edited the mailinglist-script to include a lookup in my own list before the requests to the RBL's are made:
if grep -Fxq "$REMOTE_IP" /var/log/dc-rbl/failed.txt; then log_msg "Dovecot-login REJECTED: $REMOTE_IP is listed in dc-rbl${user:+ for user $user}" exit '0'fiTo extract the ip-numbers I run a crontabbed script (there's a lot of temporal unique sorting going on that undoubtebly can be improved upon - I'm not aspiring to be a bash guru!) every 20 minutes (not realtime, but still). The below grepped errors are generated by dovecot. The script produces a daily log with the bruteforce ip numbers (i.e. all failed logins - it's extremely strict; you will have to adapt this to be more tolerant if you're running a server with loads of usermutations!) used that day and adds them to the general log that is being used to block new requests. (It requires an extra crontab to clean up the daily log).
#!/usr/local/bin/bashcat /var/log/maillog | grep 'failed: Authentication error' | cut -d ',' -f2 | sort -u >> /var/log/dc-rbl/failed_tmp.txtcat /var/log/maillog | grep 'auth failed' | cut -d ',' -f4 | cut -d '=' -f2 | sort -u >> /var/log/dc-rbl/failed_tmp.txtcat /var/log/maillog | grep 'error:0A000102' | cut -d ',' -f2 | cut -d '=' -f2 | sort -u >> /var/log/dc-rbl/failed_tmp.txtcat /var/log/maillog | grep 'error:0A0000C1' | cut -d ',' -f2 | cut -d '=' -f2 | sort -u >> /var/log/dc-rbl/failed_tmp.txtcat /var/log/maillog | grep 'error:0A00006C' | cut -d ',' -f2 | cut -d '=' -f2 | sort -u >> /var/log/dc-rbl/failed_tmp.txtsort -u /var/log/dc-rbl/failed_tmp.txt > /var/log/dc-rbl/failed_today.txt#collect some garbage:sed -i '' '/<>/d' /var/log/dc-rbl/failed_today.txt#add to totalwhile IFS= read -r line; do echo $line >> /var/log/dc-rbl/failed_tmp2.txtdone < /var/log/dc-rbl/failed_today.txtif [ -f '/var/log/dc-rbl/failed_tmp2.txt' ]; then sort -u /var/log/dc-rbl/failed_tmp2.txt >> /var/log/dc-rbl/failed.txtfisort -u /var/log/dc-rbl/failed.txt > /var/log/dc-rbl/failed_tmp3.txtmv /var/log/dc-rbl/failed_tmp3.txt /var/log/dc-rbl/failed.txtrm /var/log/dc-rbl/failed_tmp*exit 0;After a few frustrating days with no hits at all on my growing private blocklist, since yesterday hits went through the roof.
These are my current stats (halfway through the day):
POP/IMAP logins:
-----------------------------------------------------
Total ip-numbers blocked: 1006
-----------------------------------------------------
bl.blocklist.de: 46
auth.spamrats.com: 0
xbl.spamhaus.org: 3
Blocked by local dc-rbl: 957
Unblocked failed logins from 29 different IP-numbers
There are currently some 530 IP-numbers in my local blocklist (ipnumbers previously blocked by RBL's are included). The moderate advantage it has over fail2ban (except from requiring no firewall) is that it also uses input from these 3 realtime blocklists, but that advantage sort of pales in comparison to what the local list currently blocks. I had no idea in advance what the yield would be, so I thought it was a nice idea to share the outcome here.
And BTW: the blocked requests are not really blocked by dovecot; they produce a "received no input" in the checkpassword-function that follows the exit 0 command if a blocklist-hit occured.
As far as I can see this is the best dovecot can do - at least it makes life a bit more difficult for the scriptkiddies out there.
Summarizing I guess that if you have a supported firewall set up, fail2ban is probably the easiest option to go for in this case.
src:https://github.com/fail2ban/fail2ban/blob/master/config/filter.d/dovecot.confBut this works for me and the blocklists still contribute some odd %, so I'll just leave it at that.
Hope this inspires someone.
T