Securing my server from spammers and bots

In the last few weeks I've been getting hammered by spam directed toward my private, self-hosted email address; typically every 30 minutes I would receive some... well, strange emails, often trying to sell me a product or were just plain strange. Unfortunately this address was part of a LinkedIn data leak spammers had managed to get a hold of.

After observing my mail logs, I noticed the spammer(s) sending me these emails wasn't the only one trying to cause trouble: there were quite a few bots using SASL attacks to attempt to login. ssh logs were much, much worse. Finally, I decided I was going to go to war against bots trying to gain unauthorized access to my Ubuntu server.

Installing ipset

iptables is most likely suitable for small servers trying to IP ban spammer and bots. While this is optional, ipset is a more appropriate option when performance is important. Install it:

1
sudo apt-get install ipset

As an additional optional task, you can make ipset entries persist across reboots using ipset-persistent.

Installing fail2ban

fail2ban (f2b) is a piece of software that monitors log files and looks for suspicious activity. f2b has what are called filters and actions: filters are regular expressions that get evaluated for each log line and are used to match on suspicious activity (e.g. you might want to match for failed password attempts if you're monitoring ssh logs); and actions are what f2b should do when a ban is to happen. A jail in f2b is a combination of a filter and one or several actions. You can configure a jail for any app on your server. Many default jails are provided in jail.conf, but you can override their behavior in a local jail config.

To install fail2ban:

1
sudo apt-get install fail2ban

f2b comes with presets for popular apps such as ssh. Adding a jail for it to /etc/fail2ban/jail.local:

1
2
3
4
5
6
7
8
9
10
[sshd]
enabled = true
mode = aggressive
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 300
bantime = 1h
banaction = iptables-ipset-proto6
ignoreip = 127.0.0.1

A few things to point out:

  • We enable the sshd jail with enabled = true
  • While optional in this case (the sshd jail already sets the filter name in jail.conf), you can specify which filter should be applied by specifying the filter name. For example, if sshd is the filter name, there should be a matching config file in /etc/fail2ban/filter.d/sshd.conf.
  • logpath is a path to the log file to monitor.
  • maxretry is the number of matches (e.g. a failed password attempt) to allow before deciding to ban.
  • findtime is a time unit which specifies how many retries within the time given to allow. In this case, if there are more than 5 retries in a 5 minute span (300 seconds = 5 minutes), then f2b executes a ban.
  • bantime is a time unit specifying how long the ban should be in effect for.
  • banaction is what should happen when a ban is executed. iptables-ipset-proto6 is the name of an action (which should exist at /etc/fail2ban/action.d/iptables-ipset-proto6.conf), and comes with a default installation of f2b. This ban action adds the IP of the offending machine to an ipset and if not already done so, adds a line to iptables which creates a REJECT rule for any IPs which match in the ipset.

Here's an example of a log line that would match f2b's fail regex:

1
Sep 25 20:48:16 anthony-calandra sshd[3527]: Failed password for invalid user foo from 203.121.116.9 port 55036 ssh2

Here's an example of a SASL attack that f2b would match (line 2, specifically):

1
2
3
4
Sep 25 20:21:24 anthony-calandra postfix/smtps/smtpd[2317]: connect from unknown[194.61.24.152]
Sep 25 20:21:31 anthony-calandra postfix/smtps/smtpd[2317]: warning: unknown[194.61.24.152]: SASL PLAIN authentication failed:
Sep 25 20:21:31 anthony-calandra postfix/smtps/smtpd[2317]: lost connection after AUTH from unknown[194.61.24.152]
Sep 25 20:21:31 anthony-calandra postfix/smtps/smtpd[2317]: disconnect from unknown[194.61.24.152] ehlo=1 auth=0/1 commands=1/2

I also have jails for long-term attacks: bots which don't ever leave my server alone.

Adjusting my mail server to more aggressively reject suspicious email

I found that the default postfix configuration wasn't very aggressive against rejecting suspicious mail. So after looking around on the internet for some settings to enable, I settled on the following.

/etc/postfix/main.cf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
smtpd_delay_reject = yes
strict_rfc821_envelopes = yes
disable_vrfy_command = yes
smtpd_helo_required = yes
 
smtpd_relay_restrictions =
    permit_mynetworks
    permit_sasl_authenticated
    defer_unauth_destination
 
smtpd_sender_restrictions =
    permit_mynetworks
    permit_sasl_authenticated
    reject_unknown_sender_domain
    reject_non_fqdn_sender
 
smtpd_recipient_restrictions =
    permit_mynetworks
    permit_sasl_authenticated
    reject_unauth_destination
    reject_invalid_helo_hostname
    warn_if_reject reject_non_fqdn_helo_hostname
    warn_if_reject reject_unknown_helo_hostname
    warn_if_reject reject_unknown_reverse_client_hostname
    warn_if_reject reject_unknown_client_hostname
    reject_non_fqdn_sender
    reject_non_fqdn_recipient
    reject_unknown_sender_domain
    reject_unknown_recipient_domain

Once this configuration is saved, reload postfix:

1
sudo systemctl reload postfix

These simple changes rejecting about 80% of the spam I was receiving daily.

Installing spamassassin

This is still a work in progress, as I've been noticing the default rules are not effective at all against the spam I've been receiving.

TODO

Tags: bot, spam, email, postfix, dovecot, iptables, ipset, fail2ban, spamassassin, ubuntu, linux