PF How to overload bruteforcers on an rdr rule?

Hi all,

My mail jail has a private address and my pf.conf(5)() has the following:
Code:
mail4="10.10.10.25/32"

# Mail in
rdr pass on $ext_if inet proto tcp from any to $ext_if port smtp        -> $mail4 port smtp
rdr pass on $ext_if inet proto tcp from any to $ext_if port smtps       -> $mail4 port smtps
rdr pass on $ext_if inet proto tcp from any to $ext_if port submission  -> $mail4 port submission
rdr pass on $ext_if inet proto tcp from any to $ext_if port imap        -> $mail4 port imap
rdr pass on $ext_if inet proto tcp from any to $ext_if port imaps       -> $mail4 port imaps

# block bad machines!
block drop in quick from <bruteforce>

# Mail in
pass in quick log inet6 proto tcp from <local6> to $mail6 port { smtp smtps submission imap imaps }
pass in quick log inet  proto tcp from <local4> to $mail4 port { smtp smtps submission imap imaps }
# Protect mail brute force!
pass in quick log inet6 proto tcp to $mail6 port { smtp smtps submission imap imaps } \
 flags S/SA keep state \
 (max-src-conn 100, max-src-conn-rate 15/3600, \
 overload <bruteforce> flush global)
pass in quick log inet  proto tcp to $mail4 port { smtp smtps submission imap imaps } \
 flags S/SA keep state \
 (max-src-conn 100, max-src-conn-rate 15/3600, \
 overload <bruteforce> flush global)

The very last line does not work as expected. I can see literally tons of attempts within a few minutes of each to connect to my mail/postfix. See:
Code:
Nov 12 20:52:47 car dovecot[26097]: auth-worker(94198): Error: pam(althea@...,212.70.149.69): pam_authenticate() failed: Authentication error (/etc/pam.d/dovecot missing?)
Nov 12 20:52:49 car postfix/smtps/smtpd[96058]: warning: unknown[212.70.149.69]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
Nov 12 20:52:53 car postfix/smtps/smtpd[96058]: lost connection after AUTH from unknown[212.70.149.69]
Nov 12 20:52:53 car postfix/smtps/smtpd[96058]: disconnect from unknown[212.70.149.69] ehlo=1 auth=0/1 rset=1 commands=2/3
Nov 12 20:54:09 car postfix/smtps/smtpd[96058]: connect from unknown[212.70.149.69]
Nov 12 20:54:09 car postfix/smtps/smtpd[96058]: setting up TLS connection from unknown[212.70.149.69]
Nov 12 20:54:09 car postfix/smtps/smtpd[96058]: unknown[212.70.149.69]: TLS cipher list "aNULL:-aNULL:HIGH:@STRENGTH"
Nov 12 20:54:18 car postfix/smtps/smtpd[96058]: unknown[212.70.149.69]: Issuing session ticket, key expiration: 1605212657
Nov 12 20:54:18 car postfix/smtps/smtpd[96058]: Anonymous TLS connection established from unknown[212.70.149.69]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Nov 12 20:54:41 car dovecot[26097]: auth-worker(63810): Error: pam(rosalinda@...,212.70.149.69): pam_authenticate() failed: Authentication error (/etc/pam.d/dovecot missing?)
Nov 12 20:54:43 car postfix/smtps/smtpd[96058]: warning: unknown[212.70.149.69]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
Nov 12 20:54:47 car postfix/smtps/smtpd[96058]: lost connection after AUTH from unknown[212.70.149.69]
Nov 12 20:54:47 car postfix/smtps/smtpd[96058]: disconnect from unknown[212.70.149.69] ehlo=1 auth=0/1 rset=1 commands=2/3
Nov 12 20:56:01 car postfix/smtps/smtpd[12542]: connect from unknown[212.70.149.69]
Nov 12 20:56:01 car postfix/smtps/smtpd[12542]: setting up TLS connection from unknown[212.70.149.69]
Nov 12 20:56:01 car postfix/smtps/smtpd[12542]: unknown[212.70.149.69]: TLS cipher list "aNULL:-aNULL:HIGH:@STRENGTH"
Nov 12 20:56:10 car postfix/smtps/smtpd[12542]: unknown[212.70.149.69]: Issuing session ticket, key expiration: 1605212769
Nov 12 20:56:10 car postfix/smtps/smtpd[12542]: Anonymous TLS connection established from unknown[212.70.149.69]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Nov 12 20:56:32 car dovecot[20058]: auth-worker(8477): Error: pam(jordan@...,212.70.149.69): pam_authenticate() failed: Authentication error (/etc/pam.d/dovecot missing?)
Nov 12 20:56:34 car postfix/smtps/smtpd[12542]: warning: unknown[212.70.149.69]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
Nov 12 20:56:38 car postfix/smtps/smtpd[12542]: lost connection after AUTH from unknown[212.70.149.69]
Nov 12 20:56:38 car postfix/smtps/smtpd[12542]: disconnect from unknown[212.70.149.69] ehlo=1 auth=0/1 rset=1 commands=2/3
Nov 12 20:59:58 car postfix/anvil[88941]: statistics: max connection rate 1/60s for (smtps:212.70.149.69) at Nov 12 20:56:10
Nov 12 20:59:58 car postfix/anvil[88941]: statistics: max connection count 1 for (smtps:212.70.149.69) at Nov 12 20:56:10

