pax_global_header 0000666 0000000 0000000 00000000064 14574725657 0014540 g ustar 00root root 0000000 0000000 52 comment=a8d69d7f143bd6e42ab9248d7dfe99008d6295de
dnsenum2-1.3.2/ 0000775 0000000 0000000 00000000000 14574725657 0013276 5 ustar 00root root 0000000 0000000 dnsenum2-1.3.2/INSTALL.txt 0000775 0000000 0000000 00000001362 14574725657 0015152 0 ustar 00root root 0000000 0000000 ##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.2/Makefile 0000775 0000000 0000000 00000000724 14574725657 0014744 0 ustar 00root root 0000000 0000000 .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.2/README.md 0000775 0000000 0000000 00000004323 14574725657 0014562 0 ustar 00root root 0000000 0000000 # DNSENUM2
[](https://inventory.rawsec.ml/tools.html#dnsenum2)
README - dnsenum2.pl VERSION: 1.3.2
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.2/dns.txt 0000775 0000000 0000000 00000031456 14574725657 0014637 0 ustar 00root root 0000000 0000000 *
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.2/dnsenum.pl 0000775 0000000 0000000 00000143101 14574725657 0015307 0 ustar 00root root 0000000 0000000 #!/usr/bin/perl
#
#
# dnsenum.pl VERSION 1.3.2
# 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
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.3.1';
#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 ( $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') && grep { $_ eq $rr->address } @wildcardaddress
)
&& !( grep { $_ eq $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.1
=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