Tag Archives: ssh

Fixing fail2ban

I had installed fail2ban but had noticed it wasn’t working blocking ssh brute force attacks. Attacks such as below.

user@computer:$ grep sshd /var/log/auth.log | tail
Apr 29 08:06:17 sd-229337 sshd[20646]: pam_unix(sshd:auth): check pass; user unknown
Apr 29 08:06:17 sd-229337 sshd[20646]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=211-75-3-35.hinet-ip.hinet.net
Apr 29 08:06:18 sd-229337 sshd[20646]: Failed password for invalid user db2inst from 211.75.3.35 port 52724 ssh2
Apr 29 08:06:19 sd-229337 sshd[20646]: Connection closed by 211.75.3.35 [preauth]
Apr 29 08:18:21 sd-229337 sshd[20711]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=59-120-243-8.hinet-ip.hinet.net user=root
Apr 29 08:18:25 sd-229337 sshd[20711]: Failed password for root from 59.120.243.8 port 34312 ssh2
Apr 29 08:18:25 sd-229337 sshd[20711]: Connection closed by 59.120.243.8 [preauth]
Apr 29 08:19:14 sd-229337 sshd[20713]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=195-154-136-62.rev.poneytelecom.eu user=root
Apr 29 08:19:16 sd-229337 sshd[20713]: Failed password for root from 195.154.136.62 port 24329 ssh2
Apr 29 08:19:16 sd-229337 sshd[20713]: Connection closed by 195.154.136.62 [preauth]

In order to fix this we need to modify /etc/fail2ban/filter.d/common.local and modify bsd_syslog_verbose entry. Substitute __bsd_syslog_verbose = (<[^.]+\.[^.]+>) for __bsd_syslog_verbose = (<[^.]+ [^.]+>).

user@computer:$ grep bsd_syslog_verbose /etc/fail2ban/filter.d/common.local
#__bsd_syslog_verbose = (<[^.]+\.[^.]+>)
__bsd_syslog_verbose = (<[^.]+ [^.]+>)
__prefix_line = \s*%(__bsd_syslog_verbose)s?\s*(?:%(__hostname)s )?(?:%(__kernel_prefix)s )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s%(__daemon_extra_re)s?\s*

Restart fail2ban and you shall now see IPs performing brute force attacks being blocked as below.

user@computer:$ tail -30 /var/log/fail2ban.log | grep actions
2018-04-29 18:43:19,835 fail2ban.actions[28271]: WARNING [ssh] Unban 163.172.159.119
2018-04-29 18:43:20,742 fail2ban.actions[28519]: INFO Set banTime = 1800
2018-04-29 18:43:20,936 fail2ban.actions[28519]: INFO Set banTime = 600
2018-04-29 18:43:59,119 fail2ban.actions[28519]: WARNING [ssh] Ban 171.244.27.195
2018-04-29 18:46:05,286 fail2ban.actions[28519]: WARNING [ssh] Ban 5.188.10.185
2018-04-29 19:13:59,938 fail2ban.actions[28519]: WARNING [ssh] Unban 171.244.27.195
2018-04-29 19:14:50,026 fail2ban.actions[28519]: WARNING [ssh] Ban 171.244.27.195
2018-04-29 19:15:35,102 fail2ban.actions[28519]: WARNING [ssh] Ban 159.65.10.166
2018-04-29 19:16:06,167 fail2ban.actions[28519]: WARNING [ssh] Unban 5.188.10.185
2018-04-29 19:44:50,740 fail2ban.actions[28519]: WARNING [ssh] Unban 171.244.27.195
2018-04-29 19:45:35,821 fail2ban.actions[28519]: WARNING [ssh] Unban 159.65.10.166
2018-04-29 19:45:38,858 fail2ban.actions[28519]: WARNING [ssh] Ban 171.244.27.195

But why is this happening? It is because of regular expressions. The way logs are being written it will never find a match with the original __bsd_syslog_verbose. Below script test both bsd_syslog_verbose settings. Originally we needed to have a ., but in reality we have a space in our logs, so we need to modify bsd_syslog_verbose.

#!/usr/bin/env python

import re

testline = 'May 13 06:24:36'

