Please use a browser that supports javascript

Intrusion Blocking with Perl and Ipset - syslog-blacklist

This site is running on an exposed server that I maintain myself. After installing it I saw a lot of

"sshd[????]: Failed password for root from ???.???.???.??? port ????? ssh2"

in /var/log/auth.log. This looked a lot like dictionary attacks. I got annoyed, no surprise.


Looking into my options, I decided to build a system for my self. I've based it on ipset and a homebrew service, to get ipset you do this:

apt-get install ipset ipset-source
m-a prepare
m-a build ipset

This makes the kernel-modules in "/usr/src/", so install that and the userspace tools using:

dpkg -i /usr/src/ipset-modules-`uname -r`*.deb
apt-get install ipset

Setting up ipset like this, allows for the same script to be run multiple times without failing, even if yout run the shell with -e.

ipset -L blacklist >/dev/null 2>&1 || ipset -N blacklist iphash
ipset -L whitelist >/dev/null 2>&1 || ipset -N whitelist iphash
ipset -L blackout  >/dev/null 2>&1 || ipset -N blackout  iphash

ipset -F whitelist # for ips that are allowed to fail
ipset -A whitelist ???.???.???.??? # Your static home ipnumber, that shoulden't be locked out no matter how annoying the person behind is :)
ipset -F blackout  # for annoying ipnumbers

This has produced 3 ipsets based on individual ipnumbers. And handled in iptables like this:

iptables -t raw -A PREROUTING -i eth0 -m set --match-set whitelist src -j ACCEPT
iptables -t raw -A PREROUTING -i eth0 -m set --match-set blackout  src -j NOTRACK
iptables -t raw -A PREROUTING -i eth0 -m set --match-set blackout  src -j DROP
iptables -t raw -A PREROUTING -i eth0 -m set --match-set blacklist src -j NOTRACK
iptables -t raw -A PREROUTING -i eth0 -m set --match-set blacklist src -j DROP

Makes sure that ips in the whitelist set aren't blocked early and secondary Ips in blacklist & blackout sets are blocked, and doesn't take space in the connection tracking tables.

Blocking - Who and How

Most the intrusion warnings comes through syslog somehow. So it was quite obvious a solution to look at syslog th determine who to block, the solution I took was to make a perl-script that acts like a remote syslog daemon, which the system installed syslog daemon just sends a copy to.

syslogging to remote service uses UDP. Doing this does not ensure that the packages get through, however UDP over localhost, has very few dropped packages. And has the benefit that if the receiving service isn't up the message is just dropped without too much fuzz.

But mayby you would like a service not using syslog to set intrusion warnings, so another perl script, that reads from stdin and sends a syslog message for each line emulating a system daemon. This allows Apache for instance to log a errorlog through the syslog. You might get "???.???.???.??? 404 /phpMyAdmin-...", and think: people that try things like that, I don't really care for, so - go away.

The basic setup is:

  • Service that listens for syslog messages on an arbitrary port
  • Syslog that sends a copy to arbitrary port
  • Syslog injector for syslog incapable services

Selecting who to block is done by a list in "/etc/syslog-blacklist.conf" which has this format:

[log entry]
number[hms] # amount of time user is blocked
regex rule for matching
regex rule for matching

This could look like this (actual entry):

[failed ssh user]
^sshd\[\d+\]: Failed password for \w+ from {IP_NUMBER}

This takes the ipnumber (matched by {IP_NUMBER}) and blocks it, and logs something like this:

??? ?? ??:??:??: blacklisting ???.???.???.??? for failed ssh user

and 12 hours later ipset removes it automatically:

You might consider adding a rule before for a specific user, which isn't blocked for as log. Just in case you're somwhere unfamiliar, and you type a wrong password (different keyboard layout that you're used to or in a hurry or "fat fingers" or ...).

How to get it

The packages is called syslog-blacklist and is available from my repository. Or as source