I'd like to keep using PF for this job, as I don't have to track down every single service's setup and I just have one single source of block: the firewall. I do the same for sshd for instance, and don't rely on blacklistd or fail2ban.
 
I'd like to keep using PF for this job, as I don't have to track down every single service's setup and I just have one single source of block: the firewall. I do the same for sshd for instance, and don't rely on blacklistd or fail2ban.
PF can't tell if it's a failed login or not, it can only see the connection. So you're going to need to use fail2ban, blacklistd or sshguard to keep an eye on login failures. And they all just add addresses to a table that's used by PF. So PF is still a single source of the actual block.
 
I'd still strongly suggest to rely on blacklistd, because it's simply the best tool for the job. Think about it: what program other than smtpd (so: the service that's actually being attacked) can do a better job to detect these attacks? None, that's what.

At best your firewall will be able to check for multiple parallel connections and considers that bruteforce, but whatever happens "within" (or better: during) the connection will always be a mystery for it.

See, you're opening yourself up for a lot of problems because apparently you don't mind when someone tries to attack you as long as it doesn't trigger your firewall. That's a false sense of security you're aiming for, and it's potentially dangerous.

Ergo my suggestion: mail/postfix can be build with blacklistd support, use it. All it does is report the failed attempts to the blacklist service which in its turn will take action by (temporarily?) banning the offenders using a specific anchor within your firewall. And if you don't trust the default process like I did: no problem! You can easily build your own script to handle everything so that you'll always have full control over what's happening (see /usr/libexec/blacklistd-helper, also see blacklistd(8), in specific the -C parameter which allows you to utilize your own "handling script").

(edit): Just for clarification... I started with building my own 'handler' and after that studied the way the whole service works. These days I know the blacklistd-helper script inside out (more or less, it's been a while) so nowadays I simply use the default but still apply the schg flag to it (see chflags(1)) and I got it specifically included in my IDS (security/tripwire). Safety first....
 
OK, so I setup blacklistd to listen on a socket inside my mail jail, and mail/postfix which was compiled with blacklistd support is now protected. However mail/dovecot doesn't look like it has similar options. It doesn't see as much abuse as postfix, but I don't see how I'm supposed to use blacklistd for this specific port. Thus my initial idea of counting how many TCP connection the client tries to establish and nuke it if tries too many times (at most, my own devices sync mail every 20 minutes) (this is something that PF can do in specific conditions, see original post).

Code:
# bzgrep dovecot maillog.*.bz2 | grep -i fail | wc -l
     687
My helper script is a rather very stupid script that adds the IP to my <bruteforce> table, with no other functionnality.
 
Last edited by a moderator:
The downside of blacklistd(8) is that applications need to be specifically coded to make use of it. Despite it's name sshguard can actually watch more than just ssh.


The upside of sshguard is that it's small and has no dependencies. The downside is that it can only monitor certain services and the logging needs to be adjusted to exactly match what SSHGuard wants. In this respect Fail2Ban is much more versatile, you can even create your own rules to monitor a custom service and have it trigger on anything you want.
 
Back
Top