match = re.search('[^.]+\.[^.]+', testline)
if match:
    print 'Found:', match.group()
else:
    print 'Not found for bsd_syslog_verbose=[^.]+\.[^.]+'

match = re.search('[^.]+ [^.]+', testline)
if match:
    print 'Found:', match.group()
else:
    print 'Not found for bsd_syslog_verbose=[^.]+ [^.]+'

And we execute:

user@computer:$ python regex.py
Not found for bsd_syslog_verbose=[^.]+\.[^.]+
Found: May 13 06:24:36

More info here and some instructive regex google doc.

Using expect

Let’s give a brief intro to expect. Basically is a tool for automating interactive applications such as FTP, telnet, ssh and similar. Expect has regular expression pattern matching and general program capabilities.

Let’s start installing Expect. Type in your Debian based box:

sudo aptitude install expect

That’s it. You are done.

Now lets write a simple ssh expect script. Substitute user, password and hostname for the user, password and hostname to the machine you want to log into.

#!/usr/bin/expect
spawn ssh user@hostname
expect “user@hostname’s password:”
send “password\r”
expect “$\r”
send “who; pwd; last | head\r”
expect “$\r”
send “date; exit\r”
expect eof

The script is pretty simple. It basically logs into a box and executes date, pwd, who and last commands. But it clearly shows the power of expect for automating tasks.

More info at Wikipedia and Expect homepage.

Blocking SSH attacks with IPtables

If you have a website running you might get brute force attacks on the ssh port. Below is an excerpt from the logs in /var/log/auth.log

Jan 28 21:32:16 server sshd[10855]: Failed password for illegal user root from 213.191.74.219 port 51033 ssh2
Jan 28 21:32:16 server sshd[10857]: Illegal user root from 213.191.74.219
Jan 28 21:32:16 server sshd[10857]: Failed password for illegal user root from 213.191.74.219 port 53722 ssh2
Jan 28 21:32:16 server sshd[10859]: Illegal user root from 213.191.74.219
Jan 28 21:32:16 server sshd[10859]: Failed password for illegal user root from 213.191.74.219 port 54393 ssh2
Jan 28 21:32:16 server sshd[10861]: Illegal user root from 213.191.74.219
Jan 28 21:32:16 server sshd[10861]: Failed password for illegal user root from 213.191.74.219 port 55099 ssh2

Blocking this attacks is really easy with IPtables. Just type the following from the CLI.


sudo iptables -A INPUT -i eth0 -p tcp –dport 22 -m state –state NEW -m recent –set –name SSH
sudo iptables -A INPUT -i eth0 -p tcp –dport 22 -m state –state NEW -m recent –update –seconds 60 –hitcount 3 –rttl –name SSH -j DROP

The above command will block ssh attacks on the SSH port on your server. Enjoy.

Setting passwordless ssh trust

I’m going to explain how to set ssh trust between two hosts. This would allow us to connect to the server without having to type the password.

1) First generate the public and private keys on the machine from where you want to log in to other machines. This can be accomplished in two ways depending on the ssh version running on the server you want to log in. I recommend using ssh version 2. Ssh version 1 has security flaws.

Type from the command line:

# ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_dsa.
Your public key has been saved in /home/user/.ssh/id_dsa.pub.
The key fingerprint is:
86:40:27:c5:29:ce:64:35:1f:a9:b9:9c:f0:97:a5:4d user@server
The key’s randomart image is:
+–[ DSA 1024]—-+
|    o+=…       |
|   .+ooo..       |
|   =.. o.        |
|    +.o.  E      |
|     +.oS*       |
|      =.+ .      |
|       .         |
|                 |
|                 |
+—————–+
#

This will generate a public and a private key in the ~/.ssh directory. Don’t type anything when asked for the passphrase. Now we need to copy the public key to the server we want to log in passwordless.

2) Type the following.

# scp ~/.ssh/id_dsa.pub user@remote_server:/tmp

3) Log into the remote server and copy the public key to the authorized_keys file in the ~/.ssh directory.

remote_server# cat /tmp/id_dsa.pub >> ~/.ssh/authorized_keys

That’s it. You are done. Enjoy.