wmap 2.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|