How to safely connect from anywhere to your closed Linux firewall

In general all the great ideas are the simple ones. Many times we see a great idea in practice and we wander why didn’t we thought of that before? It is just so simple… The first time I have seen the knockd project I liked it instantly. The idea is so simple, and though so effective. Knockd is a port-knocking application that silently runs on a server passively listening to network traffic. Once it will see a port sequence it has an action configured for it, it will run that action. We can see this as a remote control to our server: once we hit the right button it will take the appropriate action!

How does a port knocker work?

  • we install the port knocker daemon on our server (knockd)
  • we configure some port sequences (tcp, udp, or both), and the appropriate actions for each sequence.
  • the knockd daemon will be running in the background, at low level passively on the network interface. It is completely stealth and it will not open any ports on the server.
  • once it will see a port sequence it will run the configured action for the sequence.

To exemplify its power I will show a scenario with a server running a firewalled ssh port that allows connections only from one static management IP. All the IPs are private ones for the sake of the example. Using knockd we will be able to connect to the server from another location that would be normally blocked.

Installing knockd

First you will need to install the knockd daemon. See the project home page for the program sources (or rpm, and debs) that the author provides: http://www.zeroflux.org/cgi-bin/cvstrac.cgi/knock/wiki On Debian (as my test server) we can just install it from the main debian repositories:

apt-get install knockd

Our closed firewall setup: we will use a closed SSH setup that allows connections only from 192.168.0.100 to our server. The respective iptables rules look like:

iptables -L -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     tcp  --  192.168.0.100        0.0.0.0/0           tcp dpt:22
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22

These iptables rules will allow me to connect to the server from my management station using ssh, but will drop any other ssh connection. Now if I need to connect to the server from another location I have a problem… what choices do I have? (besides knockd of course):

  • either ask someone to disable the firewall from the console (sucks) or add my IP to the allowed rules (better, but what if there is no one to help me with this?)
  • either I have some way to connect to my management station from my location (let’s say I don’t).

So you see how useful knockd can be in this situation… if I had configured my knockd daemon with the following rules (I will use the default port sequence for this example; you should never use this sequence, and choose your own port sequence):

/etc/knockd.conf:
[openSSH]
sequence    = 7000,8000,9000
seq_timeout = 5
command     = /sbin/iptables -I 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 this case I can just send the port sequence (I will be using the knock client). You can send knocks to the server using other tools like: netcat, sendip, packit, hping or even telnet.

knock -v 192.168.0.102 7000 8000 9000

This has added the rule that will allow me to connect to the server from my current location using the configured iptables rule from above:

iptables -L -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     tcp  --  192.168.0.103        0.0.0.0/0           tcp dpt:22
ACCEPT     tcp  --  192.168.0.100        0.0.0.0/0           tcp dpt:22
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22

Now I can safely connect to the server using ssh from my location (192.168.0.103). Once I am finished I will send the knock to close the whole in the firewall, and return to my original rules:

knock -v 192.168.0.102 9000 8000 7000

Automatically close rules:

If our firewall rules permit this approach we can automatically close the holes opened in the firewall. This can be useful because we might forget to send the closing knock, and leave the rules open in the firewall. Now in order to use this our firewall needs to allow established ssh connections and only block new (syn) ssh connections.

For example our ssh related iptables rules might look like this:

iptables -L -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     tcp  --  0.0.0.0/0        0.0.0.0/0           tcp dpt:22 state ESTABLISHED
ACCEPT     tcp  --  192.168.0.100        0.0.0.0/0           tcp dpt:22
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22

Our knockd configurations looks like:

/etc/knockd.conf:
[opencloseSSH]
sequence    = 7000,8000,9000
seq_timeout   = 5
tcpflags      = syn,ack
start_command = /usr/sbin/iptables -I INPUT -s %IP% -p tcp --syn --dport 22 -j ACCEPT
cmd_timeout   = 25
stop_command  = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --syn --dport 22 -j ACCEPT

In this case once we send the sequence we will have 25 seconds to establish our ssh connection. After that the rule will be deleted.

Security implications

The knockd daemon runs passively listening to network traffic without opening any network ports. Even though it is practically impossible to an attacker to see that we are running knockd on the server, and try to guess the knock sequences we have configured, here are some general common sense security rules:

  • NEVER use default sequences. I have included in my example for this reason the default 7000,8000,9000 sequence to not create another default pattern. Choose your own port sequences.
  • Use at least 3 ports in the sequence. If you are paranoic you can use as many ports as you like.
  • Mix tcp ports (default, if you do not specify the protocol) with udp ports: 9000:tcp,8000:udp,7000:tcp

Even if someone might hit by mistake the configured sequences try to prevent any damage: choose proper timeouts for running the command, use strong passwords, etc.

Other usages: port knocking is not limited to firewall rules as I have exemplified above. You can use it to run any command you might need. Just keep in mind the security implications for each of your defined port sequences (like there is a big difference if someone will hit by mistake a sequence that opens the ssh port for 25 seconds - that will still require to have a proper user and password, and for example a command that will reboot the server - that will start the command once seen the sequence).

I hope that you found this information useful and it will help you make your improve the security of your server (you can close those ports you left open because you were roaming and use port knocking to safely connect to your server).

Note: the project page (and the default installed config file) contain references to add the iptables rules with -A. As you can see in my setup this would have been useless (it would have added the rule after the DROP rule, thus doing nothing), so I have used the -I switch (that will insert the iptables rule at the beginning of the firewall rules):

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

Also you in case you are using a different chain for ssh traffic in your iptables rules (like most peoples will probably do) you will want to change the commands to fit your setup.

References:
http://www.zeroflux.org/cgi-bin/cvstrac.cgi/knock/wiki

comments powered by Disqus