Thursday, April 15, 2010

Use php to add iptables rules to block hack attempts

SkyHi @ Thursday, April 15, 2010
Did you ever sit there, tailing your secure log and see 100 attempts a minute trying to SSH login to your box? Yes, it is a brute-force attack, they are trying to figure out your password! These automated programs are easy to spot because your server will log each attempt and until they get the password, those attempts stay in your log file. Now there is a way to stop those attacks.

Create a script that opens and parses your secure log, looks for those attempts and automatically adds a rule to your IPTABLES script to block the IP’s associated with them. This script should work on Fedora and CentOS Linux variants. You could pretty easily modify it to work on just about any other Linux OS.


$badguys = array();
$recent_count = 0;
$older_count =0;
$dropped =0;
$start_time = strtotime("-1 minute"); // Change this if the cron interval is different
echo "Looking for failures since ".date("m/d/Y h:i:s",$start_time)."\n";
/* here is where we go open the log file. (/var/log/secure) in this case. Change that path if your log is located elsewhere */
exec("grep -i 'failed password for invalid user' /var/log/secure",$badguys);
echo count($badguys)." failed password records\n";
$badips =array();
foreach($badguys as $line) {
if(strtotime(substr($line,0,15))>$start_time) {
preg_match('/from ([0-9.]*)/',$line,$match);
$ip = $match[1];
// echo "$ip\n";
if(array_key_exists($ip,$badips)) $badips[$ip]++;
else $badips[$ip]=1;
}else {
echo $recent_count." failures occured in last minute.\n";
echo $older_count." failures were prior to that.\n";
if(count($badips)>0) {
// echo "Here are the ip's to be added to the drop list:\n";
foreach($badips as $ip=>$count) {
echo "$count failed attempts from $ip\n";
/* here, we are saying if there were more than 5 bad password attempts in one minute, then go add that ip to the currently running firewall script. Change this number if you think you yourself could possibly screwup logging in more that 5 times in a single minute. */
if($count > 5) {
exec("iptables -I INPUT -s $ip -j DROP");
/* Note that adding the rule in this way does not make the change permanent, you are not adding it to your startup script, just to the running config. If you want to permanently block those IP addresses, you will need to go to a command shell, and issue the following command:
# service iptables save
or add this command to this script at the very end:
exec("service iptables save");
without one of those commands, the IP blocking effect will be lost at reboot. */
echo "dropping $ip\n";
echo $dropped." ips were dropped.\n";


Now, just because you have this script, doesn’t mean anything will happen, now you have to call it from some where. How do you do that? Here is an idea…

Add it to cron set to run every minute. An even better idea would be to add it to cron on a different server on a different network. Here’s how you do the basic cron entry…

From a command prompt, type:

crontab -e

This opens a vi style editor to edit the crontab file. Use your arrow keys to go to the end of the file and hit your key. (This puts you into insert mode). The following should be on one line, this site wraps it to two lines. Type:

0-59 * * * * php -f /path/to/script.php

Now, hit your key, to get out of edit mode, now type:


Now you should get a message that says “Installing crontab”
thats it, you’re done!