
|
about
firewall primer details knock lab download implementations documentation FAQ images resources contact
The port knocking Perl prototype is licensed under the GPL license.
GPL License
![]() |
Details of Port Knocking MechanismPerl prototype: v0.30
2004-Nov-14 18:59 | ...more new Net::Pcap support added to sniff packets directly ...more
Once you've perused the firewall primer, learn about the details of port knocking here. Ideas about how to use port knocking in simple situations are presented, as well as an outline of how to use encryption to avoid eavesdropping.
applicationThis section provides some examples of how port knocking can be used to increase the security of a hypothetical networked host. Try using the Knocking Lab to construct your own port knocks. The main strength of port knocking is the facility to close all ports to all incoming IP addresses, while maintaining a mechanism of establishing a connection using a proper knock sequence. Risks associated with application vulnerabilities are mitigated if ports remain closed and are opened only by legitimate users. Quite a bit of the examples below are taken from the article in SysAdmin magazine (June, 2003). opening ssh (tcp/22) with a simple knock sequenceSuppose you have a networked system and you need to connect using ssh. Telnet has finally become taboo, and the use of ssh is wide spread. Since ssh can itself provide a tunnel for various ports, it is sufficient to use this single application for user sessions. If you have a host which is not running any public network service (mail, web, etc) you can maximally protect this host by closing all privileged and all well-known ports. To close these ports using IPCHAINS, the following commands need to be issued. ipchains -p tcp -s 0/0 -d FIREWALL/32 -p 0:1023 -j DENY -l ipchains -p tcp -s 0/0 -d FIREWALL/32 -p 1024:49151 -j DENY This will cause ports 0-1023 to refuse any TCP connections, without sending ICMP error packets back to the client. The IP of the networked host is Feb 12 00:13:26 ... input DENY ... CLIENT:64137 FIREWALL:102 ... Feb 12 00:13:27 ... input DENY ... CLIENT:64138 FIREWALL:100 ... Feb 12 00:13:27 ... input DENY ... CLIENT:64139 FIREWALL:100 ... Feb 12 00:13:28 ... input DENY ... CLIENT:64140 FIREWALL:103 ... A daemon monitoring the log file can detect these connection attempts to ports 102, 100, 100, 103 from the same IP address. This particular port sequence could trigger the daemon toopen port ssh (tcp/22). The daemon would execute the following command ipchains -I input -p tcp -s CLIENT/32 -d FIREWALL/32 22 -j ACCEPT Another sequence can be used to close the port. For example, 103, 100, 100, 102 could be used to trigger the deletion of the rule that was dynamically created to allow ipchains -D input -p tcp -s CLIENT/32 -d FIREWALL/32 22 -j ACCEPT In this example, a remote user has opened port ssh (tcp/22) to IP address CLIENT by making TCP connections to ports 102, 100, 100, 103 and subsequently closed the ssh (tcp/22) port to their IP by knocking on ports 103, 100, 100, 102. Encrypted Port KnocksThe 4-port knocks in the previous example provided limited protection against packet sniffing, since the knock was independent of the connecting IP address. Anyone on the network looking at packets could reconstruct the sequence and use it to gain access to the ssh (tcp/22) port. In order to reduce the risk of the knock being deconstructed and gainfully executed by a third-party, it should contain the client IP address and be encrypted. For example, the knock could be comprised of the following IPb1, IPb2, IPb3, IPb4, PORT, TIME, CHECKSUM where IPbx is the x byte of the IP address to which port PORT will be opened for TIME minutes. Using the IP address in the knock allows you to open the port to an arbitrary IP address, not just the one initiating the knock. For example, to open port ssh (tcp/22) for 15 minutes for the IP address 142.103.205.1 the knock would be comprised of 142, 103, 205, 1, 22, 15, 233 The final CHECKSUM field provides validation of a proper knock sequence and can be defined as CHECKSUM = (IPb1+IPb2+...+TIME) mod 255 In the above example, the check sum is 488 mod 255 = 233. The 7 digits (in the range 0-255; thus, these are bytes or chars) making up the knock can be encrypted using some appropriate method (e.g. DES, Blowfish, RSA), or a one time pad for maximum security. I'll talk about one time pads later. The client would carry out the following steps encrypt(KNOCK) = KNOCK_ENCRYPTED encode(KNOCK_ENCRYPTED) = KNOCK_ENCRYPTED_ENCODED where the
KNOCK_ENCRYPTED = decode(KNOCK_ENCRYPTED_ENCODED)
KNOCK = decrypt(KNOCK_ENCRYPTED)
OK = verify_checksum(KNOCK)
to every incoming sequence. If the sequence was malformed, the DECRYPT step would fail. If the sequence was successfully decrypted, the CHECKSUM would have to match in order for the sequence to be passed. Encrypting with PerlI'll show an example of using Perl to encrypt and decrypt a port knock sequence. The module The first thing to do is create a cipher object using use Crypt::CBC; # keyphrase for the encryption use constant KEY => "knock"; # encryption algorithm use constant CIPHER => "Blowfish"; my $cipher = Crypt::CBC->new({key => KEY, cipher => CIPHER, iv => "01234567", prepend_iv => 0}); Now that a cipher is prepared, the a list of values can be encrypted. Let's use the list (142,103,205,1,22,15) as from the example above. # create the knock payload array my @data = (142,103,205,1,22,5); # compute checksum and push it onto the data array push(@data,sum(@data) % 255); # @data = (142, 103, 205, 1, 22, 15, 233) # pack the data into a string (assume array elements are unsigned chars) my $ciphertext = $cipher->encrypt(pack("C*",@data)); # unpack the ciphered data into unsigned chars my @cipherpack = unpack("C*",$ciphertext); # create the knock sequence by mapping to ports PORTMIN ... PORTMIN+255 my @knocks = map {PORTMIN+$_} @cipherpack; # @knocks = (966, 914, 795, 964, 831, 862, 807, 932) Decrypting the knock sequence requires the creation of a cipher and the knowledge of the proper password and algorithm. Given the encrypted knock sequence (966, 914, ..., 932), first the sequence is mapped back to the range 0-255 and then it is decrypted.
my @knocks_unmapped = map {$_-PORTMIN} @knocks;
# @knocks_unmapped = (221, 169, 50, 219, 86, 117, 62, 187)
my $ciphertext = pack("C*",@knocks_unmapped);
my @knocks_decrypted = unpack("C*",$cipher->decrypt($ciphertext));
# @knocks_decrypted = (142, 103, 205, 1, 22, 15, 233)
Encrypting 7 numbers produces an 8 digit knock sequence. Remember that initialization vector I talked about above? Let's implement an IV and see how it changes the knock sequence. In this case, the IV will be a random 4 digit number.
my $iv_vector = join("",map{1+int(rand(9))} (1..4));
my $cipher = Crypt::CBC->new({key => KEY,
cipher => CIPHER,
iv => $iv_vector,
prepend_iv => 0});
Given the same knock payload as before, (142, 103, 205, 1, 22, 15, 233), here are some encrypted knock sequences for various initialization vectors.
initialization vector: 9137
knock sequence [20 knocks]: 827 842 855 845 856 854 818 831 802 794
796 800 767 851 762 822 761 930 820 947
initialization vector: 7836
knock sequence [20 knocks]: 827 842 855 845 856 854 818 831 800 801
796 799 866 995 802 848 930 925 755 905
initialization vector: 1248
knock sequence [20 knocks]: 827 842 855 845 856 854 818 831 794 795
797 801 807 997 829 914 879 976 963 872
As promised, the encrypted sequence is different if different IV values are used. The use of an IV increases the size of the knock sequence to 16+n for an IV of length n (e.g., an 8 digit IV will create a 24 digit knock sequence).
initialization vector: 64999848
knock sequence [24 knocks]: 827 842 855 845 856 854 818 831 799 797
802 802 802 801 797 801 846 813 993 931
798 972 951 928
last updated 2005-Aug-03 13:39
|




