UPDATE: This was a good exercise but I decided to replace the script with denyhosts: http://denyhosts.sourceforge.net/. In CentOS, just intall the EPEL repo first, then you can install it via yum.
This is one of the problems that my team encountered when we opened up a firewall for SSH connections. Brute force SSH attacks using botnets are just everywhere! And if you’re not careful, it’s quite a headache if one of your servers was compromised.
Lot of tips can be found in the Internet and this is the approach that I came up with based on numerous sites that I’ve read.
- strong passwords
DUH! This is obvious but most people ignore it. Don’t be lazy. - disable root access through SSH
Most of the time, direct root access is not needed. Disabling it is highly recommended.- open
/etc/ssh/sshd_config
- enable and set this SSH config to no:
PermitRootLogin no
- restart SSH:
service sshd restart
- open
- limit users who can log-in through SSH
Users who can use the SSH service can be specified. Botnets often use user names that were added by an application, so listing the users can lessen the vulnerability.- open
/etc/ssh/sshd_config
- enable and list the users with this SSH config:
AllowUsers user1 user2 user3
- restart SSH:
service sshd restart
- open
- use a script to automatically block malicious IPs
Utilizing SSH daemon’s log file (in CentOS/RHEL, it’s in /var/log/secure), a simple script can be written that can automatically block malicious IPs using tcp_wrapper’s host.deny
If AllowUsers is enabled, the SSH daemon will log invalid attempts in this format:
sshd[8207]: User apache from 125.5.112.165 not allowed because not listed in AllowUsers
sshd[15398]: User ftp from 222.169.11.13 not allowed because not listed in AllowUsers
SSH also logs invalid attempts in this format:sshd[6419]: Failed password for invalid user zabbix from 69.10.143.168 port 50962 ssh2Based on the information above, I came up with this script:#!/bin/bash # always exclude these IPs exclude_ips='192.168.60.1|192.168.60.10' file_log='/var/log/secure' file_host_deny='/etc/hosts.deny' tmp_list='/tmp/ips.for.restriction' if [[ -e $tmp_list ]] then rm $tmp_list fi # set the separator to new lines only IFS=$'\n' # REGEX filter filter="^$(date +%b\\s*%e).+(not listed in AllowUsers|\ Failed password.+invalid user)" for ip in $( pcregrep $filter $file_log \ | perl -ne 'if (m/from\s+([^\s]+)\s+(not|port)/) { print $1,"\n"; }' ) do if [[ $ip ]] then echo "ALL: $ip" >> $tmp_list fi done # reset unset IFS cat $file_host_deny >> $tmp_list sort -u $tmp_list | pcregrep -v $exclude_ips > $file_host_deny
I deployed the script in root’s crontab and set it to run every minute 🙂
There, of course YMMV. Always test deployments and I’m pretty sure there are a lot of other tools available 🙂