# -*- 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