Title: Ban scanners IPs from OpenSMTP logs | |
Author: Solène | |
Date: 22 June 2023 | |
Tags: security opensmtpd openbsd pf | |
Description: In this article you will find a script to parse OpenSMTP | |
logs to ban IP which failed too many login attempts | |
# Introduction | |
If you are an OpenBSD running an OpenSMTP email server, you may want to | |
ban IPs used by bots trying to bruteforce logins. OpenBSD doesn't have | |
fail2ban available in packages, and sshguard isn't extensible enough to | |
support the multiline log format used by OpenSMTP. | |
Here is a short script that looks for authentication failures in | |
`/var/mail/maillog` and will add the IPs into the PF table `bot` after | |
too many failed login. | |
# Setup | |
## PF | |
Add this rule to your PF configuration: | |
```pf | |
block in quick on egress from <bot> to any | |
``` | |
This will block any connection from banned IPs, on all ports, not only | |
smtp. I see no reason to allow them to try other doors. | |
## Script | |
Write the following content in an executable file, this could be | |
`/usr/local/bin/ban_smtpd` but this doesn't really matter. | |
``` | |
#!/bin/sh | |
TRIES=10 | |
EXPIRE_DAYS=5 | |
awk -v tries="$TRIES" ' | |
/ smtp connected / { | |
ips[$6]=substr($9, 9) | |
} | |
/ smtp authentication / && /result=permfail/ { | |
seen[ips[$6]]++ | |
} | |
END { | |
for(ip in seen) { | |
if(seen[ip] > tries) { | |
print ip | |
} | |
} | |
}' /var/log/maillog | xargs pfctl -T add -t bot | |
# if the file exists, remove IPs listed there | |
if [ -f /etc/mail/ignore.txt ] | |
then | |
cat /etc/mail/ignore.txt | xargs pfctl -T delete -t bot | |
fi | |
# remove IPs from the table after $EXPIRE_DAYS days | |
pfctl -t bot -T expire "$(( 60 * 60 * 24 * $EXPIRE_DAYS ))" | |
``` | |
This parses the maillog file, so by default it has a rotation every | |
day, you could adapt the script to your log rotation policy to match | |
what you want, users failing with permfail are banned after some tries, | |
configurable with `$TRIES`. | |
I added support for an ignore list, to avoid blocking yourself out, | |
just add IP addresses in `/etc/mail/ignore.txt`. | |
Finally, banned IPs are unbanned after 5 days, you can change it using | |
the variable EXPIRE_DAYS. | |
## Cronjob | |
Now, edit root's crontab, you want to run this script at least every | |
hour, and get a log if it fails. | |
```crontab | |
~ * * * * -sn /usr/local/bin/ban_smtpd | |
``` | |
This cron job will run every hour at a random minute (defined each time | |
crond restarts, so it stays consistent for a while). The periodicity | |
may depend on the number of scan your email server receives and also | |
the log size vs the CPU power. | |
# Conclusion | |
This would be better to have an integrated banning system supporting | |
multiple logfiles / daemons, such as fail2ban, but in the current state | |
it's not possible. This script is simple, fast, extensible and does | |
the job. |