ac1fb2d1da
Incidentally, the endmap scanner doesn't appear to work at all for http-rpc-epmap, so no harm done anyway (tested against Windows 2008 server). It looks like a bigger change than it realy is, thanks to the indentaton changes by removing the itertor. Diff this without whitespace changes to get a better idea of what's actually different.
223 lines
5.2 KiB
Ruby
223 lines
5.2 KiB
Ruby
# -*- coding: binary -*-
|
|
module Msf
|
|
|
|
###
|
|
#
|
|
# This module provides service-specific methods for the DCERPC exploit mixin
|
|
#
|
|
###
|
|
module Exploit::Remote::DCERPC_EPM
|
|
|
|
# Contact the endpoint mapper of the target host and find the transport
|
|
def dcerpc_endpoint_find_tcp(host, uuid, vers, transport)
|
|
res = dcerpc_endpoint_list()
|
|
return nil if not res
|
|
|
|
res.each do |ent|
|
|
if (ent[:uuid] == uuid and ent[:vers] == vers and ent[:prot] == 'tcp')
|
|
return ent[:port]
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# Contact the endpoint mapper of the target host and find the transport
|
|
def dcerpc_endpoint_find_udp(host, uuid, vers, transport)
|
|
res = dcerpc_endpoint_list()
|
|
return nil if not res
|
|
|
|
res.each do |ent|
|
|
if (ent[:uuid] == uuid and ent[:vers] == vers and ent[:prot] == 'udp')
|
|
return ent[:port]
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# Contact the endpoint mapper and create a hash of all endpoints
|
|
def dcerpc_endpoint_list
|
|
res = []
|
|
|
|
print_status("Connecting to the endpoint mapper service...")
|
|
begin
|
|
eps = nil
|
|
dport = datastore['RPORT'] || 135
|
|
|
|
begin
|
|
eps = Rex::Socket::Tcp.create(
|
|
'PeerHost' => rhost,
|
|
'PeerPort' => dport,
|
|
'Proxies' => proxies,
|
|
'Context' =>
|
|
{
|
|
'Msf' => framework,
|
|
'MsfExploit' => self,
|
|
}
|
|
)
|
|
rescue ::Exception
|
|
end
|
|
|
|
if (not eps)
|
|
print_status("Could not connect to the endpoint mapper service")
|
|
return nil
|
|
end
|
|
|
|
eph = dcerpc_handle('e1af8308-5d1f-11c9-91a4-08002b14a0fa', '3.0', 'ncacn_ip_tcp', [dport])
|
|
opt = { 'Msf' => framework, 'MsfExploit' => self }
|
|
dce = Rex::Proto::DCERPC::Client.new(eph, eps, opt)
|
|
|
|
hnd = nil
|
|
|
|
while(true)
|
|
|
|
# Placeholders
|
|
info =
|
|
{
|
|
:type => nil,
|
|
:port => nil,
|
|
:host => nil,
|
|
:pipe => nil,
|
|
:prot => nil,
|
|
:uuid => nil,
|
|
:vers => nil,
|
|
:note => nil
|
|
}
|
|
|
|
data = nil
|
|
|
|
if(not hnd)
|
|
# NULL handle to start with
|
|
data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1].pack("V*")
|
|
else
|
|
# Break the loop early if we get another NULL handle
|
|
break if hnd == [0, 0, 0, 0, 1].pack("V*")
|
|
|
|
# Use the existing handle if we already have one
|
|
data = [0, 0, 0, 0, 0].pack("V*") + hnd
|
|
end
|
|
|
|
ret = dce.call(2, data)
|
|
|
|
if (
|
|
dce.last_response == nil or
|
|
dce.last_response.stub_data == nil or
|
|
dce.last_response.stub_data.length < 40 or
|
|
dce.last_response.stub_data[36,4] == "\xd6\xa0\xc9\x16"
|
|
)
|
|
# break from the parsing loop
|
|
break
|
|
end
|
|
|
|
# Record the response data
|
|
buf = dce.last_response.stub_data
|
|
|
|
# Record the handle if needed
|
|
hnd = buf[4, 20] if not hnd
|
|
|
|
# Parse the response data
|
|
nlen = buf[60, 4].unpack('V')[0]
|
|
if (nlen > 1)
|
|
info[:note] = buf[64, nlen - 1]
|
|
end
|
|
|
|
# Align the stub offset
|
|
soff = nlen + 72
|
|
while (soff % 4 != 0)
|
|
soff += 1
|
|
end
|
|
|
|
# Determine number of records
|
|
rcnt = buf[soff, 2].unpack('v')[0]
|
|
soff += 2
|
|
|
|
# Parse the data from the stack
|
|
1.upto(rcnt) do |i|
|
|
rlen = buf[soff, 2].unpack('v')[0]
|
|
soff += 2
|
|
|
|
if (i == 1)
|
|
info[:uuid] = Rex::Proto::DCERPC::UUID.uuid_unpack(buf[soff+1, 16])
|
|
info[:vers] = buf[soff+17,2].unpack('CC').map{|s| s.to_s}.join(".")
|
|
end
|
|
|
|
if (i > 3)
|
|
info[:type] = buf[soff, 1].unpack("C*")[0]
|
|
end
|
|
|
|
soff += rlen
|
|
|
|
xlen = buf[soff, 2].unpack('v')[0]
|
|
soff += 2
|
|
|
|
case info[:type]
|
|
when nil
|
|
|
|
# TCP
|
|
when 7
|
|
info[:prot] = 'tcp'
|
|
info[:port] = buf[soff, 2].unpack('n')[0]
|
|
|
|
# UDP
|
|
when 8
|
|
info[:prot] = 'udp'
|
|
info[:port] = buf[soff, 2].unpack('n')[0]
|
|
|
|
# ADDR
|
|
when 9
|
|
info[:host] = buf[soff, 4].unpack('C4').join('.')
|
|
|
|
# PIPE
|
|
when 15
|
|
info[:prot] = 'pipe'
|
|
info[:pipe] = buf[soff, xlen].unpack("a*")[0]
|
|
|
|
# LRPC
|
|
when 16
|
|
info[:prot] = 'lrpc'
|
|
info[:pipe] = buf[soff, xlen].unpack("a*")[0]
|
|
|
|
# NETBIOS
|
|
when 17,24
|
|
info[:host] = buf[soff, xlen].unpack("a*")[0]
|
|
|
|
# HTTP
|
|
when 31
|
|
info[:prot] = 'http'
|
|
info[:port] = buf[soff, 2].unpack('n')[0]
|
|
|
|
# DYNAMIC?
|
|
when 22
|
|
# not parsed
|
|
else
|
|
print_status("EPM unknown type: #{info[:type]} #{buf[soff, xlen].unpack("H*")[0]}")
|
|
end
|
|
|
|
soff += xlen
|
|
end
|
|
|
|
info[:pipe].gsub!("\x00", '') if info[:pipe]
|
|
info[:host].gsub!("\x00", '') if info[:host]
|
|
|
|
res << info
|
|
|
|
# Handle a buggy response from a Likewise server that can result in a loop otherwise
|
|
break if hnd == [0, 0, 0, 0, 0, 0, 0, 0, 0, 1].pack("V*")
|
|
end
|
|
|
|
rescue ::Interrupt
|
|
raise $!
|
|
|
|
rescue ::Exception => e
|
|
print_status("Could not obtain the endpoint list: #{e}")
|
|
res = nil
|
|
end
|
|
|
|
res
|
|
end
|
|
|
|
end
|
|
end
|
|
|