Multiple-port knocking Netfilter/IPtables only implementation

Posted by uroboros on Fri 7 Oct 2005 at 13:52

There are several methods of implementing port knocking (the sophisticated project Knockd for instance). Here we'll demonstrate a very simple means of achieving the port-knocking effect using nothing more than netfilter, or iptables, rules.

You will need the iptables "recent" module compiled in you kernel or as a module - we've previously introduced using this to rate-limit incoming connections with the recent module.

There are the magical rules (many thanks belongs to Rusty Russel for this):

# Netfilter/IPtables - example of multiple-port knocking
# Note: Knock ports 100,200,300,400 to open SSH port for 5 seconds.
# Nice thing to knock TCP with is `telnet' program:
# $> alias k='telnet ip_address_or_hostname'
# $> k 100 ; k 200 ; k 300 ; k 400 ; ssh ip_address_or_hostname
# Then press Ctrl-C 4 times. That's all. Enjoy.

HOST_IP="12.34.56.78"

/sbin/iptables -N INTO-PHASE2
/sbin/iptables -A INTO-PHASE2 -m recent --name PHASE1 --remove
/sbin/iptables -A INTO-PHASE2 -m recent --name PHASE2 --set
/sbin/iptables -A INTO-PHASE2 -j LOG --log-prefix "INTO PHASE2: "

/sbin/iptables -N INTO-PHASE3
/sbin/iptables -A INTO-PHASE3 -m recent --name PHASE2 --remove
/sbin/iptables -A INTO-PHASE3 -m recent --name PHASE3 --set
/sbin/iptables -A INTO-PHASE3 -j LOG --log-prefix "INTO PHASE3: "

/sbin/iptables -N INTO-PHASE4
/sbin/iptables -A INTO-PHASE4 -m recent --name PHASE3 --remove
/sbin/iptables -A INTO-PHASE4 -m recent --name PHASE4 --set
/sbin/iptables -A INTO-PHASE4 -j LOG --log-prefix "INTO PHASE4: "

/sbin/iptables -A INPUT -m recent --update --name PHASE1

/sbin/iptables -A INPUT -p tcp --dport 100 -m recent --set --name PHASE1
/sbin/iptables -A INPUT -p tcp --dport 200 -m recent --rcheck --name PHASE1 -j INTO-PHASE2
/sbin/iptables -A INPUT -p tcp --dport 300 -m recent --rcheck --name PHASE2 -j INTO-PHASE3
/sbin/iptables -A INPUT -p tcp --dport 400 -m recent --rcheck --name PHASE3 -j INTO-PHASE4

/sbin/iptables -A INPUT -p tcp -s $HOST_IP --dport 22 -m recent --rcheck --seconds 5 --name PHASE4 -j ACCEPT

The script can be also downloaded from here. [Local mirror]

These rules will open port 22 for 5 seconds after you knock ports 100, 200, 300 and 400 with TCP packets.

It is not perfect I know. But can be used nearly everywhere. If you have some other ideas of how to implement the multiple-port knocking with Netfilter/IPtables, please contribute in the discussions below.

 

 


Posted by davekempe (203.206.xx.xx) on Sun 9 Oct 2005 at 11:50
We figured out how to do it with shorewall. Shorewall rocks for creating decent firewalls. We had to do a multi-port knock which opened multiple ports. It works quite well and I will santise and post somewhere if anyone is interested. Reply here if you want me to post somewhere - I couldn't be bothered sanitising until there is demand :)

[ Parent | Reply to this comment ]

Posted by Anonymous (195.202.xx.xx) on Sun 9 Oct 2005 at 20:40
I, for one, would love to see the Shorewall recipe.

[ Parent | Reply to this comment ]

Posted by Anonymous (69.15.xx.xx) on Mon 10 Oct 2005 at 17:40
ME TOO!

--
Tommy Butler

[ Parent | Reply to this comment ]

