int main(int argc, char **argv) { unsigned char buf[1024], buf2[1024]; char *ptr, *ptr2, nexthost[256], domain[256]; char b1[] = { 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; char b2[] = { 0x00, 0x2f, 0x00, 0x01 }; int pid = getpid(), dlen = 0, i = 0, fixi, len, ok = 1, cnt = 0, errcntbak, sub = 0; struct addrinfo hints, *res, *p; struct sockaddr_in6 *ipv6, *q; struct sockaddr_in *ipv4, *q4; char ipv4str[16], ipv6str[40]; void *addr, *addr4; setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); if (argc < 3) { printf("%s v1.2 (c) 2014 by Marc Heuse <*****@*****.**> http://www.mh-sec.de\n\n", argv[0]); printf("Syntax: %s [-e46] dns-server domain\n\n", argv[0]); printf("Options:\n -e ensure that the domain is present in found addresses, quit otherwise\n -4 resolve found entries to IPv4 addresses\n -6 resolve found entries to IPv6 addresses\n\n"); printf("Perform DNSSEC NSEC walking.\n\nExample: %s dns.test.com test.com\n", argv[0]); exit(0); } while ((i = getopt(argc, argv, "e46")) >= 0) { switch(i) { case 'e': ensure = 1; break; case '4': if (dores == -1) dores = AF_INET; else dores = 0; break; case '6': if (dores == -1) dores = AF_INET6; else dores = 0; break; default: fprintf(stderr, "Error: unknown option -%c\n", i); exit(-1); } } dst = argv[optind]; sock = dnssocket(dst); for (i = 0; i < strlen(argv[optind]); i++) argv[optind][i] = (char)tolower((int)argv[optind][i]); for (i = 0; i < strlen(argv[optind + 1]); i++) argv[optind + 1][i] = (char)tolower((int)argv[optind + 1][i]); if (index(argv[optind + 1], '.') == NULL) { fprintf(stderr, "Error: not a valid domain (must be at least \".\"): %s\n", argv[optind + 1]); exit(-1); } strncpy(domain, argv[optind + 1], sizeof(nexthost) - 2); domain[sizeof(domain) - 2] = 0; if (domain[strlen(domain) - 1] != '.') strcat(domain, "."); strncpy(nexthost, argv[optind + 1], sizeof(nexthost) - 1); nexthost[sizeof(nexthost) - 1] = 0; memcpy(buf, (char *) &pid + _TAKE2, 2); memcpy(buf + 2, b1, sizeof(b1)); i = 2 + sizeof(b1); fixi = i; if (dores >= 0) { memset((char*)&hints, 0, sizeof(hints)); hints.ai_family = dores; } printf("Starting DNSSEC walking on server %s about %s\n", dst, domain); while (ok == 1) { ptr = nexthost; i = fixi; // domain-encoded-here foo.com == \x03foo\x03com\x00 == dlen if (strcmp(ptr, ".") != 0) do { if ((ptr2 = index(ptr, '.')) != NULL) *ptr2 = 0; len = strlen(ptr); buf[i++] = len; memcpy(buf + i, ptr, len); i += len; dlen += (len + 1); ptr = ptr2; if (ptr != NULL) ptr++; } while (ptr != NULL && *ptr != 0); buf[i++] = 0; memcpy(buf + i, b2, sizeof(b2)); i += sizeof(b2); dlen = i; resend: if (send(sock, buf, dlen, 0) < 0) { fprintf(stderr, "Error: can not send to network\n"); exit(-1); } if (debug) { len = i; for (i = 0; i < len; i++) { if (i % 16 == 0) printf(" "); if (i % 8 == 0) printf(" "); printf("%02x ", buf[i]); if (i % 16 == 15) printf("\n"); } printf("\n\n"); } errcntbak = errcnt; signal(SIGALRM, noreply); alarm(5); memset(buf2, 0, sizeof(buf2)); len = recv(sock, buf2, sizeof(buf2), 0); alarm(0); if (sock == -1) sock = dnssocket(dst); if (len <= 0 && errcntbak == errcnt) errcnt++; if ((errcntbak != errcnt) && errcnt > 0 && errcnt <= RETRY) goto resend; if (RETRY < errcnt || len < 10) noreply(0); if ((buf2[3] & 9) == 9 || (buf2[3] & 15) == 2) { printf("Result: server not responsible for domain %s\n", nexthost); exit(1); } else if (buf2[3] == 5) { printf("Result: server does not support NSEC, dnssec walking not possible\n"); exit(1); } else if ((buf2[3] & 15) > 0) { printf("Result: unknown error (%d)\n", (buf2[3] & 15)); exit(1); } else if (buf2[7] != 1) { printf("Result: server does not support NSEC, dnssec walking not possible\n"); exit(1); } ptr = (char *) (buf2 + i); while (ptr < (char *) (buf2 + len) && *ptr != 0x2f) ptr++; ptr += 9; ptr2 = ptr + 1; i = *ptr; if (*ptr == 0) { ptr++; } else { while (i != 0) { ptr += i + 1; i = *ptr; *ptr = '.'; } } *ptr++ = '.'; *ptr = 0; if (*ptr2 != 0) { for (i = 0; i < strlen(ptr2); i++) ptr2[i] = (char)tolower((int)ptr2[i]); if (strcasecmp(ptr2, domain) == 0) ok = 2; else { if (sub == 1) { if (strcmp(firstsub, ptr2) == 0 || strcmp(beforesub, ptr2) == 0) { fprintf(stderr, "Error: loop detected (sub), aborting\n"); exit(-1); } } if (cnt != 0) { if ((ptr2[2 + strlen(ptr2)] & 2) == 2) { fprintf(stderr, "Warning: start of a sub domain: %s - following items can not be enumerated automatically (don't blame the tool, NSEC is broken. Brute force the next valid hostname and rerun the tool with hostname++.domain.)\n", nexthost); sub = 1; strcpy(beforesub, nexthost); strncpy(firstsub, ptr2, sizeof(firstsub) - 1); firstsub[sizeof(firstsub) - 1] = 0; } if (strcmp(ptr2, first) == 0 || strcmp(ptr2, nexthost) == 0) { fprintf(stderr, "Error: loop detected, aborting\n"); exit(-1); } strncpy(nexthost, ptr2, sizeof(nexthost) - 1); nexthost[sizeof(nexthost) - 1] = 0; } else { strncpy(nexthost, ptr2, sizeof(nexthost) - 1); nexthost[sizeof(nexthost) - 1] = 0; strcpy(first, nexthost); } if (ensure && strstr(nexthost, domain) == NULL) { fprintf(stderr, "Error: domain %s not found in result %s, exiting\n", domain, nexthost); exit(-1); } if (dores != -1) { if (getaddrinfo(nexthost, NULL, &hints, &res) == 0) { printf("Found: %s", nexthost); q = NULL; q4 = NULL; for (p = res; p != NULL; p = p->ai_next) { if (p->ai_family == AF_INET6) { // IPv6 ipv6 = (struct sockaddr_in6 *) p->ai_addr; addr = &(ipv6->sin6_addr); // convert the IP to a string and print it: if (q == NULL || memcmp(&ipv6->sin6_addr, &q->sin6_addr, 16) != 0) { q = ipv6; inet_ntop(p->ai_family, addr, ipv6str, sizeof ipv6str); printf(" => %s", ipv6str); } } else if (p->ai_family == AF_INET) { ipv4 = (struct sockaddr_in *) p->ai_addr; addr4 = &(ipv4->sin_addr); if (q4 == NULL || memcmp(&ipv4->sin_addr, &q4->sin_addr, 4) != 0) { q4 = ipv4; inet_ntop(p->ai_family, addr4, ipv4str, sizeof ipv4str); printf(" => %s", ipv4str); } } } printf("\n"); freeaddrinfo(res); // free the linked list } else printf("Found: %s\n", nexthost); } else printf("Found: %s\n", nexthost); cnt++; errcnt = 0; } } else ok = 0; if (ok == 0) { for (i = 0; i < len; i++) { if (i % 16 == 0) printf(" "); if (i % 8 == 0) printf(" "); printf("%02x ", buf2[i]); if (i % 16 == 15) printf("\n"); } printf("\n"); } } if (ok == 2) printf("Done, %d entries found.\n", cnt); close(sock); if (ok == 2) return 0; else return -1; }
int main(int argc, char *argv[]) { unsigned char *ptr, *ptr2, *dest, range_start = 0;; int i, j, k, ok; setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); prg = argv[0]; if (argc < 3) { printf("%s %s (c) 2013 by %s %s\n\n", prg, VERSION, AUTHOR, RESOURCE); printf("Syntax: %s dns-server ipv6address\n\n", argv[0]); printf("Performs a fast reverse DNS enumeration and is able to cope with slow servers.\n"); printf("Examples:\n"); printf(" %s dns.test.com 2001:db8:42a8::/48\n", argv[0]); printf(" %s dns.test.com 8.a.2.4.8.b.d.0.1.0.0.2.ip6.arpa\n", argv[0]); exit(0); } if (getenv("THC_IPV6_PPPOE") != NULL || getenv("THC_IPV6_6IN4") != NULL) printf("WARNING: %s is not working with injection!\n", argv[0]); if (strcmp(argv[1], "-d") == 0) { debug = 1; argv++; argc--; } dst = argv[1]; ptr = argv[2]; srand(time(NULL) + getpid()); memset(range, 0, sizeof(range)); memset(buf, 0, sizeof(buf)); memset(buf_start, 0, sizeof(buf_start)); memset(buf_end, 0, sizeof(buf_end)); ok = 1; if ((*ptr != '.') && (index((char*)(uintptr_t)ptr, '.') != NULL) && ((ptr2 = (unsigned char*)(uintptr_t)strcasestr((char*)(uintptr_t)ptr, ".ip6.arpa")) != NULL)) { *ptr2 = 0; for (i = strlen(ptr) - 1; i >= 0 && ok == 1; i--) { if ((ptr[i] >= 'A' && ptr[i] <= 'F') || (ptr[i] >= 'a' && ptr[i] <= 'f') || (ptr[i] >= '0' && ptr[i] <= '9')) { range[range_start++] = (char) tolower(ptr[i]); if (i >= 2) { if (ptr[i - 1] != '.') ok = 0; else i--; } } else ok = 0; } } else if (index(ptr, ':') != NULL && (ptr2 = index(ptr, '/')) != NULL) { *ptr2++ = 0; len = atoi(ptr2); if (len % 4 > 0 || len < 4 || len > 124) { fprintf(stderr, "Error: invalid prefix length, must be a multiple of 4!\n"); exit(-1); } if (len < 48) fprintf(stderr, "Warning: prefix length is smaller than 48, usually this does not work.\n"); if (len % 8 > 0) j = (len / 8) + 1; else j = len / 8; if ((dest = thc_resolve6(ptr)) == NULL) { fprintf(stderr, "Error: %s gives not a valid IPv6 address\n", ptr); exit(-1); } for (i = 0; i < j; i++) { range[i * 2] = tohex(dest[i] / 16); range[i * 2 + 1] = tohex(dest[i] % 16); } range_start = len / 4; } else ok = 0; if (ok == 0) { fprintf(stderr, "Error: invalid IPv6 address specified: %s\n", argv[2]); exit(-1); } memset(buf_start, 0, sizeof(buf_start)); memset(buf_end, 0, sizeof(buf_end)); buf_start[2] = 1; buf_start[5] = 1; memcpy(buf, buf_start, sizeof(buf_start)); buf[12] = 1; buf_end[0] = 3; strcpy(buf_end + 1, "ip6"); buf_end[4] = 4; strcpy(buf_end + 5, "arpa"); buf_end[11] = 0x0c; buf_end[13] = 1; signal(SIGALRM, ignore); printf("Starting DNS reverse enumeration of %s on server %s\n", ptr, dst); // first: wildcard check ok = 0; k = 0; sock = dnssocket(dst); for (j = 0; j < 5; j++) { for (i = range_start; i < 32; i++) range[i] = tohex(rand() % 16); switch(send_range()) { case 0: ok++; break; case -1: k++; break; default: i = 0; // ignored } } if (ok > 2) { fprintf(stderr, "Error: Wildcard configured in DNS server, not possible to enumerate!\n"); return -1; } if (k == 5) { fprintf(stderr, "Error: DNS server %s sent no replies!\n", dst); return -1; } else if (k > 0) waittime += 2; // starting the search i = deeper(range_start); printf("Found %d entr%s.\n", found, found == 1 ? "y" : "ies"); if (found == 0) return 1; else return 0; }