diff options
Diffstat (limited to 'repos')
-rw-r--r-- | repos/dnsmap/CREDITS.txt | 10 | ||||
-rw-r--r-- | repos/dnsmap/Changelog.txt | 25 | ||||
-rw-r--r-- | repos/dnsmap/Makefile | 12 | ||||
-rw-r--r-- | repos/dnsmap/README.txt | 177 | ||||
-rw-r--r-- | repos/dnsmap/TODO.txt | 13 | ||||
-rwxr-xr-x | repos/dnsmap/dnsmap-bulk.sh | 19 | ||||
-rw-r--r-- | repos/dnsmap/dnsmap.c | 795 | ||||
-rw-r--r-- | repos/dnsmap/dnsmap.h | 1047 | ||||
-rw-r--r-- | repos/dnsmap/gpl-2.0.txt | 339 | ||||
-rw-r--r-- | repos/dnsmap/use_cases.txt | 10 | ||||
-rw-r--r-- | repos/dnsmap/wordlist_TLAs.txt | 17576 |
11 files changed, 20023 insertions, 0 deletions
diff --git a/repos/dnsmap/CREDITS.txt b/repos/dnsmap/CREDITS.txt new file mode 100644 index 0000000..5f19715 --- /dev/null +++ b/repos/dnsmap/CREDITS.txt @@ -0,0 +1,10 @@ +Main author: +pagvac (gnucitizen.org) + +Patches, bug hunting and general feedback: +Borys Lacki (www.bothunters.pl) +Philipp Winter (7c0.org) +meathive (kinqpinz.info) +David Kierznowski (withdk.com) +GNa (gnanet.net) +srl (security.research.labs@gmail.com) diff --git a/repos/dnsmap/Changelog.txt b/repos/dnsmap/Changelog.txt new file mode 100644 index 0000000..ba1b097 --- /dev/null +++ b/repos/dnsmap/Changelog.txt @@ -0,0 +1,25 @@ +20/02/2010: dnsmap 0.30 released at www.gnucitizen.org +* IPv6 support +* Makefile included +* delay option (-d) added. This is useful in cases where dnsmap is killing your bandwidth +* ignore IPs option (-i) added. This allows ignoring user-supplied IPs from the results. Useful for domains which cause dnsmap to produce false positives +* changes made to make dnsmap compatible with OpenDNS +* disclosure of internal IP addresses (RFC 1918) are reported +* updated built-in wordlist +* included a standalone three-letter acronym (TLA) subdomains wordlist +* domains susceptible to "same site" scripting (http://snipurl.com/etbcv) are reported +* completion time is now displayed to the user +* mechanism to attempt to bruteforce wildcard-enabled domains +* unique filename containing timestamp is now created when no specific output filename is supplied by user +* various minor bugs fixed + +22/02/2009: dnsmap 0.22 released at www.gnucitizen.org +* saving the results in human-readable and CSV format for easy processing +* fixed bug that disallowed reading wordlists with DOS CRLF format +* improved built-in subdomains wordlist +* new bash script (dnsmap-bulk.sh) included which allows running dnsmap against a list of domains from a user-supplied file. i.e.: bruteforcing several domains in a bulk fashion +* bypassing of signature-based dnsmap detection by generating a proper pseudo-random subdomain when checking for wildcards + +17/08/2006: dnsmap 0.1 (first public version) released at foro.elhacker.net +* bruteforcing based on builtin list and user-supplied wordlist +* obtain all available A records for each bruteforced (sub)domain (rather than only one) diff --git a/repos/dnsmap/Makefile b/repos/dnsmap/Makefile new file mode 100644 index 0000000..2393d37 --- /dev/null +++ b/repos/dnsmap/Makefile @@ -0,0 +1,12 @@ +CC=gcc +CFLAGS=-I. +BINDIR=/usr/local/bin + +dnsmap: dnsmap.c dnsmap.h + $(CC) $(CFLAGS) -o dnsmap dnsmap.c + +install: dnsmap + mkdir -p $(DESTDIR)$(BINDIR) + install -m 0755 dnsmap $(DESTDIR)$(BINDIR) + install -m 0755 dnsmap-bulk.sh $(DESTDIR)$(BINDIR)/dnsmap-bulk + diff --git a/repos/dnsmap/README.txt b/repos/dnsmap/README.txt new file mode 100644 index 0000000..beab0f2 --- /dev/null +++ b/repos/dnsmap/README.txt @@ -0,0 +1,177 @@ +INTRODUCTION + +dnsmap was originally released back in 2006 and was inspired by the +fictional story "The Thief No One Saw" by Paul Craig, which can be found +in the book "Stealing the Network - How to 0wn the Box" + +dnsmap is mainly meant to be used by pentesters during the information +gathering/enumeration phase of infrastructure security assessments. During the +enumeration stage, the security consultant would typically discover the target +company's IP netblocks, domain names, phone numbers, etc ... + +Subdomain brute-forcing is another technique that should be used in the +enumeration stage, as it's especially useful when other domain enumeration +techniques such as zone transfers don't work (I rarely see zone transfers +being *publicly* allowed these days by the way). + +If you are interested in researching stealth computer intrusion techniques, +I suggest reading this excellent (and fun) chapter which you can find for +*free* on the web: + +http://www.ethicalhacker.net/content/view/45/2/ + +I'm happy to say that dnsmap was included in Backtrack 2, 3 and 4 and has +been reviewed by the community: + +http://backtrack.offensive-security.com/index.php?title=Tools +http://www.networkworld.com/community/node/57543 +http://www.linuxhaxor.net/2007/07/14/backtrack-2-information-gathering-all-dnsmap/ +http://www.darknet.org.uk/2009/03/dnsmap-022-released-subdomain-bruteforcing-tool/ +http://www.gnucitizen.org/blog/new-version-of-dnsmap-out/ + + +COMPILING + +Compiling should be straightforward: + +$ make + +Or: + +$ gcc -Wall dnsmap.c -o dnsmap + + +INSTALLATION + +Example of manual installation: + +# cp ./dnsmap /usr/local/bin/dnsmap + +If you wish to bruteforce several target domains in bulk fashion, you can use the +included dnsmap-bulk.sh script. Just copy the script to /usr/local/bin/ so you can +call it from any location. e.g.: + +# cp ./dnsmap-bulk.sh /usr/local/bin/ + +And set execute permissions. e.g.: + +# chmod ugo+x /usr/local/bin/dnsmap-bulk.sh + + +LIMITATIONS + +Lack of multi-threading. This speed issue will hopefully be resolved in future versions. + + +FUN THINGS THAT CAN HAPPEN + +1. Finding interesting remote access servers (e.g.: https://extranet.targetdomain.com) + +2. Finding badly configured and/or unpatched servers (e.g.: test.targetdomain.com) + +3. Finding new domain names which will allow you to map non-obvious/hard-to-find netblocks + of your target organization (registry lookups - aka whois is your friend) + +4. Sometimes you find that some bruteforced subdomains resolve to internal IP addresses + (RFC 1918). This is great as sometimes they are real up-to-date "A" records which means + that it *is* possible to enumerate internal servers of a target organization from the + Internet by only using standard DNS resolving (as oppossed to zone transfers for instance). + +5. Discover embedded devices configured using Dynamic DNS services (e.g.: linksys-cam.com). + This method is an alternative to finding devices via Google hacking techniques + +USAGE + +Bruteforcing can be done either with dnsmap's built-in wordlist or a user-supplied wordlist. +Results can be saved in CSV and human-readable format for further processing. dnsmap does +NOT require root privileges to be run, and should NOT be run with such privileges for +security reasons. + +The usage syntax can be obtained by simply running dnsmap without any parameters: + +$ ./dnsmap + +dnsmap 0.30 - DNS Network Mapper by pagvac (gnucitizen.org) + +usage: dnsmap <target-domain> [options] +options: +-w <wordlist-file> +-r <regular-results-file> +-c <csv-results-file> +-d <delay-millisecs> +-i <ips-to-ignore> (useful if you're obtaining false positives) + +Note: delay value is a maximum random value. e.g.: if you enter 1000, each DNS request +will be delayed a *maximum* of 1 second. By default, dnsmap uses a value of 10 milliseconds +of maximum delay between DNS lookups + + +EXAMPLES +Subdomain bruteforcing using dnsmap's built-in word-list: + +$ ./dnsmap targetdomain.foo + +Subdomain bruteforcing using a user-supplied wordlist: + +$ ./dnsmap targetdomain.foo -w wordlist.txt + +Subdomain bruteforcing using the built-in wordlist and saving the results to /tmp/ : + +$ ./dnsmap targetdomain.foo -r /tmp/ + +Since no filename was provided in the previous example, but rather only a path, dnsmap would +create an unique filename which includes the current timestamp. e.g.: +/tmp/dnsmap_targetdomain_foo_2009_12_15_234953.txt + +Example of subdomain bruteforcing using the built-in wordlist, saving the results to /tmp/, +and waiting a random maximum of 3 milliseconds between each request: + +$ ./dnsmap targetdomain.foo -r /tmp/ -d 300 + +It is recommended to use the -d (delay in milliseconds) option in cases where dnsmap is +interfering with your online experience. i.e.: killing your bandwidth + +Subdomain bruteforcing with 0.8 seconds delay, saving results in regular and CSV format, +filtering 2 user-provided IP and using a user-supplied wordlist: + +$ ./dnsmap targetdomain.foo -d 800 -r /tmp/ -c /tmp/ -i 10.55.206.154,10.55.24.100 -w ./wordlist_TLAs.txt + +For bruteforcing a list of target domains in a bulk fashion use the bash script provided. e.g.: + +$ ./dnsmap-bulk.sh domains.txt /tmp/results/ + + +WORDLISTS + +http://packetstormsecurity.org/Crackers/wordlists/dictionaries/ +http://www.cotse.com/tools/wordlists1.htm +http://wordlist.sourceforge.net/ + + +OTHER SIMILAR TOOLS - choice is freedom! + +WS-DNS-BFX +http://ws.hackaholic.org/tools/WS-DNS-BFX.tgz + +DNSDigger +http://www.ernw.de/download/dnsdigger.zip + +Fierce Domain Scan +http://ha.ckers.org/fierce/ + +Desperate +http://www.sensepost.com/research_misc.html + +DNSenum +http://dnsenum.googlecode.com/files/dnsenum1.2.tar.gz + +ReverseRaider +http://complemento.sourceforge.net/ + +Knock +http://knock.gianniamato.it/ + + +-- +pagvac | GNUCITIZEN.org +Feb 2010 diff --git a/repos/dnsmap/TODO.txt b/repos/dnsmap/TODO.txt new file mode 100644 index 0000000..0df1368 --- /dev/null +++ b/repos/dnsmap/TODO.txt @@ -0,0 +1,13 @@ +* multi-threading - use pthread.h? +* can't handle wildcarded domains that return more than one IP address on non-existing subdomains + test domain: proboards.com +* allow using a customized list of DNS server to share network load +* allow using DNS server supplied on the command line +* for openDNS users: document how to permanently change DNS server settings so they are not overwritten by DHCP settings +* convert hostent structs to addrinfo ? +* replace inet_ntoa(*((struct in_addr *)host->h_addr_list[j])) with ipstr +* obtain aliases for each domain (CNAME records)? +* clever numerical domain bruteforce for clusters. i.e.: www2, www3 +* pickup new subdomains via reverse lookups (PTR records) +* better input validation + * improve function that validates target domain diff --git a/repos/dnsmap/dnsmap-bulk.sh b/repos/dnsmap/dnsmap-bulk.sh new file mode 100755 index 0000000..574aba2 --- /dev/null +++ b/repos/dnsmap/dnsmap-bulk.sh @@ -0,0 +1,19 @@ +#!/bin/bash +if [[ $# -ne 1 && $# -ne 2 ]] +then + echo "usage: `basename $0` <domains-file> [results-path]"; + echo "e.g.:"; + echo "`basename $0` domains.txt"; + echo "`basename $0` domains.txt /tmp/"; + exit +fi +for i in `cat $1` +do + if [[ $# -eq 1 ]] + then + dnsmap $i + elif [[ $# -eq 2 ]] + then + dnsmap $i -r $2 + fi +done diff --git a/repos/dnsmap/dnsmap.c b/repos/dnsmap/dnsmap.c new file mode 100644 index 0000000..5276e30 --- /dev/null +++ b/repos/dnsmap/dnsmap.c @@ -0,0 +1,795 @@ +/* + * ** dnsmap - DNS Network Mapper by pagvac + * ** Copyright (C) 2010 gnucitizen.org + * ** + * ** This program is free software; you can redistribute it and/or modify + * ** it under the terms of the GNU General Public License as published by + * ** the Free Software Foundation; either version 2 of the License, or + * ** (at your option) any later version. + * ** + * ** This program is distributed in the hope that it will be useful, + * ** but WITHOUT ANY WARRANTY; without even the implied warranty of + * ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * ** GNU General Public License for more details. + * ** + * ** You should have received a copy of the GNU General Public License + * ** along with this program; if not, write to the Free Software + * ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <netdb.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "dnsmap.h" // built-in subdomains list and define macros + + +// function prototypes +unsigned short int wildcarDetect(char *, char *); +unsigned short int dodelay(unsigned short int); +unsigned short int isPrivateIP(char *); +unsigned short int isValidDomain(char *); +unsigned short int usesOpenDNS(char *); +unsigned short int isIPblacklisted(char *); + +int main(int argc, char *argv[]) { + + unsigned short int i=0, j=0, k=0, l=0, found=0, ipCount=0, filtIPcount=0, milliseconds=10, intIPcount=0, + wordlist=FALSE, txtResults=FALSE, csvResults=FALSE, + delay=TRUE, filter=FALSE; + unsigned long int start=0, end=0; + char dom[MAXSTRSIZE]={'\0'}, csvResultsFilename[MAXSTRSIZE]={'\0'}, + txtResultsFilename[MAXSTRSIZE]={'\0'}, wordlistFilename[MAXSTRSIZE]={'\0'}, + ipstr[INET_ADDRSTRLEN]={'\0'}, wildcardIpStr[INET_ADDRSTRLEN]={'\0'}, + filterIPs[5][INET_ADDRSTRLEN]={{'\0'}}, + invalidTldIpstr[INET_ADDRSTRLEN]={'\0'}; + void *addr; + char *ipver, *strP; + + struct hostent *h; + // start of IPv6 stuff + struct addrinfo hints, *res, *p; + int status; + char ipv6str[INET6_ADDRSTRLEN]; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET6; // AF_INET or AF_INET6 to force version + hints.ai_socktype = SOCK_STREAM; + // end of IPv6 stuff + + FILE *fpWords,*fpCsvLogs,*fpTxtLogs; + + time_t now; + struct tm *ts; + char timestampBuf[18]; + + printf("%s", BANNER); + + // get the current time + now = time(NULL); + + // timestamp format: yyyy_mm_dd_hhmmss + ts = localtime(&now); + strftime(timestampBuf, sizeof(timestampBuf), "%Y_%m_%d_%H%M%S", ts); + + + // start of *primitive* input validation + // ideally more work should be spent on this! + if(argc==1) { + printf("%s%s", USAGE, EXAMPLES); + exit(1); + } + else if(argc%2==1 && argc>2) { + printf("%s%s", USAGE, EXAMPLES); + exit(1); + } + for(i=0;argv[1][i];++i) // convert domain to lower case + argv[1][i]=(tolower(argv[1][i])); + #if DEBUG + printf("domain: %s\n", argv[1]); + #endif + if(!isValidDomain(argv[1])) { + printf("%s", DOMAINERR); + exit(1); + } + + for(i=0;i<argc;++i) { + if((strlen(argv[i]))>MAXSTRSIZE) { + printf("%s",INPUTERR); + exit(1); + } + } + // end of simple input validation + + /* + else if ((h=gethostbyname(argv[1])) == NULL) { // get the host info + herror("gethostbyname"); + exit(1); + } + */ + + start=(int)time(NULL); + + #if DEBUG + printf("start time: %d\n", (int)start); + #endif + + // parse options + for(i=0;i<argc;++i) { + // save results in file using regular format + if(!strcmp(argv[i],"-r")) { + // contruct path where txt results file will be created + txtResults=TRUE; + //strncpy(csvResultsFilename, argv[(i+1)], MAXSTRSIZE); + strncpy(txtResultsFilename, argv[(i+1)], MAXSTRSIZE-strlen(txtResultsFilename)-1); + fpTxtLogs=fopen(txtResultsFilename, "a"); + if(!fpTxtLogs) { + strncat(txtResultsFilename, "dnsmap_", MAXSTRSIZE-strlen(txtResultsFilename)-1); + strncat(txtResultsFilename, argv[1], MAXSTRSIZE-strlen(txtResultsFilename)-1); + strncat(txtResultsFilename, "_", MAXSTRSIZE-strlen(txtResultsFilename)-1); + strncat(txtResultsFilename, timestampBuf, MAXSTRSIZE-strlen(txtResultsFilename)-1); + // replace dots '.' with underscores '_' in filename + for(l=0;l<strlen(txtResultsFilename);++l) + if(txtResultsFilename[l]=='.') + txtResultsFilename[l]='_'; + strncat(txtResultsFilename, ".txt", MAXSTRSIZE-strlen(txtResultsFilename)-1); + fpTxtLogs=fopen(txtResultsFilename, "a"); + if(!fpTxtLogs) { + printf(CREATEFILEERR); + exit(1); + } + } + } + + // save results in file using CSV format + if(!strcmp(argv[i],"-c")) { + // contruct path where CSV results file will be created + csvResults=TRUE; + strncpy(csvResultsFilename, argv[(i+1)], MAXSTRSIZE-strlen(csvResultsFilename)-1); + fpCsvLogs=fopen(csvResultsFilename, "a"); + if(!fpCsvLogs) { + strncat(csvResultsFilename, "dnsmap_", MAXSTRSIZE-strlen(csvResultsFilename)-1); + strncat(csvResultsFilename, argv[1], MAXSTRSIZE-strlen(csvResultsFilename)-1); + strncat(csvResultsFilename, "_", MAXSTRSIZE-strlen(csvResultsFilename)-1); + strncat(csvResultsFilename, timestampBuf, MAXSTRSIZE-strlen(csvResultsFilename)-1); + // replace dots '.' with underscores '_' in filename + for(l=0;l<strlen(csvResultsFilename);++l) + if(csvResultsFilename[l]=='.') + csvResultsFilename[l]='_'; + strncat(csvResultsFilename, ".csv", MAXSTRSIZE-strlen(csvResultsFilename)-1); + fpCsvLogs=fopen(csvResultsFilename, "a"); + if(!fpCsvLogs) { + printf(CREATEFILEERR); + exit(1); + } + } + } + + // use provided wordlist as opposed to built-in one + if(!strcmp(argv[i],"-w")) { + wordlist=TRUE; + strncpy(wordlistFilename, argv[(i+1)],MAXSTRSIZE); + } + + // delay between subdomain resolution requests + if(!strcmp(argv[i],"-d")) { + if(atoi(argv[(i+1)])<1 || atoi(argv[(i+1)])>300000) { // delay must be between 1 ms and 5 minutes + printf("%s", DELAYINPUTERR); + exit(1); + } + delay=TRUE; + milliseconds=atoi(argv[(i+1)]); + } + // filter out user-provided IP(s) + if(!strcmp(argv[i],"-i")) { + for(filtIPcount=1,j=0;argv[i+1][j]!='\0';++j) + if(argv[i+1][j]==',') + ++filtIPcount; + #if DEBUG + printf("%d IP(s) to filter found\nParsing ...\n", filtIPcount); + #endif + if(filtIPcount<=5) { + printf(FILTERMSG); + strP=strtok(argv[i+1],","); + for(j=0;strP;) { + if(strlen(strP)<INET_ADDRSTRLEN) { + strncpy(filterIPs[j],strP,INET_ADDRSTRLEN); + #if DEBUG + printf("%s\n",filterIPs[j]); + #endif + ++j; + } + strP=strtok(NULL," ,"); + } + } + else { + printf(FILTIPINPUTERR); + exit(1); + } + } + } + + // read subdomains from built-in list + if(!wordlist) { + // openDNS detection + if(usesOpenDNS(invalidTldIpstr)) + printf("%s",OPENDNSMSG); + + // wildcard detection + wildcarDetect(argv[1],wildcardIpStr); + + if(strcmp(invalidTldIpstr,wildcardIpStr)) + printf(WILDCARDWARN); + printf(BUILTINMSG); + if(milliseconds>=1) + printf(DELAYMSG); + + printf("%s", "\n"); + for(i=0;i<(sizeof(sub)/MAXSUBSIZE);++i) { + //skipResolve=FALSE; + strncpy(dom,sub[i],MAXSTRSIZE-strlen(dom)-1); + strncat(dom,".",MAXSTRSIZE-strlen(dom)-1);//TEST + strncat(dom,argv[1],MAXSTRSIZE-strlen(dom)-1); + #if DEBUG + printf("brute-forced domain: %s\n",dom); + #endif + + // ipv6 code modded from www.kame.net + status = getaddrinfo(dom, NULL, &hints, &res); + if ((status=getaddrinfo(dom, NULL, &hints, &res))==0) { + printf("%s\n", dom); + ++found; + if(txtResults) + fprintf(fpTxtLogs, "%s\n", dom); + if(csvResults) + fprintf(fpCsvLogs, "%s", dom); + for(p=res,k=0;p;p=p->ai_next,++k) { + if (p->ai_family==AF_INET6) { // IPv6 + struct sockaddr_in6 *ipv6=(struct sockaddr_in6 *)p->ai_addr; + addr = &(ipv6->sin6_addr); + ipver = "IPv6"; + } + // convert the IP to a string and print it: + inet_ntop(p->ai_family, addr, ipv6str, sizeof ipv6str); + printf("%s address #%d: %s\n",ipver,k+1,ipv6str); + ++ipCount; + if(txtResults) + fprintf(fpTxtLogs,"%s address #%d: %s\n",ipver,k+1,ipv6str); + if(csvResults) + fprintf(fpCsvLogs,",%s", ipv6str); + } + printf("%s", "\n"); + if(txtResults) + fprintf(fpTxtLogs,"\n"); + if(csvResults) + fprintf(fpCsvLogs,"\n"); + freeaddrinfo(res); // free the linked list + } // end of if conditional + h=gethostbyname(dom); + //sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[0])),"%s"); + //for(j=0;h->h_addr_list[j];++j) { + // sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[j])),"%s"); + // if(isIPblacklisted(ipstr)) { + // skipResolve=TRUE; + // break; + // } + //} + //if(h && !skipResolve) { + //if(h && !isIPblacklisted(ipstr)) { + if(h && !isIPblacklisted(inet_ntoa(*((struct in_addr *)h->h_addr_list[0])))) { + for(j=0;h->h_addr_list[j];++j) { + sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[j])),"%s"); + for(k=0;k<filtIPcount;++k) { + if(strcmp(filterIPs[k],ipstr)==0) { // filtered IP found + // 1st IP of array - weird output formatting bug + if(j!=0 && strcmp(wildcardIpStr,filterIPs[k])) { + printf("\n"); + if(txtResults) + fprintf(fpTxtLogs, "%s", "\n"); + if(csvResults) + fprintf(fpCsvLogs, "%s", "\n"); + } + #if DEBUG + printf("%s found and ignored\n",filterIPs[k]); + #endif + filter=TRUE; + if(h->h_addr_list[j+1]) + ++j; + else + break; + } + } + // END OF TEST + //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { + if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { + if(j==0) { + ++found; + printf("%s\n", dom); + + if(txtResults) + fprintf(fpTxtLogs, "%s\n", dom); + if(csvResults) + fprintf(fpCsvLogs, "%s", dom); + } + printf("[%d] %s : %s\n", j+1,dom,ipstr); + ++ipCount; + + if(isPrivateIP(ipstr)) { + //if(isPrivateIP(inet_ntoa(*((struct in_addr *)h->h_addr_list[j])))) { + printf("%s",INTIPWARN); + ++intIPcount; + } + if(!strcmp(ipstr,"127.0.0.1") && strcmp(wildcardIpStr,ipstr)) { + //if(!strcmp(inet_ntoa(*((struct in_addr *)h->h_addr_list[j])), + //"127.0.0.1")) + printf("%s",SAMESITEXSSWARN); + } + if(txtResults) { + //fprintf(fpCsvLogs,",%s", + // inet_ntoa(*((struct in_addr *)h->h_addr_list[j]))); + fprintf(fpTxtLogs,"IP address #%d: %s\n", j+1, ipstr); + if(isPrivateIP(ipstr) && strcmp(wildcardIpStr,ipstr)) + fprintf(fpTxtLogs,"%s",INTIPWARN); + if(!strcmp(ipstr,"127.0.0.1") && strcmp(wildcardIpStr,ipstr)) + fprintf(fpTxtLogs,"%s",SAMESITEXSSWARN); + } + if(csvResults && strcmp(wildcardIpStr,ipstr)) + fprintf(fpCsvLogs,",%s",ipstr); + } + } + //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { + if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { + printf("%s", "\n"); + if(txtResults) + fprintf(fpTxtLogs,"%s","\n"); + if(csvResults) + fprintf(fpCsvLogs,"%s","\n"); + } + filter=FALSE; + } + // user wants delay between DNS requests? + if(delay) + dodelay(milliseconds); + } + if(txtResults) + fclose(fpTxtLogs); + if(csvResults) + fclose(fpCsvLogs); + } + + // read subdomains from wordlist file + else if(wordlist) { + // openDNS detection + if(usesOpenDNS(invalidTldIpstr)) + printf("%s",OPENDNSMSG); + + // wildcard detection + wildcarDetect(argv[1],wildcardIpStr); + if(strcmp(invalidTldIpstr,wildcardIpStr)) + printf(WILDCARDWARN); + + fpWords=fopen(wordlistFilename, "r"); + if(fpWords) { + printf(EXTERNALMSG); + if(milliseconds>=1) + printf(DELAYMSG); + printf("%s","\n"); + + while(!feof(fpWords)) { + //strncpy(dom,"",MAXSTRSIZE-strlen(dom)-1); + for(i=0;i<strlen(dom);++i) + dom[i]='\0'; + fscanf(fpWords,"%100s",dom); // wordlist subdomain not allowed to be more than 100 chars + #if DEBUG + printf("lengh of dom: %d\n",strlen(dom)); + #endif + strncat(dom,".",MAXSTRSIZE-strlen(dom)-1); + strncat(dom,argv[1],MAXSTRSIZE-strlen(dom)-1); + + #if DEBUG + printf("brute-forced domain: %s\n",dom); + #endif + // ipv6 code modded from www.kame.net + status = getaddrinfo(dom, NULL, &hints, &res); + if ((status=getaddrinfo(dom, NULL, &hints, &res))==0) { + printf("%s\n", dom); + ++found; + if(txtResults) + fprintf(fpTxtLogs, "%s\n", dom); + if(csvResults) + fprintf(fpCsvLogs, "%s", dom); + for(p=res,k=0;p;p=p->ai_next,++k) { + void *addr; + char *ipver; + if (p->ai_family==AF_INET6) { // IPv6 + struct sockaddr_in6 *ipv6=(struct sockaddr_in6 *)p->ai_addr; + addr = &(ipv6->sin6_addr); + ipver = "IPv6"; + } + // convert the IP to a string and print it: + inet_ntop(p->ai_family, addr, ipv6str, sizeof ipv6str); + printf("%s address #%d: %s\n",ipver,k+1,ipv6str); + ++ipCount; + if(txtResults) + fprintf(fpTxtLogs,"%s address #%d: %s\n",ipver,k+1,ipv6str); + if(csvResults) + fprintf(fpCsvLogs,",%s", ipv6str); + } + printf("%s", "\n"); + if(txtResults) + fprintf(fpTxtLogs,"\n"); + if(csvResults) + fprintf(fpCsvLogs,"\n"); + + freeaddrinfo(res); // free the linked list + // ipv6 code modded from www.kame.net + } // end of if conditional + + h=gethostbyname(dom); + + if(h && !isIPblacklisted(inet_ntoa(*((struct in_addr *)h->h_addr_list[0])))) { + for(j=0;h->h_addr_list[j];++j) { + sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[j])),"%s"); + //TEST + for(k=0;k<filtIPcount;++k) { + if(strcmp(filterIPs[k],ipstr)==0) { // filtered IP found + // 1st IP of array - weird output formatting bug + if(j!=0 && strcmp(wildcardIpStr,filterIPs[k])) { + printf("\n"); + if(txtResults) + fprintf(fpTxtLogs, "%s", "\n"); + if(csvResults) + fprintf(fpCsvLogs, "%s", "\n"); + } + #if DEBUG + printf("%s found and ignored\n",filterIPs[k]); + #endif + filter=TRUE; + if(h->h_addr_list[j+1]) + ++j; + else + break; + } + } + // END OF TEST + + //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { + if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { + if(j==0) { + ++found; + printf("%s\n",dom); + + if(txtResults) { + //fprintf(fpCsvLogs,"%s",dom); + fprintf(fpTxtLogs,"%s\n",dom); + } + if(csvResults) { + //fprintf(fpCsvLogs,"%s",dom); + fprintf(fpCsvLogs,"%s",dom); + } + } + printf("IP address #%d: %s\n",j+1,ipstr); + ++ipCount; + + if(isPrivateIP(ipstr) && strcmp(wildcardIpStr,ipstr)) { + printf("%s",INTIPWARN); + ++intIPcount; + } + if(!strcmp(ipstr,"127.0.0.1") && strcmp(wildcardIpStr,ipstr)) + printf("%s",SAMESITEXSSWARN); + if(txtResults && strcmp(wildcardIpStr,ipstr)) { + fprintf(fpTxtLogs,"IP address #%d: %s\n",j+1,ipstr); + if(isPrivateIP(ipstr)) + fprintf(fpTxtLogs,"%s",INTIPWARN); + if(!strcmp(ipstr,"127.0.0.1")) + fprintf(fpTxtLogs,"%s",SAMESITEXSSWARN); + } + if(csvResults && strcmp(wildcardIpStr,ipstr)) + fprintf(fpCsvLogs,",%s",ipstr); + } + } + //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { + if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { + printf("%s", "\n"); + if(txtResults) + fprintf(fpTxtLogs,"%s","\n"); + if(csvResults) + fprintf(fpCsvLogs,"%s","\n"); + } + filter=FALSE; + } + // user wants delay between DNS requests? + if(delay) + dodelay(milliseconds); + } // end while() loop + fclose(fpWords); + } + else { + printf(OPENFILEERR); + exit(1); + } + if(txtResults) + fclose(fpTxtLogs); + if(csvResults) + fclose(fpCsvLogs); + } + + printf(RESULTSMSG4); + if(intIPcount>=1) + printf(RESULTSMSG1); + + if(txtResults) + printf(RESULTSMSG2); + if(csvResults) + printf(RESULTSMSG5); + + end=(int)time(NULL); + printf(RESULTSMSG3); + + return 0; +} + +// return true if domain wildcards are enabled +unsigned short int wildcarDetect(char *dom, char *ipstr) { + char strTmp[30]={'\0'},s[MAXSTRSIZE]={'\0'}; + unsigned short int i=0,n=0,max=0; + struct hostent *h; + + srand(time(NULL)); + max=rand()%20; + // max should be between 10 and 20 + if(max<10) + max=max+(10-max); + + // generate up to random 20 digits-long subdomain + // e.g. 06312580442146732554 + + for(i=0;i<max;++i) { + n=rand()%10; + sprintf(strTmp, "%d", n); + if(i==0) + strncpy(s,strTmp,MAXSTRSIZE-strlen(s)-1); + else + strncat(s,strTmp,MAXSTRSIZE-strlen(s)-1); + } + strncat(s,".",MAXSTRSIZE-strlen(s)-1); + strncat(s, dom,MAXSTRSIZE-strlen(s)-1); + #if DEBUG + printf("random subdomain for wildcard testing: %s\n",s); + #endif + + // random subdomain resolves, thus wildcards are enabled + h=gethostbyname(s); // replace with getaddrinfo() ? + if(h) { /* + for(i=0;h->h_addr_list[i];++i) { + */ + //sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[i])),"%s"); + sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[0])),"%s"); + #if DEBUG + printf("wildcard domain\'s IP address: %s\n",ipstr); + #endif + return TRUE; + } + else + return FALSE; +} + +// return number of milliseconds delayed +unsigned short int dodelay(unsigned short int maxmillisecs) { + unsigned short int n=0; + + srand(time(NULL)); + n=rand()%maxmillisecs; + ++n; + maxmillisecs=n; + #if DEBUG + printf("sleeping %d milliseconds ...\n",maxmillisecs); + #endif + usleep(maxmillisecs*1000); + + return maxmillisecs; +} + +// return true if IP addr is internal (RFC1918) +unsigned short int isPrivateIP(char *ip) { + + char classB[][8]={"172.16.","172.17.","172.18.","172.19.", + "172.20.","172.21.","172.22.","172.23.","172.24.", + "172.25.","172.26.","172.27.","172.28.","172.29.", + "172.30.","172.31."}; + + unsigned short int i=0,j=0; + size_t len = strlen(ip); + + // shortest: 0.0.0.0 - 8 chars inc \0 + // longest: 255.255.255.255 - 16 chars inc \0 + if(len<8 || len>16) + return 0; + // ip addr must have three period signs + for(i=0,j=0;i<len;++i) { + if(ip[i]=='.') + ++j; + } + if(j!=3 || ip[0]=='.' || ip[len-1]=='.') + return 0; + + // 10.0.0.0 - 10.255.255.255 (10/8 prefix) + if(strncmp(ip,"10.",3)==0) + return 1; + + // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) + else if(strncmp(ip,"192.168.",8)==0) + return 1; + + + else { + // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) + for(i=0;i<sizeof(classB)/8;++i) { + if(strncmp(ip,classB[i],7)==0) + return 1; + } + return 0; + } +} + +// return true if domain is valid, false otherwise +unsigned short int isValidDomain(char *d) { + + unsigned int i=0, j=0; + char *tld; + size_t len; + char strTmp[30]={'\0'},s[MAXSTRSIZE]={'\0'}; + unsigned short int n=0,max=0; + + struct hostent *h; + + if(strlen(d)<4) // smallest possible domain provided. e.g. a.pl + return 0; + if(!strstr(d,".")) // target domain must have at least one dot. e.g. target.va, branch.target.va + return 0; + tld=strstr(d,"."); + tld=tld+1; + while(strstr(tld,".")){ + tld=strstr(tld,"."); + tld=tld+1; + } + #if DEBUG + printf("tld\'s length: %d\n",strlen(tld)); + printf("dom: %s tld: %s\n",d,tld); + #endif + if((strlen(tld)<2) || (strlen(tld)>6)) // tld must be between 2-6 char. e.g. .museum, .uk + return FALSE; + + // valid domain can only contain digits, letters, dot (.) and dash symbol (-) + len = strlen(d); + for(i=0;i<len;++i) { + if (!(d[i] >= '0' && d[i] <= '9') && + !(d[i] >= 'a' && d[i] <= 'z') && + !(d[i] >= 'A' && d[i] <= 'Z') && + !(d[i] >= '-' && d[i] <= '.')) + return 0; + } + + srand(time(NULL)); + max=rand()%20; + // max should be between 10 and 20 + if(max<10) + max=max+(10-max); + + // generate up to random 20 digits-long subdomain + // e.g. 06312580442146732554 + + for(i=0;i<max;++i) { + n=rand()%10; + sprintf(strTmp, "%d", n); + if(i==0) + strncpy(s,strTmp,MAXSTRSIZE-strlen(s)-1); + else + strncat(s,strTmp,MAXSTRSIZE-strlen(s)-1); + } + strncat(s,".",MAXSTRSIZE-strlen(s)-1); + strncat(s, d,MAXSTRSIZE-strlen(s)-1); + #if DEBUG + printf("random subdomain for wildcard testing: %s\n",s); + #endif + + // some domains like proboards.com return more than 1 IP address + // when resolving random subdomains (wildcards are enabled) + h=gethostbyname(s); + if(h) { + for(j=0;h->h_addr_list[j];++j) + inet_ntoa(*((struct in_addr *)h->h_addr_list[j])); + if(j>1) { + #if DEBUG + + printf("wildcard domain\'s number of IP address(es): %d" + " (this causes dnsmap to produce false positives)\n", |