How to use Port Knocking on Ubuntu to hide the SSH port

You all know these old gangster films where a guy uses a knock sequence on a door to get in? Port knocking is exactly that, just for your server. Changing your default ssh port does not guarantee that you won't get hacked. Hackers often use tools to do automated scans for open ports before they attack a server. Port Knocking is a way by which you can defend yourself against port scanners., it refuses access to a protected port until a client accesses a  sequence of other ports in the right order upfront.

Installing port knocking on Ubuntu is easy. I will show you in this article how to install and set up port knocking. The steps from this tutorials should work for Debian 8 as well.

Step 1: Make sure that all the required packages are installed

All commands below has t be run as root user. I dont want to prepent sudo to all commands, so I use:

sudo su

to become root user. The very first step is to update the Ubuntu package lists:

apt-get update

Then install the SSH server (if you have not installed it already).

apt-get install openssh-server

Now install the knockd software which is the daemon that controls the port knocking.

apt-get install knockd
Get:1 http://security.debian.org wheezy/updates Release.gpg [1,554 B]
Get:2 http://security.debian.org wheezy/updates Release [102 kB]
Get:3 http://security.debian.org wheezy/updates/main amd64 Packages [336 kB]
Hit http://mirrors.digitalocean.com wheezy Release.gpg
Hit http://mirrors.digitalocean.com wheezy Release
Get:4 http://security.debian.org wheezy/updates/main Translation-en [195 kB]
Hit http://mirrors.digitalocean.com wheezy/main amd64 Packages
Hit http://mirrors.digitalocean.com wheezy/main Translation-en
Fetched 635 kB in 1s (358 kB/s)
Reading package lists... Done
[email protected]:~#
[email protected]:~# apt-get install openssh-server
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
openssh-client
Suggested packages:
ssh-askpass libpam-ssh keychain monkeysphere rssh molly-guard ufw
The following packages will be upgraded:
openssh-client openssh-server
2 upgraded, 0 newly installed, 0 to remove and 32 not upgraded.
Need to get 1,364 kB of archives.
After this operation, 0 B of additional disk space will be used.
Do you want to continue [Y/n]? 

Press Y then enter to continue.

Install knockd.

After installing the package, you have to install the iptables kernel firewall. Run:

apt-get install iptables

Step 2: Adding rules to iptables

First, we flush existing firewall rules and ensure that outgoing connections don't get dropped.

iptables --flush
iptables -t nat --flush
iptables -t mangle --flush
iptables --policy OUTPUT ACCEPT

We want to make ensure to allow all established connections and on-going sessions through the firewall, otherwise, the firewall would block the current SSH session:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Note: The above rule has no spaces on either side of the comma in STABLISHED,RELATED.

Then use the following rule to block incoming port 22 (SSH):

iptables -A INPUT -p tcp --destination-port 22 -j DROP

Once you have established your iptables rules, you can automate the restore process at reboot with iptables-persistent. We can download this from Ubuntu's default repository:

apt-get install iptables-persistent
Current iptables rules can be saved to the configuration file ?
? /etc/iptables/rules.v4. These rules will then be loaded automatically ?
? during system startup. ?
? ?
? Rules are only saved automatically during package installation. See the ?
? manual page of iptables-save(8) for instructions on keeping the rules ?
? file up-to-date. ?
? ?
? Save current IPv4 rules?
Current iptables rules can be saved to the configuration file ?
? /etc/iptables/rules.v6. These rules will then be loaded automatically ?
? during system startup. ?
? ?
? Rules are only saved automatically during package installation. See the ?
? manual page of ip6tables-save(8) for instructions on keeping the rules ?
? file up-to-date. ?
? ?
? Save current IPv6 rules?

Install iptables persistant.

IPTables persistant, part 2

During the installation, the program will prompt you to save the current iptables rules (ipV4 and ipV6), just select Yes for both.

Save the current rule-set into a file with the iptables-save command. This file can be used by iptables-restore later to restore the same iptables setup:

iptables-save
 # Generated by iptables-save v1.4.14 on Tue Feb 23 04:59:28 2016
*filter
:INPUT ACCEPT [1:40]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [17:1976]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j DROP
COMMIT
# Completed on Tue Feb 23 04:59:28 2016

Now, you will remain connected to your existing connection while blocking other connections on the SSH port.

Next, we have to configure knockd.

To configure the service, we will have to edit the configuration file /etc/knockd.conf. Open the file with nano:

nano /etc/knockd.conf

Editing knockd.conf with nano.

You will see the sections that will look like this.

[options]
UseSyslog

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

[closeSSH]
sequence = 9000,8000,7000
seq_timeout = 5
command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
  • In the "options" section, we see a directive name UseSysloglogfile is fairly obvious – it logs all knock attempts
  • Ungerneath, we have two sections: openSSH and closeSSH. The first will allow the knocker to access port 22 (SSH), and the second will close the port when the knocker is complete. 
  • knockd automatically replaces %IP% with the IP address of the client that sent the knock, so you can open the port only to the authorized client.
sequence = 9000,8000,7000

This means that this set of rules will match if the same IP requests a connection on port 7000, followed directly by port 8000, followed finally by port 9000. It is highly advisable to change the default ports and their order as the default order is well known to attackers as well.

seq_timeout = 5

The "seq_timeout" option defines in seconds how long you have time to provide all numbers for the knock. This default value should be fine and won't be an issue if you're automatically generating your knocks.

command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

Specify the command to be executed when a client makes the correct port-knock. All instances of %IP% will be replaced with the knocker's IP address.

tcpflags = syn

Pay attention to packets that have to be used to set this flag, in this case syn packets. When using TCP flags, knockd will IGNORE tcp packets that don't match the flags.

Now enable the knockd. Edit the file /etc/default/knockd with nano:

