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.
Ipset
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] 12h ^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