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.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
--
Tommy Butler
[ Parent | Reply to this comment ]
http://www.shorewall.net/PortKnocking.html
The more info the better!
[ Parent | Reply to this comment ]
--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.
[ Parent | Reply to this comment ]
Thanks would be great.
[ Parent | Reply to this comment ]
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 ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.
[ Parent | Reply to this comment ]
--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.
[ Parent | Reply to this comment ]
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 ]
[ Parent | Reply to this comment ]
--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.
[ Parent | Reply to this comment ]
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 ]
[ Parent | Reply to this comment ]
--
If you're smart enough to ask this question, you're smart enough to RTFM and find out yourself.
[ Parent | Reply to this comment ]
/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 ]
#!/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 ]
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 ]
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 ]
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 ]
[ Parent | Reply to this comment ]