module Msf
module Ui
module Console
module CommandDispatcher

###
#
# Exploit module command dispatcher.
#
###
class Exploit

	include Msf::Ui::Console::ModuleCommandDispatcher

	@@exploit_opts = Rex::Parser::Arguments.new(
		"-e" => [ true,  "The payload encoder to use.  If none is specified, ENCODER is used." ],
		"-f" => [ false, "Force the exploit to run regardless of the value of MinimumRank."    ],
		"-h" => [ false, "Help banner."                                                        ],
		"-j" => [ false, "Run in the context of a job."                                        ],
		"-n" => [ true,  "The NOP generator to use.  If none is specified, NOP is used."       ],
		"-o" => [ true,  "A comma separated list of options in VAR=VAL format."                ],
		"-p" => [ true,  "The payload to use.  If none is specified, PAYLOAD is used."         ],
		"-t" => [ true,  "The target index to use.  If none is specified, TARGET is used."     ],
		"-z" => [ false, "Do not interact with the session after successful exploitation."     ])

	#
	# Returns the hash of exploit module specific commands.
	#
	def commands
		{
			"check"    => "Check to see if a target is vulnerable",
			"exploit"  => "Launch an exploit attempt",
			"rcheck"   => "Reloads the module and checks if the target is vulnerable",
			"rexploit" => "Reloads the module and launches an exploit attempt",
		}
	end

	#
	# Returns the name of the command dispatcher.
	#
	def name
		"Exploit"
	end

	#
	# Checks to see if a target is vulnerable.
	#
	def cmd_check(*args)
		defanged?

		begin

			code = mod.check_simple(
				'LocalInput'  => driver.input,
				'LocalOutput' => driver.output)

			if (code and code.kind_of?(Array) and code.length > 1)

				if (code == Msf::Exploit::CheckCode::Vulnerable)
					print_good(code[1])
				else
					print_status(code[1])
				end

			else
				print_error("Check failed: The state could not be determined.")
			end

		rescue ::Interrupt
			raise $!
		rescue ::Exception => e
			print_error("Exploit check failed: #{e.class} #{e}")
			if(e.class.to_s != 'Msf::OptionValidateError')
				print_error("Call stack:")
				e.backtrace.each do |line|
					break if line =~ /lib.msf.base.simple/
					print_error("  #{line}")
				end
			end
		end
	end

	#
	# Launches an exploitation attempt.
	#
	def cmd_exploit(*args)
		defanged?

		opt_str = nil
		payload = mod.datastore['PAYLOAD']
		encoder = mod.datastore['ENCODER']
		target  = mod.datastore['TARGET']
		nop     = mod.datastore['NOP']
		bg      = false
		jobify  = false
		force   = false

		# Always run passive exploits in the background
		if (mod.passive?)
			jobify = true
		end

		@@exploit_opts.parse(args) { |opt, idx, val|
			case opt
				when '-e'
					encoder = val
				when '-f'
					force = true
				when '-j'
					jobify = true
				when '-n'
					nop = val
				when '-o'
					opt_str = val
				when '-p'
					payload = val
				when '-t'
					target = val.to_i
				when '-z'
					bg = true
				when '-h'
					print(
						"Usage: exploit [options]\n\n" +
						"Launches an exploitation attempt.\n" +
						@@exploit_opts.usage)
					return false
			end
		}

		minrank = RankingName.invert[framework.datastore['MinimumRank']] || 0
		if minrank > mod.rank
			if force
				print_status("Forcing #{mod.refname} to run despite MinimumRank '#{framework.datastore['MinimumRank']}'")
				ilog("Forcing #{mod.refname} to run despite MinimumRank '#{framework.datastore['MinimumRank']}'", 'core')
			else
				print_error("This exploit is below the minimum rank, '#{framework.datastore['MinimumRank']}'.")
				print_error("If you really want to run it, do 'exploit -f' or")
				print_error("setg MinimumRank to something lower ('manual' is")
				print_error("the lowest and would allow running all exploits).")
				return
			end
		end
		
		if not payload
			payload = exploit_choose_payload(mod, target)
		end

		begin
			session = mod.exploit_simple(
				'Encoder'        => encoder,
				'Payload'        => payload,
				'Target'         => target,
				'Nop'            => nop,
				'OptionStr'      => opt_str,
				'LocalInput'     => driver.input,
				'LocalOutput'    => driver.output,
				'RunAsJob'       => jobify)
		rescue ::Interrupt
			raise $!
		rescue ::Exception => e
			print_error("Exploit exception (#{mod.refname}): #{e.class} #{e}")
			if(e.class.to_s != 'Msf::OptionValidateError')
				print_error("Call stack:")
				e.backtrace.each do |line|
					break if line =~ /lib.msf.base.simple/
					print_error("  #{line}")
				end
			end
		end

		# If we were given a session, let's see what we can do with it
		if (session)

			# If we aren't told to run in the background and the session can be
			# interacted with, start interacting with it by issuing the session
			# interaction command.
			if (bg == false and session.interactive?)
				print_line

				driver.run_single("sessions -q -i #{session.sid}")
			# Otherwise, log that we created a session
			else
				print_status("Session #{session.sid} created in the background.")
			end
		# If we ran the exploit as a job, indicate such so the user doesn't
		# wonder what's up.
		elsif (jobify)
			if mod.job_id
				print_status("Exploit running as background job.")
			end
		# Worst case, the exploit ran but we got no session, bummer.
		else
			print_status("Exploit completed, but no session was created.")
		end
	end

	#
	# Reloads an exploit module and checks the target to see if it's
	# vulnerable.
	#
	def cmd_rcheck(*args)
		omod = self.mod
		self.mod = framework.modules.reload_module(mod)
		if(not self.mod)
			print_status("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
			self.mod = omod
			return
		end

		self.mod.init_ui(driver.input, driver.output)
		cmd_check(*args)
	end

	#
	# Reloads an exploit module and launches an exploit.
	#
	def cmd_rexploit(*args)
		if mod.job_id
			print_status("Stopping existing job...")

			framework.jobs.stop_job(mod.job_id)
			mod.job_id = nil
		end

		omod = self.mod
		self.mod = framework.modules.reload_module(mod)

		if(not self.mod)
			print_status("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
			self.mod = omod
			return
		end

		self.mod.init_ui(driver.input, driver.output)

		cmd_exploit(*args)
	end
	
	#
	# Picks a reasonable payload and minimally configures it
	#
	def exploit_choose_payload(mod, target)
	
		# Choose either the real target or an invalid address
		# This is used to determine the LHOST value
		rhost = mod.datastore['RHOST'] || '50.50.50.50'
		
		# A list of preferred payloads in the best-first order
		pref = [
			'windows/meterpreter/reverse_tcp',
			'java/meterpreter/reverse_tcp',
			'php/meterpreter/reverse_tcp',
			'php/meterpreter_reverse_tcp',
			'cmd/unix/reverse',
			'cmd/unix/reverse_perl',
			'cmd/unix/reverse_netcat',
			'windows/meterpreter/reverse_nonx_tcp',
			'windows/meterpreter/reverse_ord_tcp',
			'windows/shell/reverse_tcp',
			'generic/shell_reverse_tcp'				
		]
		pset = mod.compatible_payloads.map{|x| x[0] }
		pref.each do |n|
			if(pset.include?(n))
				mod.datastore['PAYLOAD'] = n
				mod.datastore['LHOST']   = Rex::Socket.source_address(rhost)
				return n
			end
		end		
		return
	end

end

end end end end

