Defeating poor port knocking configurations


Door knocker

I was thinking about port knocking the other day (yep, that’s how I roll) and while I consider it to be a valid security layer, it occurred to me that it would be pretty easy to set up a poor implementation of it that was susceptible to being gamed. Here’s how that thought process went.

Caveat: This is a proof of concept and has many points against it which I outline at the end of this post.

For the uninitiated, port knocking is a process whereby some port on a server can be fire-walled off until some pre-determined set of ports are ‘knocked’ on, and then the firewall can be reconfigured to open some other port. A practical example is a server where you need SSH access, but you don’t want to leave the SSH daemon running wide open to the world all the time. You can use a port knocking daemon like knockd, coupled with an IPTables firewall to protect that port. The normal configuration would be to have the SSH daemon running on some arbitrary port and have the firewall dropping connections to that port until a valid set of ports are knocked on, and then the IPTables would be rewritten, usually temporarily, to allow connections to the SSH port.

The security layer this provides is two fold:

When configuring the ports that will unblock the desired port (the port sequence), there are three things that can be set:

When put together, this is a pretty daunting task. An attacker would have to know how many ports to knock (from 1 to ?) and what ports to knock (from 1 to 65,535) and pull that all off within the set sequence timeout.

But, as they say, the devil is in the details. If the configured port sequence has ports close (enough) together and ascends or descends, then the configuration is all but ruined. If an attacker were to set her sites on a server she knows runs a service, but presents no ports for that service, she might deduce that a port knocker is in use. The easiest attack to start with would be a sequential ascending or descending port knocking palooza.

An example of a defeatable (is that a word?) port knocking configuration is ports 7003, 7459 and 8001 using the default knockd.conf timeout of 5 seconds. The attack stems from the fact that the knockd daemon does not pay attention to knocks on ports that are not part of a sequence it is configured to look for. This makes sense as it would be computationally expensive to monitor every port for activity and compare it against a potentially complex list of sequences. But it can be gamed a bit like so:

As a proof of concept I set up the following test:

The knockd daemon config:

[TEST]
  sequence    = 3030,4040,5050
  seq_timeout = 5
  start_command = echo "You're in!"
  tcpflags    = syn
  cmd_timeout   = 1
  stop_command  = echo "You're out!"

The port knocking client config:

4 ms between knocks
Port: 2020
Port: 3030
Port: 3035
Port: 4040
Port: 4045
Port: 5050    

Notice that there are only 3 ports in my unblock sequence, but 6 ports in my client’s knocking config. Since the knockd daemon does not care about the 2020, 2025 or 4045 knocks, my sequence still triggers the start_command as shown in the log below:

The log:

[2016-02-15 08:48] x.x.x.x: TEST: Stage 1
[2016-02-15 08:48] x.x.x.x: TEST: Stage 2
[2016-02-15 08:48] x.x.x.x: TEST: Stage 3
[2016-02-15 08:48] x.x.x.x: TEST: OPEN SESAME
[2016-02-15 08:48] TEST: running command: echo "You're in!"

Note: the reason this attack succeeded despite my port range being outside the 1250 maximum is because I did not knock every port.

As a proof of concept this is nice, but is it really a practical attack vector in the real world? The answer is a solid “maybe”. It’s not going to attract any lulz low-hanging fruit script kiddies, but if you’re being targetted, it might be possible for a bad actor to win.

Here are some mitigating factors that make this vector potentially useless, or at least extremely costly:

If you assume that better systems can get the knock delay down to 1ms, that means an attacker could hit 5000 ports per default 5-second timeout which is a paltry 13 iterations (65 seconds) to run every port and it also greatly expands the allowable range of ports in each iteration.

Based on this, it becomes easier to see how to harden your port knocking configuration:

There are more reasons why this attack would fail than there are reasons why it would succeed, but it’s also obvious that a poor configuration could allow a bad guy in. Spending a few minutes thinking about the realities of what your configuration should be instead of taking the default configuration could save you some pain down the road.

#infosec #security