This is a system I implemented just for fun some time ago. Although the
code is functional and provides a mechanism similar to port knocking, I
did not implement the second phase and hence it is weaker than I
want it to be. I may implement the missing pieces if there is interest.
Introduction:
Often a secure system needs a port open so that only authorized persons
can access a particular service and also the service should not exposed to
attackers and worms that may use vulnerabilities that exist in the
listening server. Port knocking is designed to be used as a
complementary service to the existing authentication mechanism. But one of
the biggest problems with port knocking is manipulating the
firewall with timeouts. When the correct knock sequence is sent, the
firewall is modified for couple of seconds. Having the firewall open
automatically for a time period will make any system administrator
uncomfortable. TCP knocking attempts to solve the problem by
incorporating the knock into the TCP handshake. Tcp knocking is similar
to port knocking, but instead sending UDP packets with secret ports,
the TCP handshake packets must include secrete codes. It is at least as
secure as port knocking and it can be made secure with more hardening.
Modified
TCP handshake:
In normal TCP handshake, the client sends the syn packet and chooses a
random initial sequence number. The server responds with a packet that
has both syn and ack flags set, choosing a random
The modified TCP handshake uses the empty fields in the header. The
server does not respond to connection requests without a special code
generated along with the syn packet. The server also encrypts the
ISN in the ack packet (2) and the final packet of the three-way
handshake must have the correct acknowledgment for the servers ISN. The
system is further protected from brute-force attacks by closing the
connection if the first attempt for the third packet does not have the
expected acknowledgment sequence. Also, rather than use
conventional encryption techniques like HMAC for verification, this
system uses a file with random numbers as the key. This is
because of the limited unused space available in the TCP/IP header
which makes HMAC very weak. By using a shared file, the length of the
key can be much greater than traditional systems and even though some
parts of the key can be revealed by attacks, the server can protect
itself from replay attacks.
The handshake:
1) Syn
The syn packet does not use the 32 bit acknowledgment field in the TCP
header as it the the first packet to initiate the connection.
Further the 16 bit IPID can be used to transmit information. In the
current implementation only the 32 bit acknowledgment field is used.
Currently the 32 bit ack is derived from a 64 KB file which contains
random numbers. The ISN and the source IP address along with the random
numbers are used to generate this value.
2) Syn/Ack
The ISN is encrypted using the random numbers from the 64 KB file using
the destination IP address as well as a 16 bit random number used as
IPID. I do not have code for this part yet.
3) Ack
The client decrypts the syn number from the encrypted syn, the key
file, the 16 bit IPID and its own IP address and sends the ack packet.
The server closes all connections from the client for couple of minutes
if it sends a wrong ack value. Part of the security relies on the
fact that the ISN generated by Linux 2.6 is fairly random.
Implementation:
I have implemented only the first part, which is the server expecting
secret code along with the first syn packet from the client. Hence it
is
very possible to brute-force the server. Also the system is designed
with the second phase in mind, which is the encrypted Initial Sequence
Number in the ack packet and closing the connection if the correct ack
is not sent on the first try. I do not have an implementation for that
yet. The security will be increased greatly when the second phase is
incorporated. Also the ability to detect brute-force attacks can be
added to this system.
But the current system can be used for protecting the server from worms
and random scanning. The use-case is similar to port knocking but
it does not use the ugly system of opening the firewall for a couple of
seconds. Vanilla port knocking is susceptible to brute-force attacks as
well. Besides, inserting a kernel module to just ssh into your server
will increase your mad sysadmin points :)
Download:
Source: tcpknock.tar.bz
Contents:
/kernel - Files for the client and server kernel modules.
Edit the Makefile and point it to the source directory of the running
kernel and type make. This has to be done on both server and client if
they are running different versions of the kernel.
/iptables - This contains the extension module for
iptables. Again edit the makefile and point it to the iptables source
and do 'make'
/support - Type make for the key_gen. The keygen will
generate the key file that has to be copied to both the client and the
server. A sample firewall script is provided for the server.
Usage:
On the server:
1)
insmod
tcpknock-server.ko
It looks for the key file in
/etc/port_protector.dat. Optionally you can point the key file using
insmod tcpknock-server.ko file_name="full/path/to/keyfile"
2) Configure the iptables firewall as follows:
The firewall must allow only
established connections and reject all other packets.
Before the other rules pass
the syn packet through tcpknock module. See firewal.sh for example in
the support directory.
On the client:
insmod tcpknock-client.ko
The following parameters can be specified
file_name="full/path/to/keyfile"
nat_ip="ip address"
target_port="port number"
The nat_ip is used to specify the
IP address from which the server will be receiving the packet from (the
source IP in the packet)
The target port is the port for
which the modification will be applied. I did not want to filter by IP
address as I have more than 1 server to SSH into. The default port is
22. In the future the client will also be made as a netfilter module
with separate extension for iptables. Once that is in place, this
option will be removed.