pax_global_header00006660000000000000000000000064143172012270014511gustar00rootroot0000000000000052 comment=df901c43b592f4216c87be661bb517c7aa964ccb dnsenum2-1.3.1/000077500000000000000000000000001431720122700132465ustar00rootroot00000000000000dnsenum2-1.3.1/INSTALL.txt000077500000000000000000000013621431720122700151220ustar00rootroot00000000000000##You need Perl, it's installed on KALI Linux and on most other Linux's by default. ##To install missing Perl modules, first install cpanminus (as root): debian: apt-get install cpanminus centos: yum install cpan curl -L http://cpanmin.us | perl - App::cpanminus ##Then: root@kali:~# cpanm String::Random Net::Netmask XML::Writer --> Working on String::Random Fetching http://www.cpan.org/authors/id/S/SH/SHLOMIF/String-Random-0.25.tar.gz . .. OK Configuring String-Random-0.25 ... OK Building and testing String-Random-0.25 ... OK Successfully installed String-Random-0.25 1 distribution installed Mac Os X ======== perl -MCPAN -e shell ## and then type something like: install String::Random ANd just type enter when you're asked something ;) dnsenum2-1.3.1/Makefile000077500000000000000000000007241431720122700147140ustar00rootroot00000000000000.PHONY: default default: pod2man dnsenum.pl > dnsenum.1 .PHONY: install install: if [ "$${INSTALL_DEPS:-1}" = "1" ]; then \ cpan install XML::Writer Net::Netmask Net::IP Net::DNS Net::Whois::IP HTML::Parser WWW::Mechanize String::Random; \ fi install -D -m 644 dns.txt -t $(DESTDIR)/usr/share/dnsenum/ install -D -m 644 dnsenum.1 -t $(DESTDIR)/usr/share/man/man1/ install -D -m 755 dnsenum.pl $(DESTDIR)/usr/bin/dnsenum .PHONY: clean clean: rm -f dnsenum.1 dnsenum2-1.3.1/README.md000077500000000000000000000043231431720122700145320ustar00rootroot00000000000000# DNSENUM2 [![Rawsec's CyberSecurity Inventory](https://inventory.rawsec.ml/img/badges/Rawsec-inventoried-FF5050_flat.svg)](https://inventory.rawsec.ml/tools.html#dnsenum2) README - dnsenum2.pl VERSION: 1.3.0 multithreaded perl script to enumerate DNS information of a domain and to discover non-contiguous ip blocks. ## OPERATIONS: 1. Get the host's addresse (A record). 2. Get the nameservers (threaded). 3. Get the MX record (threaded). 4. Perform axfr queries on nameservers and get BIND VERSION (threaded). 5. Get extra names and subdomains via google scraping (google query = "-www site:domain"). 6. Brute force subdomains from file, can also perform recursion on subdomain that have NS records (all threaded). 7. Calculate C class domain network ranges and perform whois queries on them (threaded). 8. Perform reverse lookups on netranges ( C class or/and whois netranges) (threaded). 9. Write to domain_ips.txt file ip-blocks. ## PREREQUISITES: ###### Note: the make file will install these automatically. - Modules that are included in perl 5.28.0: - Getopt::Long - IO::File - Thread::Queue - Other Necessary modules: - Must have: - Net::IP - Net::DNS - Net::Netmask - String::Random - Optional: - Net::Whois::IP - HTML::Parser - WWW::Mechanize - XML::Writer ## INSTALLATION: 1. To install a module, simply run (as root): - debian:`apt-get install cpanminus` - centos: `yum install cpan` - other:`curl -L http://cpanmin.us | perl - App::cpanminus` 2. Run make file - `make`: Create Manpages - `make install`: Install files in the correct folder - This will create a direct callable `dnsenum` file from commandline. - `dns.txt` file will be loaded from `/usr/share/dnsenum/dns.txt`. (Note the -f switch will take precedence over this file) ## ADDITIONAL INFORMATION: OPTIONS:`perldoc dnsenum.pl` ## CHANGELOG Changelog from version 1.3.0 - Makefile addition - Dynamic DNS.txt reading - Additional DNS.txt entries - Fixed deprecated `allinurl` - Changed `out` to `output` as mentioned in the docs Special thanks to all Original Perl developers. [Filip Waeytens](mailto:filip.waeytens@gmail.com)
[tix tixxDZ](mailto:tixxdz@gmail.com) dnsenum2-1.3.1/dns.txt000077500000000000000000000314561431720122700146070ustar00rootroot00000000000000* 1003 1025 1027 1029 1037 1044 1066 1070 1071 1075 1082 1088 11 1106 1107 1108 1114 1115 1116 112sos 1167 1168 1178 1180 1184 1187 1189 1198 1203 1204 121 1211 1216 131 132 133 134 135 154 155 198 2005 214 223 226 228 232 25 265 27 270 28 29 30 30days 33 34 36 37 417 419 434 437 448 45 453 46 475 479 486 491 50 502 51 517 528 53 532 54 541 557 56 561 593 595 598 599 605 607 616 624 625 629 630 648 664 669 67 684 7 714 727 729 731 75 763 775 79 805 806 859 861 881 925 948 951 953 958 959 96 969 97 976 977 980 99 992 996 997 999 RKW-ONAFTS-TEST _sip _spf _tls a a-servers abc about accept accept-kbo-bce-select accept-kbo-bce-wi access accountrequest accounts acg aco acp1 act adl admin adminer administrador administrator ads adserver adsl afa afcn affaires-etrangeres affaires-sociales affairesetrangeres affairessociales afigp afnorth africa afs-nafsd afsca afsca-favv afsca2006 afsouth agencedespensions agent ags3 aigpol aiiz air aircraft airiz airn airramstein airtest alaune albert-2 albert-II albert-deux albert-twee albert2 albertdeux albertii alberttwee allocationsfamiliales ambtenaar ambtenaren ambtenarenzaken america animal-diseases animaldiseases antartica anthrax antiracisme aoot-servers aoss ap apod-kaia apps arbeid archive arcweb arp arrc arthur asc asia atlantic attest attest-acc attest-test auditinternetresorerie australia autodiscover av avatar b-fast b-servers bacillusanthracis backup badc banquecarrefour bart bc bc1 bce bcss bcss-ksz bdsrvns01 be belac beldonor belgacom belgica belgie belgien belgique belgium belgoeurop belgopocket bellis belmed belmed-acc belmed-dev belspo beroepsziekten beschaeftigung bestat beta betula bfab bfast bihdr bijzonderbeschermingsfonds binnenland binnenlandse-zaken binnenlandsezaken biodiversity biosafety birb birbdev birbtest blog boite-postale boitepostale boot-servers border1 br bram brite britetw britetwais bse budget budget-federal budgetenbeheerscontrole budgetfederal bugs buildingsagency buitenland buitenlandse-handel buitenlandse-zaken buitenlandsehandel buitenlandsezaken c caami caami-hziv cabinet cadps-login cadps-nt cadpsdev-login cadpsdev-nt caoc-find caoc1 caoc5 caoc7 caoc8 caocbalk caocf caocpr cap capac capac-hvw capelo captest ccdd ccdd-ccdv ccdv ccecrb ccvd cdvupensioenen census census2011 centredexpertise cepma cerva cfdd cfdd-frdo cgs2 cgs4 cgs5 channel cidd cidh cimicgs cimire cipal cisgr cisteam1 cisteam3 citrix civielebescherming civilservice class classical-swine-fever classicalswinefever claude cld client climat climateregistry clo clubdevenise clubofvenice cmlag cmn-bw-bru cnrcsa coda coda-cerva codacerva coedat coeurnelle-mail combuysse cominformatics commerce-exterieur commerceexterieur commissionjeuxhasard communication communications commz conformity conseil-etat conseildetat consetat conventioneu conventionue cooperation coot-servers copieconforme councilofstate cpas cprr csf csipme csl-uncl-pdc cslo cspm ctc customs cvts cwid d dau dav davo deambachten deambachten-acc debtagency demadelief dev development developpement dfi di diehandwerker diehandwerker-acc dienstenrichtlijn dienstleistungsrichtlinie dierenziekten dioxin dioxine dioxines diplobel diplomatie directiveservices directory dmz dmz-2 dns dns0 dns1 dns1w dns2 dns3 dnsintera dnsinterb dnsmaster docufin documentadministratifunique dofi doot-servers dosz dosz-ossom doszserver doteu drupal dummy dwti e e2e e3a ebr ebr-acc ecodata ecodoc ecolabel economie economie2 economiesociale ecops ed ed-dau edateng edatenq edatenq-acc eddau eensluidendverklaring ehealth ehealth-it eiss eisz eiz7iu9g election electionresults elections electionssociales elisabeth emc emetro emetro-acc emploi employment energie eng-tx engtx2 enigdocument enquete environment eoot-servers epatras eportal era-nova eranova ere-nova erenova erhebung es esb esp espacenet etudiantautravail eu2010 euconventie euconvention eudir eurdir euro europe exbmy exc exctest ext ext1 ext2 extern extranet f fanc fanc2 fao faofat fat fatfao favv favv-afsca favv2006 fbk fbz fbz-fmp fchd fcmd fdsrvns02 fedasil fedasilantartica fedict fedpol fedpolfed femmeetpension fernandez ffe file fin finance finances financien finanzen finderup finform fisconet fiscus flr-stat fmp fmp-fbz fonction-publique fonctionnaire fonctionnaires fonctionpublique fondsdevieillissement fondsspecialdeprotection foodsafety foot-servers foracs forensic forensics forfeit form fortar3 fortar3-acc forum forums fr fra frdo frdo-cfdd fs fs1 fso fsoffe ftp ftps ftpserver fugazi fytoweb g g01 g02 galahad gamingcommission gas2020gaz gaz2020 ge-nl geh\228lter gehaelter gehalter gemsz genootschap gesundheit gezondheid gfmd-fmmd gimli globalisatindebate goot-servers gr grc griep grippe grippeaviaire guideweb gwydion handicap haw hawk headlines health hermes hfa hkiv hms hog-cholera hogcholera hoot-servers horizon host hq hrf hrf-m hrf-mobile hrf-mobile-main hrf-stat hrf-static hrfd hrfd-main hrfl hrzkmo http https hvkz hvkz-cspm hvw hvw-capac hziv hziv-caami ia ib ibz ibzbb ibzdgip ibzkcl icdo ichr icn-inr icops ict-ssl ictc ictctest icte ida idav ids iefa iefh ies iev iev-ivk ievivk iewm ifa ifa-ofo ifaofo igvm ijhq illegale-arbeid imail imcd1 imcd2 imcd3 inami inami-riziv inasti inasti-rsvz incc ine info-shop infogsm infomail infosec infoshop infoshopping infrastructure infrastructuur inig inpectiondesfinances inr-icn inrct inspectievanfinancien inspectiondesfinances install interieur intern interneauditthesaurie intranet investinbelgium ioot-servers ipcbel130 ipcbel140 iph irc iroigwy isaf isaf-hq isav ism issue-tracker issuetracker it itdel iv-inig iv-niooo ivk ivk-iev ivkiev jallc jcs jcsc jcse jcsw jemm jenner jewcs jfc-nafs jfc-napl jfcbs jfclb jfcna jfcnaples jfcnp jfnp jftc jhlb jhnsgda jobs jobsdev joot-servers juridict jurion just justice justine justitie jwc jwctf kafka kansspel kansspelcommissie kbo kbo-acc kbo-bce kbo-bce-private kbo-bce-ps kbo-bce-select kbo-bce-wi kbo-test kbopub kbopub-acc kce kce2 kcenet kcetools kenniscentrum kfor kibana kim kinderbijslag klassieke-varkenspest klassiekevarkenspest kleinkasteeltje klimaat koen kommissionsglucksspiele konings-palast koningspalast koninklijk-paleis koninklijkpaleis koot-servers krantenkoppen kruispuntbank ksz ksz-bcss lab lahd lahd2 lamd lancelot laruelle laurette-onkelinckx laurette-onkelinx lauretteonkelinckx lauretteonkelinx lcc14 ldk lebensmittel lebensmittelsicherheit leefloon leefmilieu lesartisans lesartisans-acc likiv limosa linpha linux lists live live2 lju lnc01 lnc02 lnc03 lnc04 lnc05 lnc06 lnc07 lnc08 lnc09 lnc11 lnc12 lnc13 lnc14 lnc15 lnc16 lnc17 lnc18 lo log logo logos logstash lokal-polizei lokale-politie lokalepolitie lokalpolizei loot-servers lss lssplv madeliefjes magnette mail mail1 mail2 mailhost mailin mailsync main mainguard maladies-animales maladies-professionnelles maladiesanimales manp manw map margrietjes margueritebelge marguerites marketing mas masecu masp-be mathilde max maxima maximiliaan mazfp mcug me262 meads medex mediateur-pensions mediateurpensions mediation-pension mediation-pensions mediationpension mediationpensions member members merelbeke meta metrologie metrology mibz mijnsocialezekerheid milieu miltvuur mim mineco minfin minsoc mistr mittelstand mlink1 mlink2 mlm-moscow mlo-belgrade mnc-ne-pl mobile mobilit mobilitaetswoche mobilitatswoche mobility mobilityweek monarchie monarchy monit moniteur moot-servers morello msiac msz mtwg mx mx1 mx11 mx12 mx2 mx3 mykce naa nacesearch nacma nacmo naewfc nagsma nahema naissance naissance2 nama name namsa namsacell-npc naples napma nationalregister natoschool nav navtest nc nc1s nc2s nc3a ncags ncas ncbs nchd ncirc nciss nciz nclb ncmd ncnf ncnp ncnp-dpr ncnw ncnw-fcs ncrn ncsa ncsa-1sb ndc ndss nehap net netma news ng3 nhqb-mail nhqc3s nhqs nhqsa niapc nic nicc nicolas-aymeric nihdi nima nio-moscow niooo nitcdsa nitcdsa2rev2 nitcdsarev2 nitcnpki2rev2 nitcnpkirev2 nitcpki nl nlctst nmiotc nms nncc nnmc nos nova npc nr nra nrflb ns ns01 ns02 ns1 ns2 ns3 nsa nshq nss ntmi-gtt ntmi-hq ntp ntserver nurc nvr obel ocamocad ocde-principesdirecteurs ocmw ocs oecd-guidelines oeffentlichendienst oeso-richtlijnen offentlichendienst offentlichendienstespensionen office ofo ofo-ifa ofoifa old oldphpfarm oldphpfarm-stag ombudsdienst-pensioen ombudsdienst-pensioenen ombudsdienst-pension ombudsdienst-pensionen ombudsdienstpensioen ombudsdienstpensioenen ombudsdienstpension ombudsdienstpensionen ombudsman ombudsman-pensioen ombudsman-pensioenen ombudsman-pensionen ombudsman-pensions ombudsman-pesion ombudsmann-pensionen ombudsmann-pensions ombudsmannpensionen ombudsmannpensions ombudsmanpensioen ombudsmanpensioenen ombudsmanpension ombudsmanpensionen ombudsmanpensions ombudsmanpesion onafts onafts-rkw onem onem-rva onerva onkelinckx onkelinx onp onp-rvp onprvp onss onssapl onssrszlss ontwikkeling ontwikkelings-samenwerking ontwikkelingssamenwerking onva onva-rjv origin osone ossom ossom-dosz otan outpost outsite overheidspensioenen owa p-o p51 pacific palais-royal palaisroyal pan paquerette paquerettes pasteur patrimoniumdiensten pdasync pdod pdoed pdos pdos-sdpsp pegase pensioenagentschap pensioenen pensionen pensions pensionsagentur pensionspubliques peste-aviaire peste-porcine pesteaviaire pesteporcine petitchateau petrel35 pgr phimail phone phpbalancer phpbalancer-stag phpmyadmin phpwf phytoweb plan plan2004 plda pma po polfed police police-locale policelocale politie polizei pop pophost portaalserver portal postbox postbus postfach ppp1 ppp10 ppp11 ppp12 ppp13 ppp14 ppp15 ppp16 ppp17 ppp18 ppp19 ppp2 ppp20 ppp21 ppp3 ppp4 ppp5 ppp6 ppp7 ppp8 ppp9 pptp premier presscenter presscentre pressreview princess-elisabeth princesse-elisabeth princesseelisabeth princesselisabeth princesselouise princesslouise prinses-elisabeth prinseselisabeth prinseslouise print printer prinzessin-elisabeth prinzessinelisabeth prinzessinlouise privacy private-security private-sicherheit private-veilligheid privatesecurity privatesicherheit privateveilligheid prod prodcom production projects protectioncivile pub public publichealth publicweb quetelet raadvanstate raadvst raadvst-consetat rac-restaurants-cae ranva ras raven rcc rce rcn rcs rcw rdb rdb-rdg rdg rdg-rdb reach reactricity recensement recensement2011 recherche reflex regie regiedergebouwen regiedesbatiment regiedesbatiments register registrenational relay relay1 reno repository residencepalace resultatselectoraux revenu-d-integration revenu-dintegration revenudintegration rfid rfid-test rfidtest rijksregister riziv riziv-inami rjv rjv-onva rkw rkw-onafts root route router royal-palace royalpalace rrn rss rssdirectory rsvz rsvz-inasti rsz rszppo rta rto ruling rva rva-onem rvp rvp-onp rvponp saclant saclantc saclantcen salmonella salmonellose salmonellosis samenwerking saml sant01 sante sante-publique santepublique saso sav sbib03 scdfpensions scha01 schweinepest sdpsp sdpsp-pdos search secal secure secure2 securite-prive securite-privee securitealimentaire securiteprive securiteprivee securitesociale selor semainedelamobilite server server-lnmail serverex services-stag servicesdirective servicespatrimoniaux seveso sfn sgen01 sgt4 shape shipping shop shop-info shopinfo sibelius siem sigedis silberfonds simplification siod sirs siskin sist sjam01 skab01 slab01 slem02 slem03 sleu01 slgs01 slice smee01 smee03 smtp sng302 sng3lnmail1 sng3lnmail2 sng3lnmail3 sng3lnmail4 sng3lnmail5 sngslnmail1 snislnmail1 snislnmail2 snislnmail3 snislnmail4 snislnmail5 snmg1 snmp snpl01 sobane sociaaltarief sociaaltarief-acc social-assistance socialassistance sociale-zaken socialeconomy socialeeconomie socialeverkiezingen socialezekerheid socialsecurity soctar soctar-acc sof sos sos112 sozialesicherheit sozialtarif sp spam spp sql sql1 sql2 sql3 ssc ssh staatsblad staatsrat stage staging starfighter statbel static stats stcw95 stis stor01 studentaanhetwerk studentatwork style suche supremeadministrativecourt survey surveykce sw swtc02 sylvie syslog ta taalnet taccp taggingmanager tarifsocial tarifsocial-acc tax-on-web tax-web taxonweb taxweb tct tedc telcobel telerad telnet temporary temporary-acc test test-kbo-bce-select test2 test3 testdiv testmark2 testncsa tewerkstelling tipsentrics tmd tourstat tr training traitements tralal transis transport travail treasury trends tse tu tularemia tularemie upload urbain urbainacc var varkenspest vbv vbv-cprr vbvcprr veniceclub vereenvoudiging verkeer verkiezingen verkiezingsuitslagen vervoer vetera veterans veteransandvictims vici victims vigilis voedselveiligheid vogelgriep vogelpest voip volksgesundheit volksgezondheid volkstelling volkstelling2011 vpn vpn1 vpn2 vps vrouwenpensioen vsp vspp w wahlen warveterans warvictims web web2 webaccess webadmin webcache webdev webdiv webgids webguide webibz webinterface webmail webmittelstand webserver website websurveys webtranslation webtranslations wedden weekvandevervoering weekvanvervoering werk westlant win windows workinginbelgium ww ww3 www www2 wwww xbrl xbrl-acc xbrl-tst xml xmmxprod1 zdfageh\228lter zdfagehaelter zdfagehalter zdfapensionen zensus zensus2011 zfa zilverfonds zoek dnsenum2-1.3.1/dnsenum.pl000077500000000000000000001434441431720122700152710ustar00rootroot00000000000000#!/usr/bin/perl # # # dnsenum.pl VERSION 1.3.0 # This version: - changed version number to the correct one # # dnsenum.pl: multithread script to enumerate information on # a domain and to discover non-contiguous ip blocks. # # 1) Get the host's address. # 2) Get the nameservers (threaded). # 3) get the MX record (threaded). # 4) Perform axfr queries on nameservers (threaded). # 5) Get extra names via google scraping. # 6) Brute force subdomains from file (threaded). # 7) Calculate C class domain network ranges and perform whois # queries on them (threaded). # 8) Perform reverse lookups on C class or/and whois # network ranges (threaded). # 9) Write to domain_ips.txt file non-contiguous ip-blocks results. # # run perldoc on this script for help. # # To install needed modules: # sudo perl -MCPAN -e shell # and then e.g.: cpan[1]> install XML::Writer # # Copyright (C) 2014 - Filip Waeytens, tixxDZ # Copyright (C) 2019 - Network Silence # 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., 675 Mass Ave, Cambridge, MA 02139, USA. # # # Special thanks to all perl developers. # # please see perldoc dnsenum.pl for options and arguments use strict; use warnings ; #it complains about uninitialized values when it doesn't find address in RR; need to fix later no if $] >= 5.018, 'warnings', "experimental::smartmatch"; # Mute Experimental Warning use Config; use Term::ANSIColor; use Getopt::Long; use IO::File; use Net::IP; use Net::DNS; use Net::Netmask; use XML::Writer; use Socket; use Cwd; use String::Random; my ( $ithreads_support, $whois_support, $mech_support, $html_support, $xml_support ); my ( %nameservers, %allsubs, %googlesubs ); my ( %filesubs, %netranges, %recursubs ); my ( @mxservers, @results, @ipblocks, @privateips ); my ( $enum, $exp, $help, $noreverse, $nocolor, $update, $whois, $dnsserver ); my ( $private, $recursion, $scrap, $threads, $verbose ); my ( $dnsfile, $subfile, $dns_tmp, $sub_tmp, $fileips ); my ( $domain, $recur, $table, $extend_b, $extend_r ); my ( $timeout, $delay, $pages, $ipcount, $ipvalid ) = ( 10, 3, 5, 0, 0 ); my ($output); my $writer; my $program = 'dnsenum.pl'; my $default_dir = '/usr/share/dnsenum/dns.txt'; my $string_gen = String::Random->new; my $wildcards = $string_gen->randpattern("cccccccccccc"); my @wildcardaddress; my @wildcardcname; my $VERSION = '1.2.6'; #load threads modules (perl must be compiled with ithreads support) BEGIN { if ( $Config{useithreads} ) { eval( " use threads; use threads::shared; use Thread::Queue; " ); $ithreads_support = 1 unless $@; } } eval("use Net::Whois::IP qw(whoisip_query);"); $whois_support = 1 unless $@; eval("use WWW::Mechanize;"); $mech_support = 1 unless $@; eval("use HTML::Parser;"); $html_support = 1 unless $@; eval("use XML::Writer;"); $xml_support = 1 unless $@; $dnsfile = get_dns_list($default_dir); print STDOUT $program, " VERSION:", $VERSION, "\n"; GetOptions( 'dnsserver=s' => \$dnsserver, 'enum' => \$enum, 'd|delay=i' => \$delay, 'e|exclude=s' => \$exp, 'f|file=s' => \$dnsfile, 'h|help' => \$help, 'noreverse' => \$noreverse, 'nocolor' => \$nocolor, 'p|pages=i' => \$pages, 'private' => \$private, 'r|recursion' => \$recursion, 's|scrap=i' => \$scrap, 'subfile=s' => \$subfile, 'threads=i' => \$threads, 't|timeout=i' => \$timeout, 'u|update=s' => \$update, 'v|verbose' => \$verbose, 'w|whois' => \$whois, 'o|output=s' => \$output ); # Documentation Says Output not Out usage() if $help || @ARGV == 0; $domain = lc $ARGV[0]; $fileips = $domain . '_ips.txt'; #DEFAULT options --threads 5 -s 15 -w if ($enum) { $threads = 5; $scrap = 15 ; # Google scraping default to 15 to avoid Google Blocking us with captcha's $whois = 1; } #module support if ($threads) { if ( ( !defined $ithreads_support and warn "Warning: can't use threads, check ithreads support, and " . "(threads, threads::shared, Thread::Queue) modules.\n" ) || $threads <= 0 ) { $threads = undef; } else { #to handle different ips that belongs to the domain share(@results); #number of ips that will be queried in reverse lookup share($ipcount); #number of valid ips (taken from reverse lookup responses) share($ipvalid); #will contain all valid subdomains share(%allsubs); if ($recursion) { share(%recursubs); share(%nameservers); } #to save whois netblocks share($table); #whois and reverse lookup results share(%netranges); } } if ( $whois && !defined $whois_support ) { warn "Warning: can't load Net::Whois::IP module, " . "whois queries disabled.\n"; $whois = undef; } if ( $whois && !defined $whois_support ) { warn "Warning: can't load Net::Whois::IP module, " . "whois queries disabled.\n"; $whois = undef; } if ( $output && !defined $xml_support ) { warn "Warning: can't load XML::Writer module, " . "xml output disabled.\n"; $output = undef; } if ( defined($output) ) { my $out = new IO::File(">$output"); $writer = new XML::Writer( OUTPUT => $out ); $writer->xmlDecl("UTF-8"); $writer->startTag( "magictree", "class" => "MtBranchObject" ); $writer->startTag( "testdata", "class" => "MtBranchObject" ); } $scrap = undef if $scrap && ( ( not defined $mech_support and warn "Warning: can't load WWW::Mechanize module" . ", Google scraping disabled.\n" ) || ( not defined $html_support and warn "Warning: can't load HTML::Parser module" . ", Google scraping disabled.\n" ) || $scrap <= 0 || $pages <= 0 ); $timeout = 10 if $timeout < 0 || $timeout > 128; $delay = 3 if $delay < 0; $update = undef if $update && !$dnsfile; unless ($nocolor) { print color 'bold blue'; } print STDOUT "\n----- ", $domain, " -----\n"; unless ($nocolor) { print color 'reset'; } ################START##################### # (1) get the host's addresses printheader("Host's addresses:\n"); my $res = Net::DNS::Resolver->new( tcp_timeout => $timeout, udp_timeout => $timeout, defnames => 0 ); $res->nameservers($dnsserver) if $dnsserver; my $packet = $res->query($domain); if ($packet) { foreach my $rr ( grep { $_->type eq 'A' } $packet->answer ) { printrr( $rr->string ); xml_host($rr); push @results, $rr->address if $rr->name =~ /$domain$/; } } elsif ($verbose) { warn " ", $domain, " A query failed: ", $res->errorstring, "\n"; } # wildcards test - I guess it can be cleaner, but it seems to be working # tested with opendns servers and ubuntu.org domain print STDOUT "\n" . "-" x 16 . "\nWildcards test:\n" . "-" x 16 . "\n" if $verbose; my $wildcardpacket = $res->query( $wildcards . "." . $domain ); # if we get a response resolving our random hostname, it can be a A or a CNAME if ($wildcardpacket) { printheader( "Wildcard detection using: " . $wildcards . "\n" ); foreach my $rr ( $wildcardpacket->answer ) { if ( $rr->type eq 'A' ) { printrr( $rr->string ); #wildcardaddress will hold the IP that's used as a string my @wcheck = split( '\s+', $rr->string ); push @wildcardaddress, $wcheck[4]; } if ( $rr->type eq 'CNAME' ) { printrr( $rr->string ); #wildcardcname will hold CNAME that's used as a string my @wcheck = split( '\s+', $rr->string ); push @wildcardcname, $wcheck[4]; } } unless ($nocolor) { print color 'bold red'; } print "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n"; print STDOUT " Wildcards detected, all subdomains will point to the same IP address\n"; print STDOUT " Omitting results containing " . join( ', ', @wildcardaddress ) . ".\n Maybe you are using OpenDNS servers.\n"; print "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; unless ($nocolor) { print color 'reset'; } #exit(1);#we don't exit when wildcards are detected, because we will miss existing hosts } elsif ($verbose) { print STDOUT " good\n"; } # (2) get the namservers for the domain printheader("Name Servers:\n"); $packet = $res->query( $domain, 'NS' ); if ($packet) { foreach my $rr ( grep { $_->type eq 'NS' } $packet->answer ) { $nameservers{ $rr->nsdname } = 1; } die " Error: can't continue no NS record for ", $domain, "\n" unless %nameservers; #read the A record from the additional section if ( $packet->header->arcount ) { my @remain = additionalrecord( $packet, keys %nameservers ); #do nslookup on nameservers that are not present in the #additional section launchqueries( \&nslookup, @remain ) if scalar @remain; } #perform the nslookup on the nameservers else { launchqueries( \&nslookup, keys %nameservers ); } } #exit if there is no NS record. else { die " ", $domain, " NS record query failed: ", $res->errorstring, "\n"; } # (3) get the MX record printheader("Mail (MX) Servers:\n"); $packet = $res->query( $domain, 'MX' ); if ($packet) { foreach my $rr ( grep { $_->type eq 'MX' } $packet->answer ) { push @mxservers, $rr->exchange; } if ( scalar @mxservers ) { if ( $packet->header->arcount ) { my @remain = additionalrecord( $packet, @mxservers ); launchqueries( \&nslookup, @remain ) if scalar @remain; } else { launchqueries( \&nslookup, @mxservers ); } } } elsif ($verbose) { warn " ", $domain, " MX record query failed: ", $res->errorstring, "\n"; } # (4) perform zonetransfers on nameservers printheader("Trying Zone Transfers and getting Bind Versions:\n"); launchqueries( \&zonetransfer, keys %nameservers ); # (5) scrap additional names from google search and do nslookup on them if ($scrap) { printheader( "Scraping " . $domain . " subdomains from Google:\n" ); my @tmp = googlescraping(); if ( scalar @tmp ) { #print STDOUT "\n Performing nslookups:\n"; launchqueries( \&nslookup, map { $_ .= '.' . $domain } @tmp ); } } #exit if the brute force file is not specified unless ($dnsfile) { print STDOUT "\nbrute force file not specified, bay.\n"; if ( defined($output) ) { $writer->endTag('testdata'); $writer->endTag('magictree'); } exit(0); } $extend_b = 1 if ( $update && $update eq 'a' ) || $subfile || $recursion; # (6) brute force subdomains from a file printheader( "Brute forcing with " . $dnsfile . ":\n" ); bruteforce('f'); #updating dnsfile with zonetransfer or googlescraping subdomains results if ($update) { if ( $dns_tmp = IO::File->new_tmpfile() ) { if ( $update eq 'z' ) { print $dns_tmp $_, "\n" for uniq_hosts( grep { $allsubs{$_} eq $update } keys %allsubs ); } elsif ( $update eq 'g' ) { print $dns_tmp $_, "\n" for uniq_hosts( keys %googlesubs ); } } else { die "Error can't create a temporary file: $!, " . "to update ", $dnsfile, " file\n"; } } undef %googlesubs if %googlesubs; #launch recursion if ($recursion) { if (%allsubs) { printheader("Performing recursion:\n"); print STDOUT "\n ---- Checking subdomains NS records ----\n"; #select subdomains that are able to recursion launchqueries( \&selectsubdomains, map { $_ .= '.' . $domain } sort keys %allsubs ); if (%recursubs) { my @tmp = keys %recursubs; undef %recursubs; #brute force from a list using recursion bruteforce( 'l', \@tmp ); } else { print STDERR "\n Can't perform recursion " . "no NS records.\n"; } } else { print STDERR "\n Can't perform recursion no subdomains.\n"; } undef %filesubs; } #updating the brute force file (-u a switch) if ( $update && ( $update eq 'a' || $update eq 'all' ) ) { #save ns and mx servers my @tmp = keys %nameservers; push @tmp, @mxservers if scalar @mxservers; print $dns_tmp $_, "\n" for uniq_hosts( grep { s/\.$domain// } @tmp ); print $dns_tmp $_, "\n" for uniq_hosts( keys %allsubs ); } #write subdomains to the subfile if ($subfile) { if ( $sub_tmp = IO::File->new_tmpfile() ) { my %uniq; @uniq{ keys %nameservers } = (); @uniq{@mxservers} = () if scalar @mxservers; print $sub_tmp $_, "\n" for grep { s/\.$domain// } keys %uniq; print $sub_tmp $_, "\n" for keys %allsubs; } else { die "Error can't create a temporary file: $!, " . " to save results to ", $subfile, " file\n"; } } undef @mxservers; undef %allsubs; # (7) get domain network ranges from brute force results and whois queries @results = networkranges(@results); undef %netranges; # (8) perform reverse lookups on netranges (class C or whois netranges) unless ($noreverse) { #to save all valid subdomains discovered in #the reverse lookup process $extend_r = 1 if ( $update && ( $update eq 'r' || $update eq 'a' || $update eq 'all' ) ) || $subfile; printheader( "Performing reverse lookup on " . $ipcount . " ip addresses:\n" ); launchqueries( \&reverselookup, @results ); print STDOUT "\n", $ipvalid, " results out of ", $ipcount, " IP addresses.\n"; } else { #calculate ip blocks @ipblocks = finalvalidips( sort_by_ip_address(@results) ); } #save final IP blocks to the domain_ips.txt file writetofile( $fileips, "w", @ipblocks ); #show private ips if ( $private && scalar @privateips ) { print STDOUT "\n" . "-" x 26 . "\n", $domain, " private ips:\n" . "-" x 26 . "\n"; print STDOUT " ", $_, "\n" for @privateips; #save private ips to domain_ips.txt file writetofile( $fileips, "a+", @privateips ); } # (9) show non-contiguous IP blocks printheader( $domain . " ip blocks:\n" ); print STDOUT " ", $_, "\n" for @ipblocks; #clean the brute force file cleanfile( $dnsfile, $dns_tmp ) if $update; #clean the subfile cleanfile( $subfile, $sub_tmp ) if $subfile; if ( defined($output) ) { $writer->endTag('testdata'); $writer->endTag('magictree'); } print STDOUT "\ndone.\n"; exit(0); #-------------------------------------------------- #Check if dns.txt file exists. Default on nonexistance #to local dns.txt sub get_dns_list { my $default_dir = shift; unless ( -f $default_dir ) { $default_dir = getcwd() . '/dns.txt'; } return $default_dir; } #subroutine that will launch different queries #(nslookup, zonetransfer, whoisip, reverselookup) sub launchqueries { my $querytype = shift; if ( $querytype != \&reverselookup ) { if ($threads) { my $stream = new Thread::Queue; $stream->enqueue(@_); my $thrs = $threads; #don')t create unused threads $thrs = scalar @_ if $threads > scalar @_; for ( 1 .. $thrs ) { threads->new( $querytype, \$stream ); } #wait all threads foreach ( threads->list ) { $_->join if ( $_->tid && !threads::equal( $_, threads->self ) ); } } else { foreach (@_) { &$querytype($_); } } } else { foreach (@_) { my $block = new2 Net::Netmask($_); unless ($block) { print STDERR " Can't perform reverse lookup: ", $Net::Netmask::error, "\n"; next; } if ($threads) { my $stream = new Thread::Queue; $stream->enqueue( $block->enumerate ); for ( 1 .. $threads ) { threads->new( $querytype, \$stream ); } #wait all threads foreach ( threads->list ) { $_->join if ( $_->tid && !threads::equal( $_, threads->self ) ); } } else { &$querytype( $block->enumerate ); } #calculate IP blocks results if (%netranges) { my @tmp = finalvalidips( sort_by_ip_address( keys %netranges ) ); undef %netranges; #get final valid ip blocks push @ipblocks, @tmp; } #write reverse lookup hostnames results to files if ( $extend_r && %allsubs ) { if ( $update && ( $update eq 'r' || $update eq 'a' || $update eq 'all' ) ) { print $dns_tmp $_, "\n" for uniq_hosts( keys %allsubs ); } if ($subfile) { print $sub_tmp $_, "\n" for keys %allsubs; } undef %allsubs; } } } } #subroutine to perform reverse lookups sub reverselookup { my $stream = shift if $threads; my $res = Net::DNS::Resolver->new( tcp_timeout => $timeout, udp_timeout => $timeout, persistent_udp => 1 ); $res->nameservers( keys %nameservers ); while ( defined( my $ip = $threads ? $$stream->dequeue_nb : shift ) ) { my $query = $res->query($ip); if ($query) { foreach my $rr ( grep { $_->type eq 'PTR' } $query->answer ) { #exclude non PTR types answers or unwanted hostnames next if $exp && $rr->ptrdname =~ /$exp/; if ( $rr->ptrdname =~ /(.*)(\.$domain$)/i ) { $allsubs{$1} = 1 if $extend_r && !$allsubs{$1}; #to calculate last valid ip blocks unless ( $netranges{$ip} ) { $netranges{$ip} = 1; $ipvalid++; } printrr( $rr->string ); xml_host($rr); } #show all answers even if the hostname don't match the domain elsif ($verbose) { printrr( $rr->string ); xml_host($rr); } } } #this part is just to check progress elsif ($verbose) { print STDOUT " ", $ip, " ...\n"; } } } sub xml_host { if ( defined $output ) { my $rr = shift; my $ip; if ( $rr->type eq 'A' ) { $ip = $rr->address; } else { my $packed_ip = gethostbyname( $rr->name ); if ( defined $packed_ip ) { $ip = inet_ntoa($packed_ip); } } if ( defined($ip) ) { $writer->startTag("host"); $writer->characters($ip); $writer->startTag("hostname"); $writer->characters( $rr->name ); $writer->endTag("hostname"); $writer->endTag("host"); } $writer->startTag("fqdn"); $writer->characters( $rr->name . '.' ); $writer->endTag("fqdn"); } } #subroutine for nslookups (A record) sub nslookup { my $stream = shift if $threads; my $res = Net::DNS::Resolver->new( tcp_timeout => $timeout, udp_timeout => $timeout, persistent_udp => 1, dnsrch => 0 ); $res->nameservers($dnsserver) if $dnsserver; while ( defined( my $host = $threads ? $$stream->dequeue_nb : shift ) ) { my $query = $res->search($host); if ($query) { foreach my $rr ( $query->answer ) { ##we only print / add the result if it doesn't match the wildcardaddress if ( !( $rr->can('address') && $rr->address ~~ @wildcardaddress ) && !( $rr->name ~~ @wildcardcname ) ) { printrr( $rr->string ); xml_host($rr); #check if it match the domain if ( $rr->name =~ /(.*)(\.$domain$)/i ) { #save valid subdomains if ($extend_b) { $allsubs{$1} = 1 unless $allsubs{$1}; #recursion results $recursubs{$1} = 1 if $recur && !$recursubs{$1}; } #save ip address push @results, $rr->address if $rr->type eq 'A'; } } } } elsif ($verbose) { warn " ", $host, " A record query failed: ", $res->errorstring, "\n"; } } } #subroutine to select subdomains that have NS records sub selectsubdomains { my $stream = shift if $threads; my $res = Net::DNS::Resolver->new( tcp_timeout => $timeout, udp_timeout => $timeout, persistent_udp => 1 ); $res->nameservers($dnsserver) if $dnsserver; while ( defined( my $host = $threads ? $$stream->dequeue_nb : shift ) ) { my $packet = $res->query( $host, 'NS' ); if ($packet) { foreach my $rr ( grep { $_->type eq 'NS' } $packet->answer ) { #show all results #print STDOUT " ", $rr->string ,"\n"; printrr( $rr->string ); xml_host($rr); if ( $rr->name =~ /(.*)(\.$domain$)/i ) { if ( !$allsubs{$1} || $allsubs{$1} ne 'r' ) { #bookmark this hostname to #perform recursion on it and #to avoid repetition, because #some domains will use CNAME #types that point to subs #that we have already #processed in a previous #recursion levels $allsubs{$1} = 'r'; #select this subdomain #for recursion $recursubs{ $rr->name } = 1; } #perhaps for future additions we save #ns servers for each domain or #subdomain, this will be very #useful in reverse lookup # --- begin --- #check if we already have this #NS server #next if $nameservers{$rr->nsdname}; #$nameservers{$rr->nsdname} = 1; #push @tmp, $rr->nsdname; # --- end --- } } #perhaps for future additions to perform an extrem #recursion to get the IP address of the NS servers # --- begin --- #next unless scalar @tmp; #get the NS servers A record #if ($packet->header->arcount) { # @tmp = additionalrecord($packet,@tmp); # next unless scalar @tmp; #} #foreach my $nshost (@tmp) { # $packet = $res->query($nshost); # if ($packet) { # foreach my $rr \ # (grep { $_->type eq 'A' } # $packet->answer) { # print STDOUT " ", # $rr->string , "\n"; # push @results, $rr->address # if ($rr->name =~ /$domain$/); # } # } # elsif ($verbose) { # warn " ", $nshost , # " A record query failed: ", # $res->errorstring , "\n"; # } #} # --- end --- } elsif ($verbose) { warn " ", $host, " NS record query failed: ", $res->errorstring, "\n"; } } } #subroutine for zonetransfers #I got rid of the Bind Versions search...doesn't really add anything and clutters output sub zonetransfer { my $stream = shift if $threads; my $res = Net::DNS::Resolver->new( tcp_timeout => $timeout, udp_timeout => $timeout ); while ( defined( my $ns = $threads ? $$stream->dequeue_nb : shift ) ) { $res->nameservers($ns); my @zone = $res->axfr($domain); #my $version_query = $res->search("version.bind","TXT","CH"); print STDOUT "\nTrying Zone Transfer for ", $domain, " on ", $ns, " ... \n"; if (@zone) { foreach my $rr (@zone) { #print all results printrr( $rr->string ); xml_host($rr); #save data if the record's domain name #match the domain if ( $rr->name =~ /(.*)(\.$domain$)/i ) { #save hostname $allsubs{$1} = 'z' unless $allsubs{$1}; #save the IP address push @results, $rr->address if $rr->type eq 'A'; #save new mx servers hostnames push @mxservers, $rr->exchange if $rr->type eq 'MX'; #perhaps for future additions #save NS servers for reverse lookups # --- begin --- #$nameservers{$rr->nsdname} = 1 # if ($rr->type eq 'NS' && # !$nameservers{$rr->nsdname}); # --- end --- } } } else { warn "AXFR record query failed: ", $res->errorstring, "\n"; } } } #subroutine for scraping domains from google sub googlescraping { my ( $response, $browser, $form, $parser, $nextpage ); my ( $count, $mypage ) = ( 0, 1 ); my $query = qq[-www site:$domain]; # Allinurl deprecated my $nexturl = qq[/search?.*q=.*$domain.*start]; #on errors the mech object will call die $browser = WWW::Mechanize->new( autocheck => 1, stack_depth => 1, cookie_jar => undef ); #uncomment for debugging with BURP #$browser->proxy(['http'], 'http://127.0.0.1:8080'); #setup the browser config my @agents = $browser->known_agent_aliases(); my $agent = $agents[ rand( scalar @agents ) ]; $browser->agent_alias($agent); $browser->timeout($timeout); #get the first page $response = $browser->get("http://www.google.com/ncr"); $form = $browser->form_number(1) or return; $form->find_input('q')->value($query); $response = $browser->submit_form( form_number => 1, form_name => 'f' ); do { $nextpage = undef; print STDOUT "\n ---- Google search page: ", $mypage, " ---- \n\n"; $parser = HTML::Parser->new( api_version => 3, start_h => [ sub { my $attr = shift; #end of parsing #(we have enough subdomains) $parser->eof unless $count < $scrap; return unless $attr->{href}; #subdomains checks - if shit goes wrong with googlescraping it's prolly the regex if ( $attr->{href} =~ /(\/url\?q\=http:\/\/)([\w\.-]+)(\.$domain\/)/ ) { $allsubs{$2} = 'g' unless $allsubs{$2}; $googlesubs{$2} = 1 unless $googlesubs{$2}; print STDOUT " ", $2, "\n"; $count++; } #the next page elsif ( $attr->{href} =~ /^$nexturl=$mypage\d.*/ && !defined $nextpage ) { $nextpage = $attr->{href}; } }, 'attr' ] ); $parser->parse( $response->decoded_content ); if ($nextpage) { $response = $browser->get($nextpage); $mypage++; } } while ( $count < $scrap && $mypage <= $pages && $nextpage ); #print STDOUT "\n Google results: ", $count ,"\n"; printheader("Google Results:\n"); if ($count) { return grep { $allsubs{$_} eq 'g' } keys %allsubs; } else { print STDERR " perhaps Google is blocking our queries.\n Check manually.\n"; return; } } #subroutine to query a whois server for an IP address to get the correct netrange sub whoisip { my $stream = shift if $threads; while ( defined( my $ip = $threads ? $$stream->dequeue_nb : shift ) ) { my ( $inetnum, $block ); #search in the network blocks table to find #if any of them contains the IP address next if ( findAllNetblock( $ip, $table ) ); #this is very useful on whois servers #that limit the number of connections sleep rand $delay; #catch different exceptions #(on exceptions netrange will be a class C /24) eval { my $response = whoisip_query($ip); foreach ( keys %{$response} ) { next if ( $_ !~ /^(inetnum|netrange)$/i ); $inetnum = $response->{$_}; #handle all whois netrange format if ( $inetnum =~ /([\d.\.]+)\/(\d{1,2})/ ) { #whois.lacnic.net format $block = new2 Net::Netmask(qq[$1/$2]); } else { $inetnum =~ s/\s//g; $block = new2 Net::Netmask($inetnum); } if ($block) { # this is useful when threads are enabled to eliminate # the processing of same netranges next if $threads && $netranges{ $block->desc }; $block->storeNetblock($table); #this is a simple workaround to #save netblocks in a hash #because we will lost all data #in $table after threads exit #(see Net::Netmask and #threads::shared and threads safe) #i am soure that there is a beter #solution please excuse my ignorance $netranges{ $block->desc } = 1; $ipcount += $block->size(); printf STDOUT " whois ip result:" . " %-15s -> %s\n", $ip, $block->desc; } else { print STDERR " Netmask error: ", $Net::Netmask::error, "\n" if $verbose; $inetnum = undef; } } }; if ($@) { #catch any invalid results #assume that the network range is a class C print STDERR " Error: ", $@ if $verbose; $inetnum = undef; } #can't get the netrange form the whois server #so we assume that is a class C range (/24) unless ( defined $inetnum ) { $block = new Net::Netmask(qq[$ip/24]); next if $threads && $netranges{ $block->desc }; $block->storeNetblock($table); $netranges{ $block->desc } = 1; $ipcount += 256; printf STDOUT " c class default: " . "%-15s -> %s " . " (whois netrange operation failed)\n", $ip, $block->desc; } } } #subroutine to brute force subdomains sub bruteforce { #recursion on valid subdomains brute force from a list if ( shift eq 'l' ) { my ( $level, $hosts, @tmp ) = 1; my $res = Net::DNS::Resolver->new( tcp_timeout => $timeout, udp_timeout => $timeout, persistent_udp => 1, dnsrch => 0 ); $res->nameservers($dnsserver) if $dnsserver; #signal to nslookup to save all recursive subdomains $recur = 1; RECURSION: $hosts = shift; print STDOUT "\n ---- Recursion level ", $level, " ---- \n"; foreach my $host (@$hosts) { my ( @words, %uniq ); print STDOUT "\n Recursion on ", $host, " ...\n"; #wildcards test if ( $res->search( $wildcards . $host ) ) { print STDERR " ", $host, ": Wildcards detected.\n"; next; } #perform brute force using all hostnames and include the new one #(discovered from previous brute forces) foreach ( sort keys %allsubs, grep { not $allsubs{$_} } keys %filesubs ) { push @words, $_ . '.' . $host; #split hostnames that contain dots foreach ( split /\./ ) { unless ( $allsubs{$_} || $filesubs{$_} || $uniq{$_} ) { $uniq{$_} = 1; push @words, $_ . '.' . $host; } } } launchqueries( \&nslookup, @words ); } #can't find new hostnames return unless @tmp = grep { $allsubs{$_} ne 'r' } keys %recursubs; undef %recursubs; #select subdomains printheader("Checking subdomains NS records:\n"); launchqueries( \&selectsubdomains, map { $_ .= '.' . $domain } sort @tmp ); unless (%recursubs) { print STDOUT "\n Can't perform recursion, " . "no new NS records.\n" if $verbose; return; } @tmp = keys %recursubs; undef %recursubs; $level++; @_ = \@tmp; goto RECURSION; } #brute force subdomains from dnsfile else { my @words; die "Error: make sure that the file ", $dnsfile, " exists and has a size greater than zero.\n" unless -s $dnsfile; my $input = new IO::File $dnsfile, "r" or die "Could not open ", $dnsfile, " file: $!\n"; while (<$input>) { chomp; #save subdomains found in the file to use them #in the recursion process $filesubs{$_} = 1 if $recursion; #select all subdomains that have not been listed push @words, $_ . '.' . $domain unless $allsubs{$_}; } $input->close; scalar @words ? launchqueries( \&nslookup, @words ) : print STDOUT " Can't find new subdomains.\n"; #the names have already been found by zonetransfer, ... } } #subroutine to get the domain's network ranges sub networkranges { my ( @cnets, %ips, %seen ); #uniq IP's @ips{@_} = (); foreach my $ip ( sort_by_ip_address( keys %ips ) ) { my @octets = split /\./, $ip; #private IP's if ( $octets[0] == 10 || $octets[0] == 127 || ( $octets[0] == 169 && $octets[1] == 254 ) || ( $octets[0] == 172 && ( $octets[1] > 15 && $octets[1] < 32 ) ) || ( $octets[0] == 192 && $octets[1] == 168 ) ) { #save private ips push @privateips, $ip if $private; delete $ips{$ip}; next; } #to get unique class C netranges my $net = join( "\.", $octets[0], $octets[1], $octets[2] ); unless ( $seen{$net} ) { $seen{$net} = 1; push @cnets, $net . ".0"; } } #launch whois queries on IP's to get the correct netranges if ($whois) { printheader("Launching Whois Queries:\n"); #shutdown warns the whois ip will catch exceptions with eval $SIG{__WARN__} = sub { }; launchqueries( \&whoisip, @cnets ); $SIG{__WARN__} = 'DEFAULT'; printheader( $domain, " whois netranges:\n" ); print STDOUT " ", $_, "\n" for keys %netranges; } #default class C netrange else { printheader( $domain . " class C netranges:\n" ); grep { $_ .= "/24"; print STDOUT " ", $_, "\n"; } @cnets; $ipcount = scalar @cnets * 256; } defined $noreverse ? return keys %ips : ( defined $whois ? return keys %netranges : return @cnets ); } #subroutine that calculate and return non-contiguous IP blocks sub finalvalidips { my $firstip = shift; #one single IP address return $firstip . "/32" unless scalar @_; my ( $lastip, @tmp ); my $broadcast = $_[$#_]; my $tmpip = new Net::IP(qq[$firstip - $broadcast]); foreach my $thisip (@_) { # increment the previous tmp IP address to compare it with the current # IP address taken from the array ++$tmpip; if ( $broadcast ne $thisip ) { #this IP belongs to the current netrange if ( $tmpip->ip() eq $thisip ) { $lastip = $thisip; } #new netrange else { defined $lastip ? push @tmp, range2cidrlist( $firstip, $lastip ) : push @tmp, $firstip . "/32"; #update data $firstip = $thisip; $lastip = undef; $tmpip = new Net::IP(qq[$firstip - $broadcast]); } } #we have reached the last valid IP address in the network range else { #this IP belongs to the current range if ( $tmpip->ip() eq $broadcast ) { push @tmp, range2cidrlist( $firstip, $broadcast ); } #this IP is the start of a new range else { defined $lastip ? push @tmp, range2cidrlist( $firstip, $lastip ) : push @tmp, $firstip . "/32"; #save the current new ip push @tmp, $broadcast . "/32"; } } } return @tmp; } #subroutine that reads the A record from the additional section sub additionalrecord { my ( $packet, @servers, %seen ) = @_; foreach my $rr ( grep { $_->type eq 'A' } $packet->additional ) { foreach ( grep { $_ eq $rr->name } @servers ) { $seen{ $rr->name } = 1; printrr( $rr->string ); xml_host($rr); push @results, $rr->address if $rr->name =~ /$domain$/; } } #get the nameservers that have not been found in the additional section keys %seen == @servers ? return : return grep { not $seen{$_} } @servers; } #subroutine to get uniq splited subdomains sub uniq_hosts { my %uniq; grep { !$uniq{$_} && $uniq{$_}++ for split /\./ } @_; return keys %uniq; } #subroutine to write valid subdomains to files sub writetofile { my $file = shift; my $output = new IO::File $file, shift or die "Could not open ", $file, " file: $!\n"; print $output $_, "\n" for @_; $output->close; } #subroutine to update and clean files sub cleanfile { my ( $file, $tmpfile, %uniq ) = @_; seek( $tmpfile, 0, 0 ) or die "Error: seek failed on the temporary file: $!\n" . "can't update ", $file, "\n"; @uniq{<$tmpfile>} = (); if ( -s $file ) { my $input = new IO::File $file, "r" or die "Unable to update ", $file, " file: $!\n"; @uniq{<$input>} = (); $input->close; } writetofile( $file, "w", sort { uc($a) cmp uc($b) } grep { chomp } keys %uniq ); } #broken sub printrr { my $output = shift; my @outputA = split( '\s+', $output ); printf( "%-40s %-8s %-5s %-8s %10s\n", $outputA[0], $outputA[1], $outputA[2], $outputA[3], $outputA[4] ); } sub printheader { my ($header) = @_; unless ($nocolor) { print color 'bold red'; } print STDOUT "\n\n" . $header . "_" x length($header) . "\n\n"; unless ($nocolor) { print color 'reset'; } } #the usage subroutine sub usage { print STDOUT qq{Usage: $program [Options] [Options]: Note: If no -f tag supplied will default to /usr/share/dnsenum/dns.txt or the dns.txt file in the same directory as dnsenum.pl GENERAL OPTIONS: --dnsserver Use this DNS server for A, NS and MX queries. --enum Shortcut option equivalent to --threads 5 -s 15 -w. -h, --help Print this help message. --noreverse Skip the reverse lookup operations. --nocolor Disable ANSIColor output. --private Show and save private ips at the end of the file domain_ips.txt. --subfile Write all valid subdomains to this file. -t, --timeout The tcp and udp timeout values in seconds (default: 10s). --threads The number of threads that will perform different queries. -v, --verbose Be verbose: show all the progress and all the error messages. GOOGLE SCRAPING OPTIONS: -p, --pages The number of google search pages to process when scraping names, the default is 5 pages, the -s switch must be specified. -s, --scrap The maximum number of subdomains that will be scraped from Google (default 15). BRUTE FORCE OPTIONS: -f, --file Read subdomains from this file to perform brute force. (Takes priority over default dns.txt) -u, --update Update the file specified with the -f switch with valid subdomains. a (all) Update using all results. g Update using only google scraping results. r Update using only reverse lookup results. z Update using only zonetransfer results. -r, --recursion Recursion on subdomains, brute force all discovered subdomains that have an NS record. WHOIS NETRANGE OPTIONS: -d, --delay The maximum value of seconds to wait between whois queries, the value is defined randomly, default: 3s. -w, --whois Perform the whois queries on c class network ranges. **Warning**: this can generate very large netranges and it will take lot of time to perform reverse lookups. REVERSE LOOKUP OPTIONS: -e, --exclude Exclude PTR records that match the regexp expression from reverse lookup results, useful on invalid hostnames. OUTPUT OPTIONS: -o --output Output in XML format. Can be imported in MagicTree (www.gremwell.com) }; exit(1); } __END__ =head1 NAME dnsenum.pl -- multithread script to enumerate information on a domain and to discover non-contiguous IP blocks =head1 VERSION dnsenum.pl version 1.3.0 =head1 SYNOPSIS dnsenum.pl [options] -f dns.txt =head1 DESCRIPTION Supported operations: nslookup, zonetransfer, google scraping, domain brute force (support also recursion), whois ip and reverse lookups. Operations: =over 5 =item 1) Get the host's address (A record). =item 2) Get the nameservers (threaded). =item 3) Get the MX record (threaded). =item 4) Perform AXFR queries on nameservers (threaded). =item 5) Get extra names and subdomains via google scraping (google query = "-www site:domain"). =item 6) Brute force subdomains from (REQUIRED), can also perform recursion on subdomain that have NS records (all threaded). =item 7) Calculate Class C IP network ranges from the results and perform whois queries on them (threaded). =item 8) Perform reverse lookups on netranges (class C or/and whois netranges)(threaded). =item 9) Write to domain_ips.txt file non-contiguous ip-blocks results. =back =head1 OPTIONS The brute force -f switch takes priority over default dns.txt =head2 GENERAL OPTIONS: =over =over 30 =item B<--dnsserver> B<> Use this DNS server to perform all A, NS and MX queries, the AXFR and PTR queries are sent to the domain's NS servers. =item B<--enum> Shortcut option equivalent to --threads 5 -s 20 -w. =item B<-h>, B<--help> Print the help message. =item B<--noreverse> Skip the reverse lookup operations. Reverse lookups can take long time on big netranges. =item B<--nocolor> Disable ANSIColor output. This option is only intended to be used on consoles that do not support color output. =item B<--private> Show and save private ips at the end of the file domain_ips.txt. =item B<--subfile> B<> Write all valid subdomains to this file. Subdomains are taken from NS and MX records, zonetransfer, google scraping, brute force and reverse lookup hostnames. =item B<-t>, B<--timeout> B<> The tcp and udp timeout values in seconds (default: 10s). =item B<--threads> B<> The number of threads that will perform different queries. =item B<-v>, B<--verbose> Be verbose (show all the progress and all the error messages). =back =back =over 3 B neither the default domain nor the resolver search list are appended to domains that don't contain any dots. =back =head2 GOOGLE SCRAPING OPTIONS: =over 3 This function will scrap subdomains from google search, using query: -www site:domain. =back =over =over 30 =item B<-p>, B<--pages> B<> The number of google search pages to process when scraping names, the -s switch must be specified, (default: 20 pages). =item B<-s>, B<--scrap> B<> The maximum number of subdomains that will be scraped from google. =back =back =over 3 B Google can block our queries with the malware detection. Http proxy options for google scraping are automatically loaded from the environment if the vars http_proxy or HTTP_PROXY are present. "http_proxy=http://127.0.0.1:8118/" or "HTTP_PROXY=http://127.0.0.1:8118/". On IO errors the mechanize browser object will automatically call die. =back =head2 BRUTE FORCE OPTIONS: =over =over 30 =item B<-f>, B<--file> B<> Read subdomains from this file to perform brute force. =item B<-u>, B<--update> B<> Update the file specified with the -f switch with valid subdomains. =back =back =over 35 B<-u> a Update using all results. B<-u> g Update using only google scraping results. B<-u> r Update using only reverse lookup results. B<-u> z Update using only zonetransfer results. =back =over =over 30 =item B<-r>, B<--recursion> Recursion on subdomains, brute force all discovered subdomains that have an NS record. =back =back =over 3 B To perform recursion first we must check previous subdomains results (zonetransfer, google scraping and brute force) for NS records after that we perform brute force on valid subdomains that have NS records and so on. NS, MX and reverse lookup results are not concerned. =back =head2 WHOIS IP OPTIONS: Perform whois ip queries on c class netanges discovered from previous operations. =over =over 30 =item B<-d>, B<--delay> B<> The maximum value of seconds to wait between whois queries, the value is defined randomly, (default: 3s). =back =back =over 3 B whois servers will limit the number of connections. =back =over =over 30 =item B<-w>, B<--whois> Perform the whois queries on c class network ranges. B: this can generate very large netranges and it will take lot of time to perform reverse lookups. =back =back =over 3 B The whois query should recursively query the various whois providers until it gets the more detailed information including either TechPhone or OrgTechPhone by default. See: perldoc Net::Whois::IP. On errors the netrange will be a default c class /24. =back =head2 REVERSE LOOKUP OPTIONS: =over =over 30 =item B<-e>, B<--exclude> B<> Exclude PTR records that match the regexp expression from reverse lookup results, useful on invalid hostnames. =back =back =over 3 B PTR records that not match the domain are also excluded. Verbose mode will show all results. =back =head1 OUTPUT FILES Final non-contiguous ip blocks are written to domain_ips.txt file. B Final non-contiguous ip blocks are calculated : =over 5 =item 1) From reverse lookups that were performed on netranges ( c class network ranges or whois netranges ). =item 2) If the noreverse switch is used then they are calculated from previous operations results (nslookups, zonetransfers, google scraping and brute forcing). =back =head1 README dnsenum.pl: multithread script to enumerate information on a domain and to discover non-contiguous ip blocks. =head1 PREREQUISITES Modules that are included in perl 5.28.0: Getopt::Long, IO::File, Thread::Queue. Other Necessary modules: Must have: Net::DNS, Net::IP, Net::Netmask. Optional: Net::Whois::IP, HTML::Parser, WWW::Mechanize. Perl ithreads modules (perl must be compiled with ithreads support): threads, threads::shared. =head1 AUTHORS Filip Waeytens tix tixxDZ =head1 MAINTAINER Network Silence =head1 COPYRIGHT 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. =head1 SCRIPT CATEGORIES Networking DNS =cut