Posted by Anonymous (67.104.xx.xx) on Mon 10 Oct 2005 at 22:41
I would like to see. Here is the docs from shorewall

http://www.shorewall.net/PortKnocking.html


The more info the better!

[ Parent | Reply to this comment ]

Posted by uroboros (217.11.xx.xx) on Thu 13 Oct 2005 at 13:23
[ View Weblogs ]
I saw several other implementations of multiple-port knocking with IPtables that used some very "obscure" things (like marking packet etc). But I did not like the way, because why to mark packets if we have IPtables that are (nearly {a bit a joke}) "turing complete"... :) Well, I will like to see the Shorewall based implementation. No, not really. I mean, I would like to see the output set of rules, the final set of rules for the same sequence of ports as in my example. Can you make it and paste it here in this discussion? I am really very interested in it. Thanks.

--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.

[ Parent | Reply to this comment ]

Posted by Anonymous (213.146.xx.xx) on Fri 14 Oct 2005 at 09:19
I too would like to see a Shorewall script. But please the _final_ iptables, nothing in between. I know about some distributions to write firewall scripts on a kind of strange way.

Thanks would be great.

[ Parent | Reply to this comment ]

Posted by love_linux (62.30.xx.xx) on Mon 5 Feb 2007 at 23:46
basely, in shorewall, you are going to do the same thing as the example from above. you just have to change to iptable to run_iptables in SSHKnock (shorewall) and add a extra recent name in rule. thats all. if you want more security then, you could go to shorewall's official website, there is an example there that tell you exactly what you have to do to avoid port scan.
because, for the method that shows in above, it could not avoid port scan.

people could detect your sequence quit easily..
i had both multiple ports knocking and the method to avoid port scan setup in my laptop and server, it works very good.

I love shorewall. its a great tool to use.
if you need the configuration file, you could leave a msg here.


[ Parent | Reply to this comment ]

Posted by Anonymous (82.173.xx.xx) on Fri 28 Oct 2005 at 15:56
This script is great, but how do you activate this from a windows pc for example?

[ Parent | Reply to this comment ]

Posted by Anonymous (82.173.xx.xx) on Fri 28 Oct 2005 at 15:57
and in this i mean, i'm sitting behind a pc and want to open the port.

[ Parent | Reply to this comment ]

