The Guru College

Auto-blocking abusive hosts with iptables (Part II)

Last time we looked at auto-blocking hosts, it was a theory session. Today, it’s code, configurations and MySQL databases to make blocking SSH scans real. I know you can do rate-limiting within iptables to slow SSH scanners down, but I take a slightly more hard line approach – if you scan my system, I drop all traffic you send my way for two days. If you scan again within a month of your last block, you get a 30 day ban. Even better – it’s not a block against SSH traffic, it’s a block against all traffic, to all systems that I manage.

To start with, we’re going to need a pair of perl scripts, a MySQL database, and one or more systems running the IPTables or ipfw firewalls. If you’re following along with the HA LAMP stack examples, you already have most of what you need to get started. I’m going to put all the code into a git repository at github.com as I develop the system. The repo is a bit of a mess, and I’m trying to keep it clean, but if you have pointers for a better way to do something, I’m all ears. Also, keep in mind that this is a free-time project for me, which I can only really work on after hours (and after my toddler is asleep.)

First, the MySQL database. The first file you need to use is in sql/bad_traffic.sql. This has the database table structures you need. Please note that it doesn’t do any GRANT statements, so you’ll need to adjust your permissions once it’s installed. It also doesn’t try to do a CREATE DATABASE bad_traffic; you’ll need that setup in advance as well. When you load it up (mysql -u <em>username</em> -p bad_traffic < bad_traffic.sql), it will create two tables: a whitelist_hosts and a blocked_hosts. The whitelist is easy: any address, or fragment of an address will be ignored when looking for bad traffic to add blocks to the database. It’s NOT used when applying blocks, as there are times when you will want to manually add a host that is otherwise whitelisted. (Let’s say you add “10.” as a whitelist entry, which grants anything in the private 10.0.0.0/8 space to the whitelist. You then realize that a rouge machine on your wireless network is causing problems, and you want to shut it down.) The blocked_hosts table contains a lot more details: the IP address of the host being blocked, the day and time it was blocked, the day and time the block will expire, the reason the host was blocked, etc. This is all used when applying blocks, and for determining how long a new block will last, based on past traffic.

The bin/ssh-scanner script looks through /var/log/secure and /var/log/secure.log, looking for failed password attempts for known and unknown users. If it finds SSH attempts for more than 10 user accounts (a frequent pattern of scanning), or if the root account is attempted more than 10 times, the ip address is considered “hostile”, and a block entry is submitted. If this is the first entry for this IP address in the last 30 days, it’s a 2 day block. If there has been at least one block in the past 30 days, the new block is entered for 30 days. If there’s two or more blocks in the last 30 days, the ban is increased to 180 days.

The bin/blocker script does the actual blocking. It generates a hash of the current blocks in the INPUT-AUTO iptables chain and ipfw rules, and compares them against active blocks in the database. Anything present in the database that is not in the firewall is added, and anything that has expired in the database but hasn’t timed out is removed.

The final piece of this puzzle is the config file for the system, for now store in “/etc/cthulhu-manip.cfg”. Usernames, passwords and table names will all go here. It’s safely out of the way of the repo, so I’m not going to accidentally commit my throwaway password, and you won’t have to worry about having yours overwritten when I update the sample config file with more/better examples. There’s an installer script in bin/installer that tries to set the file up for you with sane defaults, as well as add future fields easily without damaging your settings. Finally, bin/chronos sets up a crontab file with jobs to run blocker and scanner at 5 minute intervals.

Anyway, feel free to model your solution as you like, but this is a handy way to give teeth (and memory) to your snort alerts, among other things. It shouldn’t be too hard to adapt the database manipulator to talk to ipfw in Mac OS X (as long as you have the MySQL DBD bits in the right place). It should also be easily extended to other types of traffic blocking – simply write a filter for the proper log file looking for malicious activity, and then log it to the database. (I’m working on a HTTP log analyzer at the moment). Once the block record is in the database, the rest of the system will handle black hole maintenance of “-j DROP” on the rest of the hosts that subscribe to this system. If you develop good ones, I’m happy to take patches, credit you, and keep this going.

DBD::MySQL and Snow Leopard | Home | cthulhu-manip and OSX