Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dcerpc_epm.rb 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. # -*- coding: binary -*-
  2. module Msf
  3. ###
  4. #
  5. # This module provides service-specific methods for the DCERPC exploit mixin
  6. #
  7. ###
  8. module Exploit::Remote::DCERPC_EPM
  9. # Contact the endpoint mapper of the target host and find the transport
  10. def dcerpc_endpoint_find_tcp(host, uuid, vers, transport)
  11. res = dcerpc_endpoint_list()
  12. return nil if not res
  13. res.each do |ent|
  14. if (ent[:uuid] == uuid and ent[:vers] == vers and ent[:prot] == 'tcp')
  15. return ent[:port]
  16. end
  17. end
  18. nil
  19. end
  20. # Contact the endpoint mapper of the target host and find the transport
  21. def dcerpc_endpoint_find_udp(host, uuid, vers, transport)
  22. res = dcerpc_endpoint_list()
  23. return nil if not res
  24. res.each do |ent|
  25. if (ent[:uuid] == uuid and ent[:vers] == vers and ent[:prot] == 'udp')
  26. return ent[:port]
  27. end
  28. end
  29. nil
  30. end
  31. # Contact the endpoint mapper and create a hash of all endpoints
  32. def dcerpc_endpoint_list
  33. res = []
  34. print_status("Connecting to the endpoint mapper service...")
  35. begin
  36. eps = nil
  37. dport = datastore['RPORT'] || 135
  38. begin
  39. eps = Rex::Socket::Tcp.create(
  40. 'PeerHost' => rhost,
  41. 'PeerPort' => dport,
  42. 'Proxies' => proxies,
  43. 'Context' =>
  44. {
  45. 'Msf' => framework,
  46. 'MsfExploit' => self,
  47. }
  48. )
  49. rescue ::Exception
  50. end
  51. if (not eps)
  52. print_status("Could not connect to the endpoint mapper service")
  53. return nil
  54. end
  55. eph = dcerpc_handle('e1af8308-5d1f-11c9-91a4-08002b14a0fa', '3.0', 'ncacn_ip_tcp', [dport])
  56. opt = { 'Msf' => framework, 'MsfExploit' => self }
  57. dce = Rex::Proto::DCERPC::Client.new(eph, eps, opt)
  58. hnd = nil
  59. while(true)
  60. # Placeholders
  61. info =
  62. {
  63. :type => nil,
  64. :port => nil,
  65. :host => nil,
  66. :pipe => nil,
  67. :prot => nil,
  68. :uuid => nil,
  69. :vers => nil,
  70. :note => nil
  71. }
  72. data = nil
  73. if(not hnd)
  74. # NULL handle to start with
  75. data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1].pack("V*")
  76. else
  77. # Break the loop early if we get another NULL handle
  78. break if hnd == [0, 0, 0, 0, 1].pack("V*")
  79. # Use the existing handle if we already have one
  80. data = [0, 0, 0, 0, 0].pack("V*") + hnd
  81. end
  82. ret = dce.call(2, data)
  83. if (
  84. dce.last_response == nil or
  85. dce.last_response.stub_data == nil or
  86. dce.last_response.stub_data.length < 40 or
  87. dce.last_response.stub_data[36,4] == "\xd6\xa0\xc9\x16"
  88. )
  89. # break from the parsing loop
  90. break
  91. end
  92. # Record the response data
  93. buf = dce.last_response.stub_data
  94. # Record the handle if needed
  95. hnd = buf[4, 20] if not hnd
  96. # Parse the response data
  97. nlen = buf[60, 4].unpack('V')[0]
  98. if (nlen > 1)
  99. info[:note] = buf[64, nlen - 1]
  100. end
  101. # Align the stub offset
  102. soff = nlen + 72
  103. while (soff % 4 != 0)
  104. soff += 1
  105. end
  106. # Determine number of records
  107. rcnt = buf[soff, 2].unpack('v')[0]
  108. soff += 2
  109. # Parse the data from the stack
  110. 1.upto(rcnt) do |i|
  111. rlen = buf[soff, 2].unpack('v')[0]
  112. soff += 2
  113. if (i == 1)
  114. info[:uuid] = Rex::Proto::DCERPC::UUID.uuid_unpack(buf[soff+1, 16])
  115. info[:vers] = buf[soff+17,2].unpack('CC').map{|s| s.to_s}.join(".")
  116. end
  117. if (i > 3)
  118. info[:type] = buf[soff, 1].unpack("C*")[0]
  119. end
  120. soff += rlen
  121. xlen = buf[soff, 2].unpack('v')[0]
  122. soff += 2
  123. case info[:type]
  124. when nil
  125. # TCP
  126. when 7
  127. info[:prot] = 'tcp'
  128. info[:port] = buf[soff, 2].unpack('n')[0]
  129. # UDP
  130. when 8
  131. info[:prot] = 'udp'
  132. info[:port] = buf[soff, 2].unpack('n')[0]
  133. # ADDR
  134. when 9
  135. info[:host] = buf[soff, 4].unpack('C4').join('.')
  136. # PIPE
  137. when 15
  138. info[:prot] = 'pipe'
  139. info[:pipe] = buf[soff, xlen].unpack("a*")[0]
  140. # LRPC
  141. when 16
  142. info[:prot] = 'lrpc'
  143. info[:pipe] = buf[soff, xlen].unpack("a*")[0]
  144. # NETBIOS
  145. when 17,24
  146. info[:host] = buf[soff, xlen].unpack("a*")[0]
  147. # HTTP
  148. when 31
  149. info[:prot] = 'http'
  150. info[:port] = buf[soff, 2].unpack('n')[0]
  151. # DYNAMIC?
  152. when 22
  153. # not parsed
  154. else
  155. print_status("EPM unknown type: #{info[:type]} #{buf[soff, xlen].unpack("H*")[0]}")
  156. end
  157. soff += xlen
  158. end
  159. info[:pipe].gsub!("\x00", '') if info[:pipe]
  160. info[:host].gsub!("\x00", '') if info[:host]
  161. res << info
  162. # Handle a buggy response from a Likewise server that can result in a loop otherwise
  163. break if hnd == [0, 0, 0, 0, 0, 0, 0, 0, 0, 1].pack("V*")
  164. end
  165. rescue ::Interrupt
  166. raise $!
  167. rescue ::Exception => e
  168. print_status("Could not obtain the endpoint list: #{e}")
  169. res = nil
  170. end
  171. res
  172. end
  173. end
  174. end