Posted by uroboros (217.11.xx.xx) on Mon 31 Oct 2005 at 17:09
[ View Weblogs ]
Knock the same way, of course. Use TCP only and use the suggested "telnet" method. Go to DOS and run `telnet ..., telnet ...', etc. as suggested. I have never had Windows at all. Maybe ask in some Windows forum for some tools that can be suitable for this purpose. But I think that Windows has got the Telnet command line client, hasn't it?

--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.

[ Parent | Reply to this comment ]

Posted by uroboros (217.11.xx.xx) on Mon 31 Oct 2005 at 17:16
[ View Weblogs ]
Or you can do some sort of a "trick". If you have some UNIX shell account you can still reprogram the given rules to another sort of behaviour. You can even allow knocking as such from the UNIX machine for the purpose to open the needed port for 0/0 for some time and then close. So, you connect from the Windows box to the UNIX machine, knock and then request the service from the Windows box and logout. :-) Or somethink like that...

--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.

[ Parent | Reply to this comment ]

Posted by uroboros (217.11.xx.xx) on Mon 31 Oct 2005 at 17:30
[ View Weblogs ]
Or imagine this:

A(Windows) = 12.34.56.78
B(Unix) = 23.45.67.89
C(server we wanna reach) = 34.56.78.90

On C setup rules that will say somethink like this:

If from server B somebody knocks with sequence s1 s2 s3 12 34 56 78 s4 s5 ("sx" means some "secret" ports that only you know) then open PORT for A for N seconds.

You can setup several rules and you will only need to memorize the "sx" sequences.

Just use the imagination. On the other hand, if you are really unable to knock with telnet from Windows box and you do not have any shell account on protected UNIX machine, you can still install Cygwin and telnet from it.

--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.

[ Parent | Reply to this comment ]

Posted by Anonymous (92.28.xx.xx) on Wed 21 Apr 2010 at 20:41
In linux you use netcat (nc), it allows to enter any IP and port number with a 1 second connection. eg scrip for above would be:

#! /bin/bash
nc -w 1 192.168.1.10 100
nc -w 1 192.168.1.10 200
nc -w 1 192.168.1.10 300
nc -w 1 192.168.1.10 400

(-w 1 = connect for 1 seconds, ipaddress= 192.168.1.1, port = 100)
(also you need to "chmod u+x (script name).sh" to make it executable)
(after running this you attempt a connection on 22, and bingo it works)
:)

[ Parent | Reply to this comment ]

Posted by Anonymous (201.252.xx.xx) on Fri 4 Nov 2005 at 18:06
but using GNU/Debian...why don't you install knockd and get a much more configurable port knocking system..?

[ Parent | Reply to this comment ]

Posted by uroboros (217.11.xx.xx) on Tue 15 Nov 2005 at 08:38
[ View Weblogs ]
As I said: with this there is no need of installing some extra stuff. You can do what you need to do.

--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.

[ Parent | Reply to this comment ]

Posted by Anonymous (82.67.xx.xx) on Thu 15 Dec 2005 at 18:53
Hi all !

I don't have any pretention to tell you what is good a idea or not, but here is mine :
what about using a shared public key, associated with a private key, to generate knocks combinations. the system could ban any valid used keys.

if you think that idea doesn't sucks at all, mail me : doctor@makelofine.org

Best wishes all !

[ Parent | Reply to this comment ]

Posted by Anonymous (202.89.xx.xx) on Sun 2 Apr 2006 at 22:02
Hi all, I'm a newbie so please bear with me :). I just tried the above script and everything went file till that last rule. but don't you have to explicitly close your port 22? as I can't see it anywhere.

[ Parent | Reply to this comment ]

Posted by uroboros (86.49.xx.xx) on Wed 5 Apr 2006 at 22:52
[ View Weblogs ]
Ah, I must have failed to mention it: default policy is expected to be DROP, of course. :-)

--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.

[ Parent | Reply to this comment ]

Posted by Anonymous (208.187.xx.xx) on Thu 6 Apr 2006 at 16:02
You would need to add something like:

/sbin/iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j REJECT

at the end to block all traffic to port 22 except connections that are already open. This way you have to knock and connect in the 5 second window before the door shuts again. You would not have to login in within 5 seconds but just establish the initial connection.

[ Parent | Reply to this comment ]

Posted by jbyers (208.187.xx.xx) on Thu 6 Apr 2006 at 17:14
Here is a full working script for multi-port knocking that will handle multiple ports. Im currently using 'Its Me Port Knocking Client' from http://www.min.at/port/ along with putty on my windows box to open the door. Works very well. I call it from a batch file.

#!/bin/sh
#
# Netfilter/IPtables - example of multiple-port knocking
# Note: Knock ports 100,200,300,400 to open SSH port for 5 seconds.
# Nice thing to knock TCP with is `telnet' program:
# $> alias k='telnet ip_address_or_hostname'
# $> k 100 ; k 200 ; k 300 ; k 400 ; ssh ip_address_or_hostname
# Then press Ctrl-C 4 times. That's all. Enjoy.
#
# Change this to the name of the interface that provides your "uplink"
# (connection to the Internet) or connection you want to protect.
UPLINK="eth0"
#
# Comma seperated list of ports to protect with no spaces.
SERVICES="22,21"
#
# Location of iptables command
IPTABLES='/sbin/iptables'
#
${IPTABLES} -N INTO-PHASE2
${IPTABLES} -A INTO-PHASE2 -m recent --name PHASE1 --remove
${IPTABLES} -A INTO-PHASE2 -m recent --name PHASE2 --set
${IPTABLES} -A INTO-PHASE2 -j LOG --log-prefix "INTO PHASE2: "
#
${IPTABLES} -N INTO-PHASE3
${IPTABLES} -A INTO-PHASE3 -m recent --name PHASE2 --remove
${IPTABLES} -A INTO-PHASE3 -m recent --name PHASE3 --set
${IPTABLES} -A INTO-PHASE3 -j LOG --log-prefix "INTO PHASE3: "
#
${IPTABLES} -N INTO-PHASE4
${IPTABLES} -A INTO-PHASE4 -m recent --name PHASE3 --remove
${IPTABLES} -A INTO-PHASE4 -m recent --name PHASE4 --set
${IPTABLES} -A INTO-PHASE4 -j LOG --log-prefix "INTO PHASE4: "
#
${IPTABLES} -A INPUT -m recent --update --name PHASE1
#
${IPTABLES} -A INPUT -p tcp --dport 100 -m recent --set \
--name PHASE1
${IPTABLES} -A INPUT -p tcp --dport 300 -m recent --rcheck \
--name PHASE1 -j INTO-PHASE2
${IPTABLES} -A INPUT -p tcp --dport 200 -m recent --rcheck \
--name PHASE2 -j INTO-PHASE3
${IPTABLES} -A INPUT -p tcp --dport 400 -m recent --rcheck \
--name PHASE3 -j INTO-PHASE4
#
${IPTABLES} -A INPUT -p tcp --match multiport --dport ${SERVICES} \
-i ${UPLINK} -m recent --rcheck --seconds 5 --name PHASE4 -j ACCEPT
${IPTABLES} -A INPUT -p tcp --match multiport --dport ${SERVICES} \
-m state --state NEW -j REJECT

