Configure port knocking for a Tor node

I am preparing a post about tools and tips for Tor node operators and, as it frequently happens, trying to put together and write up what I have learned led me to discover new stuff. In particular, I have learned a new technique for hiding services from port scanners and scripts-kiddies called “port knocking“. I decided I wanted to implement it for my node: here you can find a guide on how to do so.

Port knocking for the impatient

If you are going to copy-paste these scripts change the ports numbers, otherwise this is useless. Also, remember that port knocking is not a valid authentication method and should not be used to provide authentication.

  1. change your SSH server configuration in /etc/ssh/sshd_config to run SSH on a non-standard port: sshd_config.patch;
  2. copy iptables rules. These rules set up a knock sequence on ports 23456, 34567, 45678, 56789 with UDP packets that lead to opening port 4992 where SSH should be listening: iptables.rules;
  3. install iptables rules: install rules;
  4. verify that everything is working as expected;
  5. knocking script: knock.sh.

Port knocking: theory and code

What is port knocking?

Wikipedia defines port knocking quite clearly:

Port knocking is a method of externally opening ports on a firewall by generating a connection attempt on a set of prespecified closed ports. Once a correct sequence of connection attempts is received, the firewall rules are dynamically modified to allow the host which sent the connection attempts to connect over specific port(s).
(source: Wikipedia)

The analogy with knocking actual doors is quite strong: the port for a given service – SSH, for example – is kept closed unless the server receives a known sequence of packets. Each packet of the sequence is called a knock. If a valid, pre-established knock sequence is received then the firewall opens the port for the given service for a limited amount of time.

Sheldon knocking Penny's door from The Big Bang Theory - source: http://i.makeagif.com/media/9-21-2015/EzT1wc.gif

Obligatory TBBT reference (source)

It should be noted, and this is stressed on almost all the guides that I have read, that port knocking is not a secure authentication method and should never be used as the only security method to protect your services. In particular, if you want to securely login remotely to your machine, you should use SSH with (RSA) key authentication.

You can set up port knocking with the help of a dedicated service like knockd, which allows the easy setup of complicated knocking sequences, however it is also possible to configure port knocking using only iptables. While the configuration may be more complicated, using only iptables has the advantages of not requiring additional software and of not depending on a service that could cause additional problems of its own (e.g. if the daemon stops working for any reason you are locked outside). There are other tools like knockknock that focus on simplicity.

Configuration

Set up key-based-only SSH authentication on a non-standard port

If you have just created a VPS, you will probably have root access with root being the only user available. The first thing to do is to secure your SSH server. To do so, you need to:

  • make the SSH server listen on a non-standard port (through this example it will be port 4992, you can choose any random high port);
  • disable password login, leaving us only with key-based authentication;
  • create a new user myuser with useradd myuser;
  • increase the size of SSH v1 key (this is probably obsolete, but can’t hurt);
  • disable root login;
  • disable X11 forwarding;
  • disable Linux PAM;
  • Turn off reverse DNS lookups;

At the end, you should change the following configuration values in /etc/ssh/sshd_config:

(view this code on GitHub as a patch with respect to the stock SSH server configuration)

It can be a good idea also to regenerate the ssh host keys using an higher number of bits (2048 for the RSA key, and 512 for the ECDSA key).

Copy the file authorized_keys file over to myuser, this will allow you key-based logins.

Please note that the permission of both /home/myuser and /home/myuser/.ssh should be set to 755 otherwise the server will discard them.

Restart you SSH server:

and test if everything is working correctly logging in from another terminal.

iptables rules

Below you can find the rules to configure port knocking on your node for SSH. The following rules establish that a sequence of 4 knocks on ports 23456, 34567, 45678, 56789 with UDP packets is needed before opening SSH on port 4992.

(view this code on GitHub)

Knocking script

The following script knocks on the ports specified above with UDP packets.

(view this code on GitHub)

Applying the rules

These rules were tested on a Debian 7.10 (wheezy) machine with iptables v. 1.4.14. They should work on any system with a reasonably recent version of iptables.

I recommend trying them first on a machine you can safely lose/reinstall if needed because it is at least theoretically possible that you lock yourself out when trying this 1.

To apply the rules above you can save them in a file iptables.rules and execute the following command (as root)

Testing

In the following we will fire up a backup SSH server and look at the connection logs of the server.

Set up a backup SSH server