nano /etc/default/knockd

and change:

START_KNOCKD=0

to

START_KNOCKD=1

after this save and exit. If you have multiple network adapters or experience issues that knockd is not starting automatically during system startup, you can manually specify the network interface to listen on by uncommenting and amending the second line KNOCKD_OPTS.

Then start knockd manually:

service knockd start

This will start the daemon and allows you to change the iptables rule sets by knocking on the sequences of ports.

You have installed the required the packages, if you are disconnected from your server, to reconnect you have to knock the ports that you defined in the right sequence establish an SSH connection.

Step 3: Access the server when knockd is running

If you have followed the above steps, then you will not be able to connect to the SSH server directly anymore without port knocking.

You should receive no response from the server and the SSH client should timeout. This is because our SSH daemon is currently blocked by iptables. Type ctrl-C to end the SSH attempt if it does not time out automatically.

Test knocking with a telnet client

For Linux users: Install the telnet package with apt.

For Windows users: you can install the Telnet client by accessing the “Programs” section, search for "Turn windows features on or off", from there enable the Telnet Client.

Type the following the command in your command prompt (replace the port sequence with your custom sequence):

telnet youripaddress 7000
telnet youripaddress 8000
telnet youripaddress 9000

You have to do all this in 5 seconds because this the time limit imposed for the configuration. Now, attempt to connect to your server via SSH. You will be able to access the connection.

Run the above commands in reverse order to close the SSH server.

telnet youripaddress 9000
telnet youripaddress 8000
telnet youripaddress 7000

The best part of port knocking is that you can configure it alongside the private key authentication. If you configure both, then virtually there is no chance that someone could gain access or connect until and unless they know both the ports and the private key.

Share this page:

Suggested articles

14 Comment(s)

Add comment

Comments

By: Tom

Does this work on a CentOS server too that I only can work on through SSH? There is no display and no keyboard connected to it.

By: till

Generally this should work for all Linux distributions. You might have to check where you find a knockd .rpm package.

By: Opensmooth

I use a very much simple solution on my servers. I hide a webpage which unlocks the port 22 for the IP I am calling it from and sends an email to the sysadmin. It is easy, does not need any client except a browser and fairly secure. If the page is found, I just have to rename it and it is not a security issue as it only opens ssh but does not give access.Port knocking is neat but a bit overkill and complicated.

By: Jeremy

Doesn't opening up a web page and port for your solution then expose your machine to hacks on the web server port, possibly exposing that port to hacking vulnerabilities?  So you're sort of trading one vulnerability for another?

By: Flo

How can I prevent forgetting to close port 22 again? What happens when my ip changes? Thanks

By: Erikit

Well, i intergrated it trough IPTABLES directly, and also wrote rules that only 3 packets can be send for logging in after the KNOCKING seqence was correct. So i think this is very secure, if someone would detect the knocking sequence then he has only 3 times to gues the LOGIN.. after that he will be blocked and all traffic will be DROPPED, scanning doesnt work then.. because dropping all the packets.... It works as expected i locked myself out and needed to start a rescue session so i could work in some config files to put my IP on a whitelist...

So yes PORTKNOCKING is a great thing to give someone a hardtime getting into the system 

By: Erikit

Port 22 will only stay open for excisting connection, so if you got the correct KNOCKING sequence then you can connect to port 22... after the connection is made the port will stay open as stated before. Your ip is only relevant if you combine KNOCKIN and IP SPECIFIC access. then you need to specify your new ip address... but if you only integrate KNOCKING then your ip can change as it wouldnt block you to your server.

By: JC

It would be really cool if this tool had a auto close property so that if nobody is connected to port 22 after certain amount of time, it would automatically close the port and I would have to do the port knocking again to re open the port

By: Asterix

So how do I combine this with IP whitelisting so it only opens up the port for my current IP address (from which I'm knocking)? I'm connected on a daily basis so I don't want the port open to all during that time. And I travel daily and connect with different IP addresses via my cell phone's hotspot. I want to knock on the port and then be able to login via Putty, FileZilla, Stash, Git etc via SSH and only via my current IP address. 

By: Ken

Running Ubuntu server 15.04 and 15.10 CLI, knockd was unreliable in that the daemon would inexplictely end, plus it would not handle repeating port-protocol knocks reliably.  I coded my own iptables-only knock rules which are available via a bash-script installer on GitHub.  I call it "POOFITEE".  Toally free, it installs iptables rules and does not have any daemon aspect that can drop dead just when you need it to work like knockd did for me.  It features two styles of knocking that I call strict rules and loose rules.  There are other options in POOFITEE, some in development stage, but the two port knocking options are fully working.  Please let me know if you have any success or difficulties with it, and I can help.  I unashameably lift up the Lordship of Jesus Christ in the project's copyright message, and that aspect of it is absolutely not negotiable.  Lord bless!

By: marcopinero

This does not work on Ubuntu 16.04

By: Jerome

Shouldn't the [closeSSH] command end with DENY? As it is, the commands for both [open/closeSSH] appear to open port 22, which is not what it is supposed to do. This will keep the port open indefinitely for every IP address you use it from.

Don't blindly copy and paste code from general how-to sites like this. Serverfault or the official docs ( run "man knockd" or "man iptables" ) are usually much safer.

Also, this method won't work as-is on an Amazon AWS VM because firewall rules are set in the AWS management console under Security Groups.

By: GeeKayBee

@Jerome the rule is -D, which deletes the ACCEPT rule and is totally valid.  Don't just blindly criticise well written articles becuase you don't understand them

By: Kelvin

This did not work for me (Ubuntu 20.04) because the default knockd.conf command to open the port (A)ppends the rule after the ssh deny rule.

Changing this to (I)nsert the rule fixed this: command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT