How to Secure External facing SSH Servers from attacks

Write tutorials here
There are more tutorials here http://community.linuxmint.com/tutorial/welcome
Forum rules
Do not start a support topic here please. Before you post please read this

How to Secure External facing SSH Servers from attacks

Postby miket on Wed Nov 26, 2008 6:26 pm

This article is the result of questions I have been asked on the LinuxMint IRC Channel, questions
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 that's denyhosts installed, but we now need to configure it, so lets stop it for the moment to make configuration easier,
so in the same terminal type:

Code: Select all
sudo /etc/init.d/denyhosts stop


Great, now we can edit the config file!
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


Edit the file to make the settings the same as below :

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 =



Any setting not listed above should be left as default in the denyhosts.conf file.
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


I'm assuming you have already installed the ssh server, however if you haven't you'll need to enter the following command to install it:

Code: Select all
sudo apt-get install openssh-server


Now we need to stop the sshd daemon so that we can edit the config file, enter the following command in the terminal:

Code: Select all
sudo /etc/init.d/ssh stop


Now we can edit the sshd_config file.
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


Change the entries in the sshd_config file to match the following, make sure you change the network addresses to match your network
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



So once the settings are changed accordingly, save the file and then exit the editor.

Now restart the sshd daemon using the following command in the terminal:

Code: Select all
sudo /etc/init.d/ssh start


The next step in the process is the installation of the firewall management program, as I said earlier in this article,
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


Next we need to enable the firewall with the following command:

Code: Select all
sudo ufw enable


and now we need to ensure that the default rule for all incoming traffic that hasn't originated from this host is DENY:

Code: Select all
sudo ufw default deny


We are now ready to put the last piece of the jigsaw in place!
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


In the blank editor enter the following code in it's entirety, make sure you change the IP Address to match your network
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


Once you copied the code and made the necessary changes save the file and exit the editor.

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


Next we need to put an entry into the system crontab file for this script to be called every minute, so once again
here is the terminal command to do it:

Code: Select all
sudo gedit /etc/crontab


Go to the bottom of the file and add the following:

Code: Select all
* * * * *   root   cd /root && ./stopfailedssh.sh


Save and exit the editor.
Just bounce the cron daemon to make sure it picks up the change:

Code: Select all
sudo /etc/init.d/cron restart


So the system is now in place, if anyone makes brute force attacks on your external facing ssh service then this
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.
User avatar
miket
Level 5
Level 5
 
Posts: 524
Joined: Tue Mar 04, 2008 5:50 am
Location: UK & France

Linux Mint is funded by ads and donations.
 

Re: How to Secure External facing SSH Servers from attacks

Postby Fred on Wed Nov 26, 2008 11:04 pm

AvanceIT,

Nicely done. Thank you. :-)

Fred
Insanity: Doing the same thing over and over and each time expecting a different result.

Democracy is 2 wolves and a lamb voting on the menu. Liberty is an armed lamb protesting the electoral outcome. A Republic negates the need for an armed protest.
User avatar
Fred
Level 10
Level 10
 
Posts: 3356
Joined: Fri Jan 04, 2008 11:59 am
Location: NC USA

Re: How to Secure External facing SSH Servers from attacks

Postby N1ckR on Thu Nov 27, 2008 6:52 am

Those are good settings.

Additionally, which is not much effort is change the standard port to one above 1024, adds a little obscurity, as there are quite a lot of people only check for port 22 open.

Advanced stuff:

Though I do not personally run them, you could run http://www.snort.org/ to protect from port scans (in the case of some scanning for open ssh port) or running something like knockd (useful ssh instructions: http://www.ducea.com/2006/07/05/how-to- ... -firewall/) which monitors for port sequences so you can only allow an SSH connection if 3 specific ports in specific order are hit.

Cheers, Nick
N1ckR
Level 1
Level 1
 
Posts: 33
Joined: Wed Apr 16, 2008 2:02 pm
Location: West Yorkshire, UK.

Re: How to Secure External facing SSH Servers from attacks

Postby EllisD on Fri May 24, 2013 8:51 am

Thanks for all the hardwork creating this document.

I also found a very useful app called "Fail2ban". Very easy to install, works for SSH straight out of the box.

E
EllisD
Level 1
Level 1
 
Posts: 4
Joined: Thu Sep 20, 2012 12:46 pm

Re: How to Secure External facing SSH Servers from attacks

Postby trapperjohn on Fri May 24, 2013 9:53 am

Good article and well designed for a new comer.

I usually use ssh with key ecryption. It can be setup and done easily with a gui... Putty and puttygen. Here's an article I wrote on how to make this simple. http://www.mark-bishop.net/ssh.php
trapperjohn
Level 5
Level 5
 
Posts: 689
Joined: Wed Jul 11, 2012 4:10 pm

Re: How to Secure External facing SSH Servers from attacks

Postby num7 on Wed May 29, 2013 5:15 pm

Hi, thanks miket for writing this nice howto!!

I have some questions:
question to: /etc/ssh/sshd_config
#1#
Do i have to set:
Code: Select all
# Only allow IPV4 connections
AddressFamily inet

? and why?
#2#
What is the ListenAddress 192.168.100.125 ? Can i find it out with ifconfig. Is it the locale IP of my own machine? ifconfig says my local IP is: inet addr:192.168.178.26

question to: /root/stopfailedssh.sh
Code: Select all
MYNETWORK="192.168.100.0/24"

Is the the same as the local IP of my machine in the LAN? and what does "/24" do at the end of the address?

Most of this i don't understand anyway, now. :cry:
#3#
Code: Select all
case $CURRENTCOUNT in

   $LASTUPDATE )  # logger -p user.notice "stopfailedssh.sh:  LastCount=$LASTUPDATE : Current Count=$CURRENTCOUNT - Nothing to do, exiting ...."
         exit

Isn't the an " <- missing? (Count=$CURRENTCOUNT - Nothing to do, exiting ....")

How can i test if the script is running fine and did no tipping errors?
Can i test if Brute-Force Attacks are denied now?

Thanks for taking into account my posts!
best regards! :D
User avatar
num7
Level 1
Level 1
 
Posts: 13
Joined: Sun Mar 31, 2013 6:23 am


Return to Tutorials

Who is online

Users browsing this forum: Alexa [Bot] and 13 guests