To be safe, you can set up a second SSH server listening on port 2222, just in case:

  • create a directory called ~/backup_ssh/;
  • copy the configuration file /etc/ssh/sshd_config in ~/backup_ssh/sshd_config;
  • copy the authorized_keys file in ~/backup_ssh/;
  • create a folder named keys in ~/backup_ssh/ and generate new server keys;
  • update ~/backup_ssh/sshd_config changing:
    • the port number to 2222;
    • the location of server keys to ./keys/ssh_host_rsa_key, ./backup_ssh/keys/ssh_host_dsa_key and ./backup_ssh/keys/ssh_host_ecdsa_key;
    • the AuthorizedKeysFile to ./authorized_keys;
  • uncomment line 43 from the rules above to open port 2222 in the firewall.
  • in a screen/tmux session launch the backup ssh server :

When it is up, the server should say the following:

Note that this server will die on disconnect, so you need to start it each time you use it.

Monitor the logs

You can monitor the connection attemps from your local machine to your server using tcpdump. Suppose that the local machine has IP 111.111.111.111 and the remote server has ip 123.123.123.123. Launch the following command monitors all connection from the specified source ip:

A successful port knocking and following SSH connection will look like this:

We can also monitor the kernel logs for iptables log messages:

A successful port knocking and following SSH connection will look like this:

From the client side, this is how a successful knocking and connection looks like:

Installing

If everything works you can get rid of your backup SSH server (remmeber to comment back line 43 above) and make the iptables rules permanent. We save all the rules in /etc/iptables.rules, we also download a script iptables-restore that re-applies the iptables rules when restarting the network:

Caveat emptor

As pointed out above and in many other venues (see the red box in Arch’s wiki page on port knocking) you should be warned:

Port knocking should be used as part of a security strategy, not as the only protection. That would be a fragile security through obscurity. In case of SSH protection, see SSH keys for a strong method that can be used along with port knocking.

Thus port knocking as only the limited benefit of obscurity. In practice, with port knocking am attacker scanning your machine should first need to guess the correct knocking sequence before discovering your service. It should be noted, though, that this is true only if you choose your port knocking sequence at random. To do so you should change the port numbers, including the port on which you SSH server is listening. You can generate random numbers using a service like random.org. I repeat, do not use the port sequence used in this example for live configurations permanently.

In the case of an attacker that is able to monitor the connections between you and your server the protection offered by port knocking is even more limited. Why is so? As the author of knockknock points out:

The problem with the original concept [of port knocking] was that if your port sequence was observed by passive eavesdropping, it was easily replayable.
that is saying that anyone that could monitor the connections between you and your server can learn which is the knocking sequence that you are using and which is the port where your SSH server is listening and simply knock himself. For this reason a strong authentication method, such as RSA keys, must be used to provide strong authentication.

You may wonder at this point what good can come from techniques like port knocking or the widespread advice of not running SSH on standard ports. If they do not provide security in a strict sense, why bother changing the settings? For this I would like to share this good advices from the tor-relay mailing list. Running SSH on non-standard ports and/or using port knocking can have 3 main advantages:

  1. Many brute-force attackers will only bother trying port 22 (the default port for SSH). Just moving SSH to a non-standard port will shelter you from these attackers.
  2. Using non-standard ports keeps the log files clean, which allows you to focus on the (relative small) number of login attempts the machine gets.
  3. If OpenSSH (or one of its dependencies) should ever be subject to a severe security issue, plenty of folks would immediately
    start scanning and exploiting the Internet. A non-standard port (or port knocking) would likely give you a grace period which would allow you to shut down SSH or take other measures. In other words these measures try to restrict the perimeter of exposure of your services an machines, as the creator of knockknock puts it:

Why Is This Even Necessary?

Because you are running network services with security vulnerabilities in them. Again, you are running network services with security vulnerabilities in them. If you’re running a server, this is almost universally true. Most software is complex. It changes rapidly, and innovation tends to make it more complex. It is going to be, forever, hopelessly, insecure. Even projects like OpenSSH that were designed from the ground-up with security in mind, where every single line of code is written with security as a top priority, where countless people audit the changes that are made every day — even projects like this have suffered from remotely exploitable vulnerabilities. If this is true, what hope do the network services that are written with different priorities have?

The name of the game is to isolate, compartmentalize, and expose running services as little as possible.

Furthermore some other solutions developed on the initial idea of port knocking, such as knockknock, provide countermeasures to some of the limitations above.

Finally, no security-related solution can be relied upon until it has reviewed by a significant number of expert n the field. I do not consider myself an expert in networking and/or the manipulation of iptables. If you find errors lurking in the rules above or improvements that could be made you are invited to provide them in the comments.


  1. To be honest: it took me a couple of tries before getting this configuration right. The first time I locked myself out of a server and only then (sic et simpliciter) I realized that it was better to fire up a new server for testing.