Disabling failed ssh logins from script kiddies
I have been getting a huge number of failed login attempts on my web server. These have been anoying for two reasons.
And that's all there is for the code. Then all I did was install it in the root crontab with the following line:
- Someone is trying to hack into my machines.
- The machine can slow to a crawl when trying to deal with the thousands of requests that I am getting. Causing my web services to slow down.
So, the question is:
How can I deal with this?
Some common suggestions:
- Change your port to a non-standard port such as 2222, or some other random number. I agree that this does work, but it can be annoying if my applications cant be configured to connect to a non-standard port.
- Use port knocking to keep the port closed, until the right sequence of ports have been probed. This sounds more elegant than changing the port number, but again if my programs cant do this, then I need some sort of hack to get the port open.
I have gone for a slightly different approach, which is to setup a cronjob to monitor my log files and add the offenders to a list of banned ip addresses. The code was written in ruby and is running on a debian server
Without further ado, here is the code:#!/usr/bin/ruby -T
# hash of found ips used to store the ips found in the
# auth.log
ipFound = Hash.new(0)
puts 'Checking for scanning attempts'
# 1. read in the auth.log
authLog = File.open('/var/log/auth.log','r')
authLog.each_line { |line|
# 2. check for the ip addresses that are scanning
if line =~ /Failed password for invalid user/
if line =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
@ipaddress = $1
#add it to the list
ipFound[@ipaddress] += 1
end
end
}
authLog.close
# hash used to store the ips that are already banned
ipDenied = Hash.new(0)
# open the list of banned ip adresses
hostsDeny = File.open('/etc/hosts.deny','r')
hostsDeny.each_line { |line|
if line =~ /ALL:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
ipDenied[$1] += 1
end
}
hostsDeny.close
# if ip not in denied list or from the local network,
# then add it
hostsDenied = File.open('/etc/hosts.deny','a')
ipFound.each_pair { |ip,count|
puts "IP:#{ip} -> #{count}"
if ipDenied[ip] != 0
puts "IP Already denied"
next
end
if ip =~ /^192.168.1/
puts "IP in local network"
next
end
if count < 10
puts "Didn't scan that much"
next
end
puts "Adding to the denied list"
hostsDenied << "ALL:#{ip}\n"
}
hostsDenied.close
puts "Done"
10 * * * * /path/to/banning_code 2>&1 | Mail -s 'offender ban run' you@your.domainNow it gets run every ten minutes and adds login offenders to the banned list. There is loads more that could be done with this code and it doesn't check for some edge cases, but it will catch most of the script kiddies and get rid of them, until their ip address changes :-(
