wmap 2.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +141 -0
- data/LICENSE.txt +15 -0
- data/README.rdoc +98 -0
- data/TODO +13 -0
- data/bin/deprime +21 -0
- data/bin/distrust +38 -0
- data/bin/googleBot +23 -0
- data/bin/prime +21 -0
- data/bin/refresh +26 -0
- data/bin/run_tests +16 -0
- data/bin/spiderBot +26 -0
- data/bin/trust +38 -0
- data/bin/updateAll +57 -0
- data/bin/wadd +25 -0
- data/bin/wadds +26 -0
- data/bin/wcheck +28 -0
- data/bin/wdel +25 -0
- data/bin/wdump +21 -0
- data/bin/wmap +151 -0
- data/bin/wscan +32 -0
- data/data/cidrs +2 -0
- data/data/deactivated_sites +1 -0
- data/data/domains +2 -0
- data/data/hosts +1 -0
- data/data/prime_hosts +1 -0
- data/data/sites +2 -0
- data/data/sub_domains +2 -0
- data/demos/bruter.rb +27 -0
- data/demos/dns_brutes.rb +28 -0
- data/demos/filter_cidr.rb +18 -0
- data/demos/filter_crawls.rb +5 -0
- data/demos/filter_domain.rb +25 -0
- data/demos/filter_geoip.rb +26 -0
- data/demos/filter_known_services.rb +59 -0
- data/demos/filter_netinfo.rb +23 -0
- data/demos/filter_prime.rb +25 -0
- data/demos/filter_profiler.rb +3 -0
- data/demos/filter_redirection.rb +19 -0
- data/demos/filter_site.rb +40 -0
- data/demos/filter_siteip.rb +31 -0
- data/demos/filter_status.rb +17 -0
- data/demos/filter_timestamp.rb +23 -0
- data/demos/filter_url.rb +19 -0
- data/demos/new_fnd.rb +66 -0
- data/demos/nmap_parser.pl +138 -0
- data/demos/site_format.rb +18 -0
- data/demos/whois_domain.rb +78 -0
- data/dicts/GeoIP.dat +0 -0
- data/dicts/GeoIPASNum.dat +0 -0
- data/dicts/GeoLiteCity.dat +0 -0
- data/dicts/ccsld.txt +2646 -0
- data/dicts/cctld.txt +243 -0
- data/dicts/gtld.txt +25 -0
- data/dicts/hostnames-dict.big +1402 -0
- data/dicts/hostnames-dict.txt +101 -0
- data/lib/wmap/cidr_tracker.rb +327 -0
- data/lib/wmap/dns_bruter.rb +308 -0
- data/lib/wmap/domain_tracker/sub_domain.rb +142 -0
- data/lib/wmap/domain_tracker.rb +342 -0
- data/lib/wmap/geoip_tracker.rb +72 -0
- data/lib/wmap/google_search_scraper.rb +177 -0
- data/lib/wmap/host_tracker/primary_host.rb +130 -0
- data/lib/wmap/host_tracker.rb +550 -0
- data/lib/wmap/network_profiler.rb +144 -0
- data/lib/wmap/port_scanner.rb +208 -0
- data/lib/wmap/site_tracker/deactivated_site.rb +85 -0
- data/lib/wmap/site_tracker.rb +937 -0
- data/lib/wmap/url_checker.rb +314 -0
- data/lib/wmap/url_crawler.rb +381 -0
- data/lib/wmap/utils/domain_root.rb +184 -0
- data/lib/wmap/utils/logger.rb +53 -0
- data/lib/wmap/utils/url_magic.rb +343 -0
- data/lib/wmap/utils/utils.rb +333 -0
- data/lib/wmap/whois.rb +76 -0
- data/lib/wmap.rb +227 -0
- data/logs/wmap.log +17 -0
- data/ruby_whois_patches/base_cocca2.rb +149 -0
- data/ruby_whois_patches/kero.yachay.pe.rb +120 -0
- data/ruby_whois_patches/whois.PublicDomainRegistry.com.rb +124 -0
- data/ruby_whois_patches/whois.above.com.rb +61 -0
- data/ruby_whois_patches/whois.adamsnames.tc.rb +107 -0
- data/ruby_whois_patches/whois.aeda.net.ae.rb +105 -0
- data/ruby_whois_patches/whois.ai.rb +112 -0
- data/ruby_whois_patches/whois.arnes.si.rb +121 -0
- data/ruby_whois_patches/whois.ascio.com.rb +91 -0
- data/ruby_whois_patches/whois.cnnic.cn.rb +123 -0
- data/ruby_whois_patches/whois.corporatedomains.com.rb +67 -0
- data/ruby_whois_patches/whois.crsnic.net.rb +108 -0
- data/ruby_whois_patches/whois.denic.de.rb +174 -0
- data/ruby_whois_patches/whois.dk-hostmaster.dk.rb +120 -0
- data/ruby_whois_patches/whois.dns.be.rb +134 -0
- data/ruby_whois_patches/whois.dns.lu.rb +129 -0
- data/ruby_whois_patches/whois.dns.pl.rb +150 -0
- data/ruby_whois_patches/whois.dns.pt.rb +119 -0
- data/ruby_whois_patches/whois.domain.kg.rb +126 -0
- data/ruby_whois_patches/whois.domainregistry.my.rb +123 -0
- data/ruby_whois_patches/whois.domreg.lt.rb +110 -0
- data/ruby_whois_patches/whois.dot.tk.rb +140 -0
- data/ruby_whois_patches/whois.hkirc.hk.rb +121 -0
- data/ruby_whois_patches/whois.isnic.is.rb +130 -0
- data/ruby_whois_patches/whois.je.rb +119 -0
- data/ruby_whois_patches/whois.jprs.jp.rb +137 -0
- data/ruby_whois_patches/whois.kenic.or.ke.rb +140 -0
- data/ruby_whois_patches/whois.markmonitor.com.rb +118 -0
- data/ruby_whois_patches/whois.melbourneit.com.rb +58 -0
- data/ruby_whois_patches/whois.nic.as.rb +96 -0
- data/ruby_whois_patches/whois.nic.at.rb +109 -0
- data/ruby_whois_patches/whois.nic.ch.rb +141 -0
- data/ruby_whois_patches/whois.nic.cl.rb +117 -0
- data/ruby_whois_patches/whois.nic.ec.rb +157 -0
- data/ruby_whois_patches/whois.nic.im.rb +120 -0
- data/ruby_whois_patches/whois.nic.it.rb +170 -0
- data/ruby_whois_patches/whois.nic.lv.rb +116 -0
- data/ruby_whois_patches/whois.nic.ly.rb +127 -0
- data/ruby_whois_patches/whois.nic.mu.rb +27 -0
- data/ruby_whois_patches/whois.nic.mx.rb +123 -0
- data/ruby_whois_patches/whois.nic.net.sa.rb +111 -0
- data/ruby_whois_patches/whois.nic.or.kr.rb +101 -0
- data/ruby_whois_patches/whois.nic.tel.rb +129 -0
- data/ruby_whois_patches/whois.nic.tr.rb +133 -0
- data/ruby_whois_patches/whois.nic.us.rb +129 -0
- data/ruby_whois_patches/whois.nic.ve.rb +135 -0
- data/ruby_whois_patches/whois.norid.no.rb +127 -0
- data/ruby_whois_patches/whois.pandi.or.id.rb +118 -0
- data/ruby_whois_patches/whois.psi-usa.info.rb +63 -0
- data/ruby_whois_patches/whois.registro.br.rb +109 -0
- data/ruby_whois_patches/whois.registrygate.com.rb +55 -0
- data/ruby_whois_patches/whois.rrpproxy.net.rb +61 -0
- data/ruby_whois_patches/whois.sgnic.sg.rb +130 -0
- data/ruby_whois_patches/whois.srs.net.nz.rb +166 -0
- data/ruby_whois_patches/whois.tucows.com.rb +70 -0
- data/ruby_whois_patches/whois.twnic.net.tw.rb +133 -0
- data/settings/discovery_ports +24 -0
- data/settings/google_keywords.txt +9 -0
- data/settings/google_locator.txt +23 -0
- data/test/domain_tracker_test.rb +31 -0
- data/test/utils_test.rb +168 -0
- data/version.txt +13 -0
- data/wmap.gemspec +49 -0
- metadata +202 -0
@@ -0,0 +1,308 @@
|
|
1
|
+
#--
|
2
|
+
# Wmap
|
3
|
+
#
|
4
|
+
# A pure Ruby library for the Internet web application discovery and tracking.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2012-2015 Yang Li <yang.li@owasp.org>
|
7
|
+
#++
|
8
|
+
require "dnsruby"
|
9
|
+
require "parallel"
|
10
|
+
|
11
|
+
|
12
|
+
# Class to discover valid hosts through either zone transfer or DNS brute-force methods
|
13
|
+
class Wmap::DnsBruter
|
14
|
+
include Wmap::Utils
|
15
|
+
|
16
|
+
attr_accessor :hosts_dict, :verbose, :max_parallel, :data_dir
|
17
|
+
attr_reader :discovered_hosts_from_dns_bruter, :fail_domain_cnt
|
18
|
+
|
19
|
+
# Set default instance variables
|
20
|
+
def initialize (params = {})
|
21
|
+
# Change to your brute-force dictionary file here if necessary
|
22
|
+
@data_dir=params.fetch(:data_dir, File.dirname(__FILE__)+'/../../data/')
|
23
|
+
@file_hosts = @data_dir + 'hosts'
|
24
|
+
@file_hosts_dict = File.dirname(__FILE__)+'/../../dicts/hostnames-dict.txt'
|
25
|
+
|
26
|
+
@verbose=params.fetch(:verbose, false)
|
27
|
+
@discovered_hosts_from_dns_bruter=Hash.new
|
28
|
+
@hosts_dict=params.fetch(:hosts_dict, @file_hosts_dict)
|
29
|
+
@max_parallel=params.fetch(:max_parallel, 30)
|
30
|
+
@fail_domain_cnt=Hash.new
|
31
|
+
end
|
32
|
+
|
33
|
+
# Main worker to perform the brute-forcing on an Internet domain
|
34
|
+
def dns_brute_worker(host)
|
35
|
+
puts "Start DNS brute forcer on: #{host}"
|
36
|
+
results=Hash.new
|
37
|
+
domain=get_domain_root(host)
|
38
|
+
begin
|
39
|
+
host=host.strip.downcase
|
40
|
+
raise "Invalid internet host format: #{host}" unless is_fqdn?(host)
|
41
|
+
domain=get_domain_root(host)
|
42
|
+
# If we can do the zone transfer, then the brute-force process can be skipped.
|
43
|
+
if zone_transferable?(domain)
|
44
|
+
hosts=zone_transfer(domain)
|
45
|
+
else
|
46
|
+
hosts=brute_force_dns(host)
|
47
|
+
end
|
48
|
+
results[domain]=hosts
|
49
|
+
puts "Finish discovery on #{host}: #{results}"
|
50
|
+
return results
|
51
|
+
rescue Exception=>ee
|
52
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
53
|
+
return results
|
54
|
+
end
|
55
|
+
end
|
56
|
+
alias_method :query, :dns_brute_worker
|
57
|
+
alias_method :brute, :dns_brute_worker
|
58
|
+
|
59
|
+
# Parallel DNS brute-forcer operating on target domain list - by utilizing fork manager to spawn multiple child processes on multiple domains simultaneously
|
60
|
+
def dns_brute_workers(list,num=@max_parallel)
|
61
|
+
puts "Start the parallel engine one the domain list: #{list} \nMaximum brute-forcing session: #{num} "
|
62
|
+
begin
|
63
|
+
targets=list.uniq.keep_if { |x| is_fqdn?(x) }
|
64
|
+
results=Hash.new
|
65
|
+
Parallel.map(targets, :in_processes => num) { |target|
|
66
|
+
dns_brute_worker(target)
|
67
|
+
}.each do |process|
|
68
|
+
if process.nil?
|
69
|
+
next
|
70
|
+
elsif process.empty?
|
71
|
+
#do nothing in case of thrown an empty array
|
72
|
+
else
|
73
|
+
#domain=get_domain_root(process.first).downcase
|
74
|
+
results.merge!(process)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
puts "Parallel DNS brute-force results: #{results}" if @verbose
|
78
|
+
@discovered_hosts_from_dns_bruter.merge!(results)
|
79
|
+
return results
|
80
|
+
rescue Exception => ee
|
81
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
82
|
+
end
|
83
|
+
end
|
84
|
+
alias_method :queries, :dns_brute_workers
|
85
|
+
alias_method :brutes, :dns_brute_workers
|
86
|
+
|
87
|
+
# Parallel DNS brute-forcer operating on target domain file - by utilizing fork manager to spawn multiple child processes on multiple domains simultaneously
|
88
|
+
def dns_brute_file(file_target,num=@max_parallel)
|
89
|
+
puts "Start the parallel brute-forcing with multiple child processes on target file #{file_target}: #{num}"
|
90
|
+
begin
|
91
|
+
hosts=Array.new
|
92
|
+
targets=file_2_list(file_target)
|
93
|
+
hosts=dns_brute_workers(targets,num)
|
94
|
+
return hosts
|
95
|
+
rescue Exception => ee
|
96
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
97
|
+
return hosts
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Perform zone transfer on a domain, return found host entries in an array
|
102
|
+
def zone_transfer(domain)
|
103
|
+
puts "Perform zone transfer on zone: #{domain}"
|
104
|
+
domain=domain.downcase
|
105
|
+
nameservers = get_nameservers(domain)
|
106
|
+
hosts=Array.new
|
107
|
+
puts "Retrieved name servers: #{nameservers}" if @verbose
|
108
|
+
nameservers.each do |nssrv|
|
109
|
+
begin
|
110
|
+
puts "Attempt zone transfer on name server: #{nssrv}"
|
111
|
+
if nssrv.nil?
|
112
|
+
abort "Method input variable error: no name server found!" if @verbose
|
113
|
+
next
|
114
|
+
end
|
115
|
+
zt = Dnsruby::ZoneTransfer.new
|
116
|
+
zt.server=nssrv unless nssrv.empty?
|
117
|
+
records = zt.transfer(domain)
|
118
|
+
if records==nil
|
119
|
+
puts "Zone transfer failed for zone #{domain} on: #{nssrv}"
|
120
|
+
next
|
121
|
+
else
|
122
|
+
puts "Zone transfer successfully for zone #{domain} on the name server: #{nssrv}"
|
123
|
+
records = records.delete_if {|x| not x.to_s=~/(\s+|\t+)IN/ }
|
124
|
+
records.each { |line| puts line.to_s } if @verbose
|
125
|
+
hosts=records.collect {|x| x.to_s.split(/\.(\s+|\t+)/).first}
|
126
|
+
hosts=hosts.sort!.uniq!
|
127
|
+
puts "Found hosts: #{hosts}" if @verbose
|
128
|
+
@discovered_hosts_from_dns_bruter[domain] = hosts
|
129
|
+
return hosts
|
130
|
+
end
|
131
|
+
rescue Exception=>ee
|
132
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
133
|
+
end
|
134
|
+
end
|
135
|
+
return hosts
|
136
|
+
end
|
137
|
+
|
138
|
+
# Test the DNS server if zone transfer is allowed. If allowed, save the found hosts into the class variable.
|
139
|
+
def get_vulnerable_ns(domain)
|
140
|
+
puts "Identify the vulnerable DNS servers if zone transfer is allowed."
|
141
|
+
domain=domain.strip.downcase
|
142
|
+
vuln=Array.new
|
143
|
+
begin
|
144
|
+
nameservers = get_nameservers(domain)
|
145
|
+
nameservers.each do |nssrv|
|
146
|
+
zt = Dnsruby::ZoneTransfer.new
|
147
|
+
zt.server=nssrv unless nssrv.empty?
|
148
|
+
records = zt.transfer(domain)
|
149
|
+
unless records==nil
|
150
|
+
vuln.push(nssrv)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
return vuln
|
154
|
+
rescue Exception=>ee
|
155
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Return a list of valid hosts by brute-forcing the name servers
|
160
|
+
def brute_force_dns (host)
|
161
|
+
puts "Start dictionary attacks on the DNS server for: #{host}" if @verbose
|
162
|
+
begin
|
163
|
+
host=host.strip
|
164
|
+
valid_hosts = Array.new
|
165
|
+
my_host_tracker = Wmap::HostTracker.new(:data_dir=>@data_dir)
|
166
|
+
# build the host dictionary for the brute force method
|
167
|
+
dict = Array.new
|
168
|
+
if File.exists?(@hosts_dict)
|
169
|
+
dict = file_2_list(@hosts_dict)
|
170
|
+
elsif File.exists?(@file_hosts)
|
171
|
+
dict = my_host_tracker.top_hostname(200)
|
172
|
+
my_host_tracker.list_2_file(dict,@hosts_dict)
|
173
|
+
else
|
174
|
+
abort "Error: Non-existing common hosts dictionary file - #{@host_dict} or hosts file #{@file_hosts}. Please check your file path and name setting again."
|
175
|
+
end
|
176
|
+
domain=String.new
|
177
|
+
unless is_root_domain?(host) or my_host_tracker.sub_domain_known?(host)
|
178
|
+
my_hosts=hostname_mutation(host).map {|x| x.split('.')[0]}
|
179
|
+
dict+=my_hosts unless my_hosts.empty?
|
180
|
+
end
|
181
|
+
if is_domain?(host) or my_host_tracker.sub_domain_known?(host)
|
182
|
+
domain=host
|
183
|
+
elsif
|
184
|
+
array_h=host.split('.')
|
185
|
+
array_h.shift
|
186
|
+
domain=array_h.join('.')
|
187
|
+
puts "Domain for #{host}: #{domain}" if @verbose
|
188
|
+
end
|
189
|
+
dict+=[host.split(".")[0],""]
|
190
|
+
puts "Choose Brute-force Dictionary: #{dict}" if @verbose
|
191
|
+
cnt=0
|
192
|
+
dict.each do |x|
|
193
|
+
# 10/09/2013 add logic to skip brute-forcing the domain in case of experiencing more than 2 Dnsruby::ServFail conditions
|
194
|
+
if @fail_domain_cnt.key?(domain)
|
195
|
+
if @fail_domain_cnt[domain]>2
|
196
|
+
puts "Error! Multiple ServFail conditions detected in method #{__method__}. Now skip remaining works on: #{sub_domain}" if @verbose
|
197
|
+
return valid_hosts
|
198
|
+
end
|
199
|
+
end
|
200
|
+
cnt=cnt+1
|
201
|
+
if x.nil?
|
202
|
+
next
|
203
|
+
elsif x.empty?
|
204
|
+
host=domain
|
205
|
+
else
|
206
|
+
host=[x,".",domain].join.downcase
|
207
|
+
end
|
208
|
+
valid_hosts.push(host) if valid_dns_record?(host)
|
209
|
+
# Logic to detecting the bluff if the DNS server return hostname we threw to it
|
210
|
+
if cnt==10 && valid_hosts.size>=10
|
211
|
+
valid_hosts=[host]
|
212
|
+
puts "Brute force method fail, as the DNS server response to every host-name threw at it!"
|
213
|
+
break
|
214
|
+
end
|
215
|
+
end
|
216
|
+
puts "Found DNS records on domain #{host}: #{valid_hosts}" if @verbose
|
217
|
+
@discovered_hosts_from_dns_bruter[host] = valid_hosts
|
218
|
+
my_host_tracker = nil
|
219
|
+
return valid_hosts.uniq
|
220
|
+
rescue Exception => ee
|
221
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Parallel DNS brute-forcer operating on the trusted domains - by utilizing fork manager to spawn multiple child processes on multiple sub_domain domains from the local hosts table simultaneously
|
226
|
+
def dns_brute_domains(targets,num=@max_parallel)
|
227
|
+
puts "Start the parallel brute-forcing with multiple child processes: #{num}"
|
228
|
+
begin
|
229
|
+
hosts=Array.new
|
230
|
+
# Sliced to chunks of 1,000 domains for each process time, to avoid potential overflow of large array ?
|
231
|
+
puts "Brute-forcing the following domain: #{targets}" if @verbose
|
232
|
+
targets.each_slice(1000).to_a.map do |slice|
|
233
|
+
hosts_new=dns_brute_workers(slice,num)
|
234
|
+
hosts << hosts_new
|
235
|
+
end
|
236
|
+
puts "Parallel bruting result: #{hosts.flatten}" if @verbose
|
237
|
+
return hosts.flatten
|
238
|
+
rescue Exception => ee
|
239
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
240
|
+
return hosts.flatten
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Parallel DNS brute-force all existing domains
|
245
|
+
def brute_all(num=@max_parallel)
|
246
|
+
puts "Start the parallel brute-forcing all domains with maximum child processes: #{num}"
|
247
|
+
begin
|
248
|
+
hosts=Array.new
|
249
|
+
my_dis=Wmap::HostTracker.new(:data_dir=>@data_dir)
|
250
|
+
known_domains=my_dis.dump_root_domains
|
251
|
+
hosts=dns_brute_domains(num, known_domains)
|
252
|
+
my_dis.adds(hosts)
|
253
|
+
my_dis.save!
|
254
|
+
my_dis=nil
|
255
|
+
hosts
|
256
|
+
rescue Exception => ee
|
257
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Return a list of hosts in the mutation form from the original, i.e. "ww1.example.com" => ["ww1,example.com","ww2.example.com",...]
|
262
|
+
def hostname_mutation(host)
|
263
|
+
puts "Start host mutation emulation on: #{host}" if @verbose
|
264
|
+
begin
|
265
|
+
hosts=Array.new
|
266
|
+
host=host.strip.downcase
|
267
|
+
raise "Invalid host format: #{host}" unless is_fqdn?(host)
|
268
|
+
unless is_domain_root?(host)
|
269
|
+
hostname=host.split('.')[0]
|
270
|
+
hosts.push(host)
|
271
|
+
case hostname
|
272
|
+
when /\d+/
|
273
|
+
#first form of mutation, i.e. "ww1" => ["ww1","ww2",...]
|
274
|
+
hostname.scan(/\d+/).map do |x|
|
275
|
+
y=x.to_i
|
276
|
+
5.times do |i|
|
277
|
+
z=y+i+1
|
278
|
+
w=(y-i-1).abs
|
279
|
+
mut1=host.sub_domain(x,z.to_s)
|
280
|
+
mut2=host.sub_domain(x,w.to_s)
|
281
|
+
hosts.push(mut1,mut2)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
else
|
285
|
+
puts "No mutation found for: #{host}" if @verbose
|
286
|
+
end
|
287
|
+
end
|
288
|
+
puts "Host mutation found: #{hosts.uniq}" if @verbose
|
289
|
+
return hosts.uniq
|
290
|
+
rescue Exception => ee
|
291
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
292
|
+
return hosts # fail-safe
|
293
|
+
end
|
294
|
+
end
|
295
|
+
alias_method :mutation, :hostname_mutation
|
296
|
+
|
297
|
+
# Print summary report of found hosts from the brute force attacks
|
298
|
+
def print_discovered_hosts_from_bruter
|
299
|
+
puts "\nSummary Report of the Discovered Hosts:"
|
300
|
+
@discovered_hosts_from_dns_bruter.each do |domain,hosts|
|
301
|
+
puts "Domain: #{domain}"
|
302
|
+
puts "Found hosts:"
|
303
|
+
puts @discovered_hosts_from_dns_bruter[domain]['hosts']
|
304
|
+
end
|
305
|
+
puts "End of the summary"
|
306
|
+
end
|
307
|
+
alias_method :print, :print_discovered_hosts_from_bruter
|
308
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
#--
|
2
|
+
# Wmap
|
3
|
+
#
|
4
|
+
# A pure Ruby library for Internet web application discovery and tracking.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2012-2015 Yang Li <yang.li@owasp.org>
|
7
|
+
#++
|
8
|
+
#require "singleton"
|
9
|
+
|
10
|
+
|
11
|
+
module Wmap
|
12
|
+
class DomainTracker
|
13
|
+
|
14
|
+
# Class to differentiate the sub-domain from the top domain for the enterprise. This is needed for better managing
|
15
|
+
# of the sub-domains and the associated entities
|
16
|
+
class SubDomain < Wmap::DomainTracker
|
17
|
+
include Wmap::Utils
|
18
|
+
#include Singleton
|
19
|
+
|
20
|
+
attr_accessor :verbose, :domains_file, :max_parallel, :data_dir
|
21
|
+
attr_reader :known_internet_sub_domains
|
22
|
+
|
23
|
+
# Set default instance variables
|
24
|
+
def initialize (params = {})
|
25
|
+
@verbose=params.fetch(:verbose, false)
|
26
|
+
@data_dir=params.fetch(:data_dir, File.dirname(__FILE__)+'/../../../data/')
|
27
|
+
@max_parallel=params.fetch(:max_parallel, 40)
|
28
|
+
# Hash table to hold the trusted domains
|
29
|
+
@file_sub_domains=@data_dir + 'sub_domains'
|
30
|
+
File.write(@file_sub_domains, "") unless File.exist?(@file_sub_domains)
|
31
|
+
@known_internet_sub_domains=load_domains_from_file(@file_sub_domains) #unless @known_internet_sub_domains.size>0
|
32
|
+
end
|
33
|
+
|
34
|
+
# 'setter' to add sub-domain entry to the cache one at a time
|
35
|
+
def add(sub)
|
36
|
+
puts "Add entry to the local sub domain cache table: #{sub}" if @verbose
|
37
|
+
begin
|
38
|
+
record=Hash.new
|
39
|
+
sub=sub.strip.downcase
|
40
|
+
if @known_internet_sub_domains.key?(sub)
|
41
|
+
puts "Skip on known sub-domain: #{sub}" if @verbose
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
if zone_transferable?(sub)
|
45
|
+
record[sub]=true
|
46
|
+
else
|
47
|
+
record[sub]=false
|
48
|
+
end
|
49
|
+
puts "Adding new record into the data store: #{record}" if @verbose
|
50
|
+
@known_internet_sub_domains.merge!(record)
|
51
|
+
return record
|
52
|
+
rescue => ee
|
53
|
+
puts "Exception on method #{__method__} for #{sub}: #{ee}" if @verbose
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# 'setter' to add domain entry to the cache in batch (from a list)
|
58
|
+
def bulk_add(list, num=@max_parallel)
|
59
|
+
puts "Add entries to the local domains cache table from list: #{list}" if @verbose
|
60
|
+
begin
|
61
|
+
results=Hash.new
|
62
|
+
domains=list
|
63
|
+
if domains.size > 0
|
64
|
+
Parallel.map(list, :in_processes => num) { |target|
|
65
|
+
add(target)
|
66
|
+
}.each do |process|
|
67
|
+
if process.nil?
|
68
|
+
next
|
69
|
+
elsif process.empty?
|
70
|
+
#do nothing
|
71
|
+
else
|
72
|
+
results.merge!(process)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
@known_internet_sub_domains.merge!(results)
|
76
|
+
puts "Done loading entries."
|
77
|
+
return results
|
78
|
+
else
|
79
|
+
puts "Error: no entry is loaded. Please check your list and try again."
|
80
|
+
end
|
81
|
+
return results
|
82
|
+
rescue => ee
|
83
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
84
|
+
end
|
85
|
+
end
|
86
|
+
alias_method :adds, :bulk_add
|
87
|
+
|
88
|
+
# Procedures to identify sub-domain from the hosts store
|
89
|
+
def update_from_host_store!
|
90
|
+
puts "Invoke internal procedures to update the sub-domain list from the host store."
|
91
|
+
begin
|
92
|
+
# Step 1 - obtain the latest sub-domains
|
93
|
+
subs = Wmap::HostTracker.new(:data_dir=>@data_dir).dump_sub_domains - [nil,""]
|
94
|
+
# Step 2 - update the sub-domain list
|
95
|
+
unless subs.empty?
|
96
|
+
#subs.map { |x| self.add(x) unless domain_known?(x) }
|
97
|
+
self.bulk_add(subs,@max_parallel)
|
98
|
+
end
|
99
|
+
puts "Update discovered sub-domains into the store: #{@known_internet_sub_domains}"
|
100
|
+
self.save!(file_domains=@file_sub_domains, domains=@known_internet_sub_domains)
|
101
|
+
rescue Exception => ee
|
102
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
103
|
+
return nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
alias_method :update!, :update_from_host_store!
|
107
|
+
|
108
|
+
# Save the current domain hash table into a file
|
109
|
+
def save_sub_domains_to_file!(file_domains=@file_sub_domains, domains=@known_internet_sub_domains)
|
110
|
+
puts "Saving the current domains cache table from memory to file: #{file_domains} ..." if @verbose
|
111
|
+
begin
|
112
|
+
timestamp=Time.now
|
113
|
+
f=File.open(file_domains, 'w')
|
114
|
+
f.write "# Local domains file created by class #{self.class} method #{__method__} at: #{timestamp}\n"
|
115
|
+
f.write "# domain name, free zone transfer detected?\n"
|
116
|
+
domains.keys.sort.map do |key|
|
117
|
+
if domains[key]
|
118
|
+
f.write "#{key}, yes\n"
|
119
|
+
else
|
120
|
+
f.write "#{key}, no\n"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
f.close
|
124
|
+
puts "Domain cache table is successfully saved: #{file_domains}"
|
125
|
+
rescue => ee
|
126
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
127
|
+
end
|
128
|
+
end
|
129
|
+
alias_method :save!, :save_sub_domains_to_file!
|
130
|
+
end
|
131
|
+
|
132
|
+
# Print summary report on all known / trust domains in the domain cache table
|
133
|
+
def print_known_sub_domains
|
134
|
+
puts "\nSummary of known Internet Sub-domains:"
|
135
|
+
self.known_internet_sub_domains.keys.sort.each do |domain|
|
136
|
+
puts domain
|
137
|
+
end
|
138
|
+
puts "End of the summary"
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|