forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 2
/
vhost_scanner.rb
151 lines (119 loc) · 3.51 KB
/
vhost_scanner.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'rex/proto/http'
require 'msf/core'
#
# May I reuse some methods?
#
require 'cgi'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::WmapScanServer
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'HTTP Virtual Host Brute Force Scanner',
'Description' => %q{
This module tries to identify unique virtual hosts
hosted by the target web server.
},
'Author' => [ 'et [at] cyberspace.org' ],
'License' => BSD_LICENSE))
register_options(
[
OptString.new('PATH', [ true, "The PATH to use while testing", '/']),
OptString.new('QUERY', [ false, "HTTP URI Query", '']),
OptString.new('DOMAIN', [ true, "Domain name", '']),
OptString.new('HEADERS', [ false, "HTTP Headers", '']),
OptPath.new('SUBDOM_LIST', [false, "Path to text file with subdomains"]),
], self.class)
end
def run_host(ip)
if datastore['SUBDOM_LIST'] and ::File.file?(datastore['SUBDOM_LIST'])
valstr = IO.readlines(datastore['SUBDOM_LIST']).map {
|e| e.gsub(".#{datastore['DOMAIN']}", "").chomp
}
else
valstr = [
"admin",
"services",
"webmail",
"console",
"apps",
"mail",
"intranet",
"intra",
"spool",
"corporate",
"www",
"web"
]
end
datastore['QUERY'] ? tquery = queryparse(datastore['QUERY']): nil
datastore['HEADERS'] ? thead = headersparse(datastore['HEADERS']) : nil
noexistsres = nil
resparr = []
2.times do |n|
randhost = Rex::Text.rand_text_alpha(5)+"."+datastore['DOMAIN']
begin
noexistsres = send_request_cgi({
'uri' => normalize_uri(datastore['PATH']),
'vars_get' => tquery,
'headers' => thead,
'vhost' => randhost,
'method' => 'GET',
'ctype' => 'text/plain'
}, 20)
print_status("[#{ip}] Sending request with random domain #{randhost} ")
if noexistsres
resparr[n] = noexistsres.body
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end
if resparr[0] != resparr[1]
print_error("[#{ip}] Unable to identify error response")
return
end
vprint_status("Running with #{valstr.length} sudomains")
valstr.each do |astr|
thost = astr+"."+datastore['DOMAIN']
begin
res = send_request_cgi({
'uri' => normalize_uri(datastore['PATH']),
'vars_get' => tquery,
'headers' => thead,
'vhost' => thost,
'method' => 'GET',
'ctype' => 'text/plain'
}, 20)
if res and noexistsres
if res.body != noexistsres.body
print_status("[#{ip}] Vhost found #{thost} ")
report_note(
:host => ip,
:proto => 'tcp',
:sname => (ssl ? 'https' : 'http'),
:port => rport,
:type => 'VHOST',
:data => thost,
:update => :unique_data
)
else
vprint_status("NOT Found #{thost}")
end
else
print_status("[#{ip}] NO Response")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end
end
end