Add Port Knocking to SSH for Extra Security

Written by Mark Sanborn: Apr 2, 2008

SSH by default is very strong. It has protection against various hacks and known vulnerabilities. For instance SSH has a password retry wait time of five seconds. This makes the time for brute force attacking an SSH server very long and probably not effective. However, sometimes script kiddies will fork their hacking program making multiple processes of the brute force attack. Sometimes they are able to fork it off upwards of 1000 attempts every 5 seconds. This drastically minimizes the time to crack short passwords. If you think your users may have weak short passwords you may consider using public key authentication instead of passwords.

Fortuantely SSH comes with a limit on how many connections you allow at once. I believe the default configuration only allows for 40 connections. This along with public key authentication should be enough security to ward of any intrusion attempts. But, what if there was a better way? What if there was a way for the SSH server to appear to not exist?

Well you can make SSH appear to not exist by simply changing the default port to a random port, maybe port 1027. Since port 1027 is not a known SSH port people at first glance will not associate it with an SSH server. However, modern day port scanners can tell not only what ports are open but they can also tell the intruder what service is running on that port. Some port scanners can even list all known vulnerabilities for that service. In fact this is how almost all worms spread themselves. They scan for known open ports and then run a plethora of scripts to attempt to exploit the running service.

With knowledge of the specific port and service that is open, hackers have what they need to start looking for exploits, vulnerabilites or ways to brute force attack your service or in this case SSH server.

This is where the beauty of port knocking comes in. With port knocking you block all incomming traffic to all ports, or in this case SSH. Now when someone tries to do a port scan on port 22 or any other port for that matter they will see absolutely nothing. It will be like the computer doesn’t exist. Even YOU cannot connect to the SSH server on port 22. All requests will be denied.

How do I gain access then?

You will use a knockd server on the remote server running SSH that will monitor all ports at the link layer. It will be waiting for a special “knock”. It will be waiting for you to attempt to gain access to X amount of ports within X seconds. The definition of a valid knock is arbitrary, and up to the implementer. A knock might be, a syn packet sent to these closed ports:

Port 3000, 3001, 8000, 7555 within 4 seconds.

If anyone does the specified knock within the designated time they will be allowed temporary access to port 22 for their IP address. Once the port is opened it doesn’t mean you have access to that computer. You will still have to then connect via SSH and login with your password or private key. Port knocking is just an added layer of protection. It is not intended to be a replacement for authentication.

Although port knocking is awesome technology it is not for services that are intended for public use. Its more for remote administrators that want to access the server without exposing ports generally for private use.

Setting it up on FreeBSD 7.0

`# cd /usr/ports/security/knock

make install clean`

Create edit /usr/local/etc/knockd.conf

[options]
        logfile = /var/log/knockd.log
        interface = xl0

[openSSH]
        sequence    = 7000,8000,9000
        seq_timeout = 5
        command     = /sbin/ipfw -q add 00101 pass proto tcp src-ip %IP% dst-port 22
        tcpflags    = syn

[closeSSH]
        sequence    = 9000,8000,7000
        seq_timeout = 5
        command     = /sbin/ipfw -q delete 00101 pass proto tcp src-ip %IP% dst-port 22
        tcpflags    = syn

Now edit your /etc/rc.conf and add these three lines to turn the firewall on

# Enable Firewal firewall_enable="YES" firewall_type="open"

Available values for firewall_type:

open – pass all traffic. client – will protect only this machine. simple – protect the whole network. closed – entirely disables IP traffic except for the loopback interface. UNKNOWN – disables the loading of firewall rules. filename – absolute path of file containing firewall rules.

_Note: If you don’t specify the firewall type it will default to deny all. This is basically like turning of your internet. We don’t usually want this so set it to open for now. Later you will want to make a file with your specific settings._

Now do a reboot.

When it is rebooting you should now see something like this:

ipfw2 initialized, divert disabled, rule-based forwarding disabled, open, logging disabled

Type this in as root to add a firewall rule on the fly:

ipfw -q add 00102 deny tcp from any to any 22

This will block all incoming traffic to port 22.

You can now test to make sure. Try to open up an SSH connection from another machine. If you get a network error or connection refused the firewall is working.

Now you need to make sure you can open that port by knocking. Make sure knockd is started by typing as root:

knockd

Now according to our /usr/local/etc/knockd.conf it will run the following command when we do a successful port knock:

/sbin/ipfw -q add 00101 pass proto tcp src-ip %IP% dst-port 22

Notice how the number is 00101. This comes before our previous rule we put in that had the number, 00102. You see, ipfw checks rule number one if it passes it goes to the next rule and so on until it reaches the end of the config file.

You can look at your current firewall rules by typing:

# ipfw list

Setting it up on Linux

Since installation of knock will determined by your distribution’s package management software and configuring knockd is pretty much the same in Linux I won’t go into detail. For Debian based systems it should be something like this:

apt-get install knockd

The configuration file for knockd will most likely be in /etc/

The other difference between Linux and FreeBSD is that linux by default usually uses iptables as their firewall instead of ipfw. So you will need to modify your knock config file to have iptables commands instead of ipfw commands.

[options]
      logfile = /var/log/knockd.log

[SSH]
      sequence    = 7000,8000,9000
      seq_timeout = 5
      command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
      tcpflags    = syn
      cmd_timeout   = 10
      stop_command  = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

Doing the Knocking from Windows

To do the knocking for Windows I usually use KnockKnock. Run KnockKnock.exe you should get something like this:

KnockKnock

You should now be able to connect with PuTTY.

If do a ipfw list you should see something similar to this:

00100 allow ip from any to any via lo0 00101 allow ip from any to any proto tcp src-ip 192.168.1.103 dst-port 22 00102 deny tcp from any to any dst-port 22 00200 deny ip from any to 127.0.0.0/8 00300 deny ip from 127.0.0.0/8 to any 65000 allow ip from any to any 65535 deny ip from any to any

Notice how it only opened port 22 to my ip only, not to the entire world.

Need to print shipping labels on your site?

Checkout my product RocketShipIt for simple easy-to-use developer tools for UPS™ FedEx™ USPS™ and more.

Share: