I've received via email and questions via this forum.
It is by no means a complete guide to security for a Linux system, however it addresses one particular
problem, that being the ever increasing number of brute force ssh attacks now taking place on the internet today.
It would appear that the old ssh Trojan is back in circulation and that more and more Linux machines are
being infected due to users setting weak passwords for their user accounts and then having these machines externally
facing on the internet which leads to them being hacked and the Trojan being installed without them realising.
This article is by no means a criticism of Linux users in general, more an aid to help anyone that has an externally
facing Linux system protect it against such ssh attacks and to help reduce the numbers of new systems being infected.
So, how does this Trojan work ?
Well basically it has two lists, a list of usernames and a list of passwords, it then tries combinations of the two
against unsuspecting ssh serving Linux systems until it gets a match and can login, once logged in
it installs another copy of the Trojan and then the process starts again. It uses a very simple process,
one which is very easy to block with a little careful configuration.
So on to the interesting part, how do we stop these attacks from causing us problems ?
One of the simplest ways to stop these attacks is to use two widely available applications and a simple shell script to
pass data from one to the other.
The first of these applications is a program called "denyhosts". "denyhosts" monitors the /var/log/auth.log file for sequential
failed ssh login attempts and then (depending how it's config file is setup) denies the attacker access to the sshd port. This is great
as it puts an immediate stop to the attack, normally within a few seconds of the attack starting.
"denyhosts" stops the attacker accessing the ssh port (port 22 normally) by adding their IP Address into the /etc/hosts.deny file.
This is very handy as a simple shell script can read this information and then pass it to a firewall for it to be automatically added
to the ruleset to deny the attacker access to any port on the system thus increasing security even further.
I've decided to use ufw for the firewall interface as it is easy for the newbie to get to grips with.
So, lets get on with the installation and configuration!
First we need to install denyhosts, the easiest way is to do it from the command line, so open a Terminal and enter the following command:
Code: Select all
sudo apt-get install denyhosts
so in the same terminal type:
Code: Select all
sudo /etc/init.d/denyhosts stop
In the terminal enter the following command to open the editor with the denyhosts.conf file in it:
Code: Select all
sudo gedit /etc/denyhosts.conf
Code: Select all
# Debian:
SECURE_LOG = /var/log/auth.log
# Most operating systems:
HOSTS_DENY = /etc/hosts.deny
# never purge:
PURGE_DENY =
# To block only sshd:
BLOCK_SERVICE = sshd
DENY_THRESHOLD_INVALID = 1
DENY_THRESHOLD_VALID = 3
DENY_THRESHOLD_ROOT = 1
DENY_THRESHOLD_RESTRICTED = 1
WORK_DIR = /var/lib/denyhosts
SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES
HOSTNAME_LOOKUP=YES
# Debian
LOCK_FILE = /var/run/denyhosts.pid
# Disable Email notification.
ADMIN_EMAIL =
SMTP_HOST = localhost
SMTP_PORT = 25
SMTP_FROM = DenyHosts <nobody@localhost>
SMTP_SUBJECT = DenyHosts Report
SYSLOG_REPORT=YES
AGE_RESET_VALID=
AGE_RESET_ROOT=
AGE_RESET_RESTRICTED=
AGE_RESET_INVALID=
DAEMON_LOG = /var/log/denyhosts
DAEMON_SLEEP = 5s
DAEMON_PURGE =
Once you made the necessary changes, save the file and exit the editor.
Now we need to restart the denyhosts daemon, so now enter the following command:
Code: Select all
sudo /etc/init.d/denyhosts start
Code: Select all
sudo apt-get install openssh-server
Code: Select all
sudo /etc/init.d/ssh stop
Note: I have decided not to cover key authentication in this article, as I'm keeping to the KISS principle, but I will cover it in a later article,
so this example allows login via ssh using username and pasword, so make sure you use a mix of UPPER and lower case characters with a splattering of
numbers in your password, don't use easy to guess words and names!!
So to edit the sshd_config file, enter the following command in the terminal:
Code: Select all
sudo gedit /etc/ssh/sshd_config
and the username to match your Linux Login name.
Code: Select all
# Only allow IPV4 connections
AddressFamily inet
# What ports, IPs and protocols we listen for
Port 22
# Use these options to restrict which interfaces/protocols sshd will bind to
# Change this to match your network subnet!!
#ListenAddress ::
#ListenAddress 0.0.0.0
ListenAddress 192.168.100.125
ListenAddress 127.0.0.1
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes
# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 768
# Logging
SyslogFacility AUTH
LogLevel INFO
# Authentication:
LoginGraceTime 30
PermitRootLogin no
StrictModes yes
MaxAuthTries 2
RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile %h/.ssh/authorized_keys
# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes
# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Change to no to disable tunnelled clear text passwords
#PasswordAuthentication yes
# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
X11Forwarding yes
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no
#MaxStartups 10:30:60
#Banner /etc/issue.net
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
# Change YOURUSERNAME to your Linux Login name!
AllowUsers YOURUSERNAME
# NEVER allow root to login via SSH !!
DenyUsers root
Now restart the sshd daemon using the following command in the terminal:
Code: Select all
sudo /etc/init.d/ssh start
I've decided to use ufw as it is very easy for the Linux newbie to understand.
First we need to install it!
The terminal command for this is:
Code: Select all
sudo apt-get install ufw
Code: Select all
sudo ufw enable
Code: Select all
sudo ufw default deny
This piece consists of a simple shell script that will form the link between denyhosts and the ufw firewall control program.
For those of you who are experienced shell scriptors this is a very simple script, it's simple deliberately and yes there is
scope for improvement, however I've kept it simple for a reason, it's easy to understand and reliable!
Since the script is going to be run by the root user via cron I will suggest you install it in /root ... however if you prefer
you may install it else where, but make sure you make the necessary changes to make it work!
so, lets create the script, in the terminal type:
Code: Select all
sudo gedit /root/stopfailedssh.sh
and add/delete the services as required (ufw commands), Note These rules DO NOT affect OUTGOING network traffic, only INCOMING :
Code: Select all
#!/bin/bash
######################################################################################
#
# This script is released into the public domain under the Open Source GPL Licence.
# Originally written by MikeT, http://www.avanceit.co.uk
#
# This script comes with no guarantees or warranties, you run it at your own risk!!
#
######################################################################################
######################################################################################
# stopfailedssh.sh
#
# Simple script to collect IP Addresses of hackers trying to get in via ssh
# and add them to the firewall with DENIED access ruleset
# IP Addresses are supplied by denyhosts and are listed in the /etc/hosts.deny file
# marked by sshd in the first field.
######################################################################################
######################################################################################
# MikeT - v1.0 15/11/08
# Update - v1.5 21/11/08
# Update - v2.0 24/11/08
######################################################################################
######################################################################################
# This script is called by adding the following into the /etc/crontab file
#
# * * * * * root cd /root && ./stopfailedssh.sh
#
# This will run the script every minute, which is what we want.
# Remember to remove the "#" at the beginning of the line when adding to the crontab file!!
#
# Save this script into /root/stopfailedssh.sh
# chown root:root & chmod 700
######################################################################################
######################################################################################
# Packages required by this script:
#
# sudo apt-get install ufw
# sudo apt-get install denyhosts
# sudo apt-get install openssh-server
#
######################################################################################
######################################################################################
# Declare Global Variables
INPUTFILE="/etc/hosts.deny"
LISTOFIPS=`cat $INPUTFILE | grep sshd | awk '{print $2}'`
UFWCOMMAND="/usr/sbin/ufw"
TOUCHFILE="/root/.stopfailedssh"
LASTUPDATE=`cat /root/.stopfailedssh.UPDATE`
COUNTFILE="/root/.stopfailedssh.UPDATE"
# Change the netork address belwo to match your network IP range!!
MYNETWORK="192.168.100.0/24"
######################################################################################
# Make a note of the date/time we ran
touch $TOUCHFILE
######################################################################################
# First of all lets see if there are any changes we need to incorporate into the firewall ruleset
CURRENTCOUNT=`grep sshd $INPUTFILE | wc -l `
case $CURRENTCOUNT in
$LASTUPDATE ) # logger -p user.notice "stopfailedssh.sh: LastCount=$LASTUPDATE : Current Count=$CURRENTCOUNT - Nothing to do, exiting ...."
exit
;;
esac
######################################################################################
# If we get to here then there are new entries in the /etc/hosts.deny file that need processing!
######################################################################################
# Remove the Allow Entries in the firewall rule set as they must stay
# at the bottom as the rules are applied from the top down.
# So all DENY rules MUST be before any ALLOW rules.
# Uncommment for Jabber server
#$UFWCOMMAND delete allow 5222/tcp
#$UFWCOMMAND delete allow 5269/tcp
# Uncomment for IRC server
#$UFWCOMMAND delete allow 6667/tcp
# Allow connections from our own network
$UFWCOMMAND delete allow from $MYNETWORK
# Allow ssh connections from anywhere
$UFWCOMMAND delete allow 22/tcp
# Uncomment for WebServer
#$UFWCOMMAND delete allow 80/tcp
logger -p user.notice "stopfailedssh.sh: Updating Firewall Rule Set now ...."
for ENTRY in $LISTOFIPS
do
$UFWCOMMAND deny proto any from $ENTRY to any
logger -p user.notice "$UFWCOMMAND deny proto any from $ENTRY to any"
done
######################################################################################
# Now put all the ALLOW rules back into the firewall
# so that they are after all the DENY rules.
# Uncomment for Jabber Server
#$UFWCOMMAND allow 5222/tcp
#$UFWCOMMAND allow 5269/tcp
# Uncomment for IRC Server
#$UFWCOMMAND allow 6667/tcp
# Allow connections from our own network
$UFWCOMMAND allow from $MYNETWORK
# Allow ssh from anywhere
$UFWCOMMAND allow 22/tcp
# Uncommeent for WebServer
#$UFWCOMMAND allow 80/tcp
######################################################################################
# Now the catch all, if none of the above rules apply then there is something
# fishy going on, so DENY them any access at all!
$UFWCOMMAND default deny
######################################################################################
# Tidy up and lets get out of here !
echo $CURRENTCOUNT > $COUNTFILE
logger -p user.notice "stopfailedssh.sh: LastCount=$LASTUPDATE : Current Count=$CURRENTCOUNT - Updates Complete!"
exit
Now we need to make the executable by root only:
Code: Select all
sudo chmod 700 /root/stopfailedssh.sh
chown root:root /root/stopfailedssh.sh
here is the terminal command to do it:
Code: Select all
sudo gedit /etc/crontab
Code: Select all
* * * * * root cd /root && ./stopfailedssh.sh
Just bounce the cron daemon to make sure it picks up the change:
Code: Select all
sudo /etc/init.d/cron restart
neat little system will detect it, block it and then deny the attacker access to any port on your server!
I hope this all makes sense, please feel free to post any questions !
Mike.