[ Parent | Reply to this comment ]

Posted by uroboros (86.49.xx.xx) on Wed 24 May 2006 at 23:24
[ View Weblogs ]

To `jbyers': Script pretends that default politic for the INPUT is DROP:

...
/sbin/iptables -P INPUT DROP
...
source /path/to/the/script
...

Thus there is no need for adding any special rule in the INPUT chain in my script. Or did I miss something about your solution?

To all:

The script works as follows: If first port is touched then we jump into PHASE1. If we are in PHASE1 we expect PHASE2 which is the second port touching. If the second port is touched then we remove from PHASE1 and jump to PHASE2 and expect PHASE3... and so on. If we reach the last phase we allow what we want for what time we want from anywere we want. I can even be generalized this way. Nice, isn't it?

More tighten rules could also be as such:

#!/bin/bash

NETWORK=12.34.56.78/32

# ... cleaning up, setting up politics, etc.

# ---GENERATED W/ IPTKNOCK---

/sbin/iptables  -A INPUT -i eth0 -p tcp -s ${NETWORK} --dport 100 -m recent --name 1-1-1 --set
/sbin/iptables  -N 1-1-IN-2
/sbin/iptables  -A 1-1-IN-2 -m recent --name 1-1-1 --remove
/sbin/iptables  -A 1-1-IN-2 -m recent --name 1-1-2 --set
/sbin/iptables  -A 1-1-IN-2 -j LOG --log-prefix NAME-1-1-IN-2
/sbin/iptables  -A INPUT -i eth0 -p tcp -s ${NETWORK} --dport 100 -m recent --rcheck --name 1-1-1 -j 1-1-IN-2
/sbin/iptables  -N 1-1-IN-3
/sbin/iptables  -A 1-1-IN-3 -m recent --name 1-1-2 --remove
/sbin/iptables  -A 1-1-IN-3 -m recent --name 1-1-3 --set
/sbin/iptables  -A 1-1-IN-3 -j LOG --log-prefix NAME-1-1-IN-3
/sbin/iptables  -A INPUT -i eth0 -p tcp -s ${NETWORK} --dport 200 -m recent --rcheck --name 1-1-2 -j 1-1-IN-3
/sbin/iptables  -N 1-1-IN-4
/sbin/iptables  -A 1-1-IN-4 -m recent --name 1-1-3 --remove
/sbin/iptables  -A 1-1-IN-4 -m recent --name 1-1-4 --set
/sbin/iptables  -A 1-1-IN-4 -j LOG --log-prefix NAME-1-1-IN-4
/sbin/iptables  -A INPUT -i eth0 -p tcp -s ${NETWORK} --dport 300 -m recent --rcheck --name 1-1-3 -j 1-1-IN-4
/sbin/iptables  -N 1-1-IN-5
/sbin/iptables  -A 1-1-IN-5 -m recent --name 1-1-4 --remove
/sbin/iptables  -A 1-1-IN-5 -m recent --name 1-1-5 --set
/sbin/iptables  -A 1-1-IN-5 -j LOG --log-prefix NAME-1-1-IN-5
/sbin/iptables  -A INPUT -i eth0 -p tcp -s ${NETWORK} --dport 400 -m recent --rcheck --name 1-1-4 -j 1-1-IN-5
/sbin/iptables  -A INPUT -i eth0 -p tcp -s ${NETWORK} --dport 22 -m recent --seconds 5 --rcheck --name 1-1-5 -j ACCEPT

# ---EOF GENERATED PART---

# ... etc.

Rules I used for generation of the pointed part of the above script were these:

NAME

if tcp/100,200,300,400 from \\${NETWORK} in INPUT on eth0 then

    in INPUT on eth0 open tcp/22 for 5
fi

You can easily change the IPTKnock script into generator with changing the beginning of it like this:

function ec () { echo '/sbin/iptables ' "$@" ; }
IPT=ec
### IPT=/sbin/iptables

Then source stored generated firewall rules in your firewalling script on a proper place.

Examples on how to use the horrible BASH script (I know, I am really very "lame" BASH coder, oh really, I know it so much) can be found in the same directory.

If somebody founds a bug, please, send it to me. I will repair the script for future use. Also if somebody will create much efficient "meta-language" to define the rules or even anything else concerning this topic, send it to me too. Send e-mails on iptknock@ligaturaPROTECTED.org -- remove the PROTECTED chain from the e-mail address. All ideas or thoughts are heartfuly welcome!

I hope it helps.

--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.

[ Parent | Reply to this comment ]

Posted by Anonymous (131.151.xx.xx) on Mon 3 Jul 2006 at 20:01
Just ran across this and I'm going to look into implementing. One thought I had was rewriting the ports used in the knock sequence each time to avoid replay attacks. More specifically, the user login would have sudo privileges to call a script to do such that would be part of the login scripts. The results would be echoed to the console for use with the next connection.

By using knocking across all ports and, say five, ports in the sequence it would be relatively immune from brute force, and the random factor protection from replay. Because the sequence is only regenerated on a successful login scanning can't DoS it.

Of course, this approach only works when you have one user for the rules set.

[ Parent | Reply to this comment ]

Posted by Anonymous (84.104.xx.xx) on Sun 11 Mar 2007 at 21:35
I suggest one should use a random order of the ports being used. I'm not able to test te script but as I can see a regular portscan wil trigger the port being opened.

A (default) portscan sends a SYN packet port by port from a low port number to a high port number. It reaches port 100 -> phase1, reaches 200 -> phase2, reaches 300 -> phase3 , phase 4 -> port opened.

If an attacker would do two portscans directly after each other they would 'see' the open port.

Am i wright? (sorry not able to test at the moment)

Piotr Popieluch
piotr (at) quicknet (dot) nl

[ Parent | Reply to this comment ]

Posted by Anonymous (193.64.xx.xx) on Fri 13 Apr 2007 at 07:27
Just add some triggers around those ports that remove all of the -m recent names. That way any port scan will knock on to those and wind up resetting the knock sequence.

[ Parent | Reply to this comment ]

Posted by Anonymous (89.38.xx.xx) on Wed 11 Jun 2008 at 14:25
Guys, is there a possibility to do it the other way around, if the client has an open port, than give him access?

[ Parent | Reply to this comment ]

Posted by Anonymous (213.41.xx.xx) on Thu 26 Mar 2009 at 15:55
There is no check on unwanted port during your sequence ( 4 successive nmap port scan open your port) .

[ Parent | Reply to this comment ]

Posted by Anonymous (74.78.xx.xx) on Fri 13 Nov 2009 at 22:18
Hello All,

I am newbie at iptables. My task is to perform port knocking. My iptables setting is following:

# Generated by iptables-save v1.3.8 on Wed Nov 4 12:28:16 2009
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [144:18414]
:Phase2 - [0:0]
:Phase3 - [0:0]
-A INPUT -m recent --update --name Port1 --rsource
-A INPUT -p tcp -m tcp --dport 1100 -m recent --set --name Port1 --rsource
-A INPUT -p tcp -m tcp --dport 2000 -m recent --rcheck --name Port1 --rsource -j Phase2
-A INPUT -p tcp -m tcp --dport 3000 -m recent --rcheck --name Port2 --rsource -j Phase3
-A INPUT -p tcp -m tcp --dport 22 -m recent --rcheck --seconds 600 --name Port3 --rsource
-A Phase2 -m recent --remove --name Port1 --rsource
-A Phase2 -m recent --set --name Port2 --rsource
-A Phase2 -j LOG --log-prefix "22222222"
-A Phase3 -m recent --remove --name Phase2 --rsource
-A Phase3 -m recent --set --name Port3 --rsource
-A Phase3 -j LOG --log-prefix "3333333333"
COMMIT
# Completed on Wed Nov 4 12:28:16 2009
-------------------------------------------------
Once i knock on specified ports with the help of knockd and then i run nmap for port scanning, it does not detects the ssh(port 22) service.
Please HELP me to get out of this PROBLEM....
I am running UBUNTU SERVER on VMWARE WORKSTATION.....

In order to set the iptables i am running the following script:
###################################
#! /bin/sh
echo Running port knocking script....
iptables -N Phase2
iptables -A Phase2 -m recent --name Port1 --remove
iptables -A Phase2 -m recent --name Port2 --set
iptables -A Phase2 -j LOG --log-prefix "22222222"
iptables -N Phase3
iptables -A Phase3 -m recent --name Phase2 --remove
iptables -A Phase3 -m recent --name Port3 --set
iptables -A Phase3 -j LOG --log-prefix "3333333333"
iptables -A INPUT -m recent --update --name Port1
iptables -A INPUT -p tcp --dport 1100 -m recent --set --name Port1
iptables -A INPUT -p tcp --dport 2000 -m recent --rcheck --name Port1 -j Phase2
iptables -A INPUT -p tcp --dport 3000 -m recent --rcheck --name Port2 -j Phase3
iptables -A INPUT -p tcp --dport 22 -m recent --rcheck --seconds 600 --name Port3
#####iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j REJECT
#################################

Thank you very much..

[ Parent | Reply to this comment ]

Posted by Anonymous (97.90.xx.xx) on Thu 27 Jan 2011 at 15:44
Can this be improved to only open the ports for the knocker's source IP?

[ Parent | Reply to this comment ]

Posted by Anonymous (89.181.xx.xx) on Sat 17 Sep 2011 at 01:20
It already does by design. --set adds the source address of the packet to the specified list, and --rcheck checks if the source address of the packet is on that list.

[ Parent | Reply to this comment ]

Sign In

Username:

Password:

[Register|Advanced]

 

Flattr

 

Current Poll

What do you use for configuration management?








( 822 votes ~ 10 comments )