Questions about this topic? Sign up to ask in the talk tab.

Port Knocking

From NetSec
Jump to: navigation, search

Introduction to Port Knocking

The definition of port knocking for this lesson is the method of externally opening ports on a computer that is otherwise closed. Port knocking is not just running nmap on a host and “knocking” on every port to see if it’s open.

Port knocking is a simple way to obfuscate, or hide ports from the outside world but still give you the freedom to connect back to your computer without needing to filter by IP addresses. Thus, if you’re mobile, you’ll still be able to connect.

We don’t want port 22 to be visible to the outside world, so we create a knocking sequence that will either open port 22 temporarily, or reverse ssh to the host that knows the secret handshake. This is also helpful for creating backdoors for those interested in that area. The knocking sequence is like a password in code, transmitted to the port, like morse code on a door.

A reverse connection is when the server connects to the client, as opposed to the client connecting to the server. This reverse connection method bypasses aspects of firewall security and other server based security. The server initialises the handshake and instead of the client sending packets to the server, the server sends packets to the client and by listening for those packets, the connection is started.

Knocking Sequences

Knocking sequences are limited to your imagination, it is simple and can be tested through downloading metasploit and analysing vulnerable linux via live cd. Sequences can be anything, for the first example: 1) 3 TCP ports hit in a certain order within 10 seconds, ports 1337, 31337 and 13375. The person knocking would use hping, nmap or a custom client to knock each of those ports in sequence, note that scanning other ports would disrupt this sequence.

Once these ports have been knocked in the correct sequence, the server lowers protection on the port or spawns a shell back. You can use netcat to bind a shell to an outgoing socket or use any of the other variations.


For windows, after you install nmap you will need to edit system variables, found here:

My Computer -> Properties -> Advanced Setting -> Environment variables -> System Variables

Once inside system variables, add nmap as a path there. This will make your command shell look in the nmap directory for any exes you try to run through it.


  • Requires: ";c:\Program Files\Nmap" in the path variable

When you type nmap.exe or nmap, it will search through the nmap directory for it, meaning you can be cded into any direction and still use nmap. An excellent resource is, it has a tonne of information as well as an easy tool to download and play with.

Single Packet Port Knock Example - Based on SYN/ACK Values

 * knock.c
 * Example compiler command-line for GCC:
 *   gcc -Wall -o knock knock.c -lpcap 
#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <unistd.h> 
#define DEBUG_APP
#ifdef DEBUG_APP
#define DEBUG(...) fprintf(stderr, __VA_ARGS__);
#define DEBUG(...)
/* default snap length (maximum bytes per packet to capture) */
#define MAX_CAP 1518
/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14
#define MAGIC_SEQ 0xdead
#define MAGIC_ACK 0xbeef
/* IP header */
struct sniff_ip {
        u_char  ip_vhl;                 /* version << 4 | header length >> 2 */
        u_char  ip_tos;                 /* type of service */
        u_short ip_len;                 /* total length */
        u_short ip_id;                  /* identification */
        u_short ip_off;                 /* fragment offset field */
        #define IP_RF 0x8000            /* reserved fragment flag */
        #define IP_DF 0x4000            /* dont fragment flag */
        #define IP_MF 0x2000            /* more fragments flag */
        #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
        u_char  ip_ttl;                 /* time to live */
        u_char  ip_p;                   /* protocol */
        u_short ip_sum;                 /* checksum */
        struct  in_addr ip_src,ip_dst;  /* source and dest address */
#define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
/* TCP header */
typedef u_int tcp_seq;
struct sniff_tcp {
        u_short th_sport;               /* source port */
        u_short th_dport;               /* destination port */
        tcp_seq th_seq;                 /* sequence number */
        tcp_seq th_ack;                 /* acknowledgement number */
        u_char  th_offx2;               /* data offset, rsvd */
#define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
        u_char  th_flags;
        #define TH_FIN  0x01
        #define TH_SYN  0x02
        #define TH_RST  0x04
        #define TH_PUSH 0x08
        #define TH_ACK  0x10
        #define TH_URG  0x20
        #define TH_ECE  0x40
        #define TH_CWR  0x80
        u_short th_win;                 /* window */
        u_short th_sum;                 /* checksum */
        u_short th_urp;                 /* urgent pointer */
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
void print_app_usage(char *app_name);
 * print help text
print_app_usage(char *app_name) {
	printf("Usage: %s [interface]\n", app_name);
	printf("    interface    Listen on <interface> for packets.\n");
 * dissect/print packet
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
	/* declare pointers to packet headers */
	const struct sniff_ip *ip;              /* The IP header */
	const struct sniff_tcp *tcp;            /* The TCP header */
	int size_ip;
	int size_tcp;
	unsigned int r_ack;
	unsigned int r_seq;
	/* define/compute ip header offset */
	ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
	size_ip = IP_HL(ip)*4;
	if (size_ip < 20) {
		DEBUG("* Invalid IP header length\n");
	/* determine protocol */	
	switch(ip->ip_p) {
	/* define/compute tcp header offset */
	tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
	size_tcp = TH_OFF(tcp)*4;
	if (size_tcp < 20) {
		DEBUG("* Invalid TCP header length\n");
	/* set ack and seq variables, then compare to MAGIC_ACK and MAGIC_SEQ */
	r_ack = ntohl(tcp->th_ack);
	r_seq = ntohl(tcp->th_seq);
	if (r_ack == MAGIC_ACK && r_seq == MAGIC_SEQ) {
	        DEBUG("magic packet received\n"); // do something, like remove iptables rule protecting a port for 30 seconds.
int main(int argc, char **argv) {
	char *dev = NULL;			/* capture device name */
	char errbuf[PCAP_ERRBUF_SIZE];		/* error buffer */
	pcap_t *handle;				/* packet capture handle */
	char filter_exp[] = "tcp";		/* filter expression [3] */
	struct bpf_program fp;			/* compiled filter program (expression) */
	bpf_u_int32 mask;			/* subnet mask */
	bpf_u_int32 net;			/* ip */
	int num_packets = 0;			/* Capture indefinitely */
	/* check for capture device name on command-line */
	if (argc == 2) {
		dev = argv[1];
	else if (argc > 2) {
		fprintf(stderr, "error: unrecognized command-line options\n\n");
	else {
		/* find a capture device if not specified on command-line */
		dev = pcap_lookupdev(errbuf);
		if (dev == NULL) {
			DEBUG( "Couldn't find default device: %s\n", errbuf);
	/* get network number and mask associated with capture device */
	if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
		DEBUG("Couldn't get netmask for device %s: %s\n", dev, errbuf);
		net = 0;
		mask = 0;
	/* print capture info */
	DEBUG("Device: %s\n", dev);
	DEBUG("Filter expression: %s\n", filter_exp);
	/* open capture device */
	handle = pcap_open_live(dev, MAX_CAP, 1, 1000, errbuf);
	if (handle == NULL) {
		DEBUG("Couldn't open device %s: %s\n", dev, errbuf);
	/* make sure we're capturing on an Ethernet device [2] */
	if (pcap_datalink(handle) != DLT_EN10MB) {
		DEBUG("%s is not an Ethernet\n", dev);
	/* compile the filter expression */
	if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
		DEBUG("Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
	/* apply the compiled filter */
	if (pcap_setfilter(handle, &fp) == -1) {
		DEBUG("Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
	/* now we can set our callback function */
	pcap_loop(handle, num_packets, got_packet, NULL);
	/* cleanup */
	return 0;