PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb

https://bitbucket.org/technopunk2099/metasploit-framework
Ruby | 222 lines | 173 code | 43 blank | 6 comment | 20 complexity | 6d90785f62ef31be52b796d8ce01d2e6 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-2.1, GPL-2.0, MIT
  1. ##
  2. # This file is part of the Metasploit Framework and may be subject to
  3. # redistribution and commercial restrictions. Please see the Metasploit
  4. # web site for more information on licensing and terms of use.
  5. # http://metasploit.com/
  6. ##
  7. require 'msf/core'
  8. class Metasploit3 < Msf::Auxiliary
  9. include Msf::Exploit::Remote::Ipv6
  10. include Msf::Exploit::Remote::Capture
  11. include Msf::Auxiliary::Report
  12. include Msf::Auxiliary::Scanner
  13. def initialize
  14. super(
  15. 'Name' => 'IPv6 Local Neighbor Discovery',
  16. 'Description' => %q{
  17. Enumerate local IPv6 hosts which respond to Neighbor Solicitations with a link-local address.
  18. Note, that like ARP scanning, this usually cannot be performed beyond the local
  19. broadcast network.
  20. },
  21. 'Author' => 'belch',
  22. 'License' => MSF_LICENSE
  23. )
  24. register_options(
  25. [
  26. OptString.new('SHOST', [false, "Source IP Address"]),
  27. OptString.new('SMAC', [false, "Source MAC Address"]),
  28. ], self.class)
  29. deregister_options('SNAPLEN', 'FILTER')
  30. end
  31. def run_batch_size
  32. datastore['BATCHSIZE'] || 256
  33. end
  34. def run_batch(hosts)
  35. open_pcap({'SNAPLEN' => 68, 'FILTER' => "arp[6:2] == 0x0002"})
  36. @netifaces = true
  37. if not netifaces_implemented?
  38. print_error("WARNING : Pcaprub is not uptodate, some functionality will not be available")
  39. @netifaces = false
  40. end
  41. print_status("Discovering IPv4 nodes via ARP...")
  42. @interface = datastore['INTERFACE'] || Pcap.lookupdev
  43. @shost = datastore['SHOST']
  44. @shost ||= get_ipv4_addr(@interface) if @netifaces
  45. raise RuntimeError ,'SHOST should be defined' unless @shost
  46. @smac = datastore['SMAC']
  47. @smac ||= get_mac(@interface) if @netifaces
  48. raise RuntimeError ,'SMAC should be defined' unless @smac
  49. addrs = []
  50. begin
  51. found = {}
  52. hosts.each do |dhost|
  53. probe = buildprobe(@shost, @smac, dhost)
  54. capture.inject(probe)
  55. while(reply = getreply())
  56. next unless reply.is_arp?
  57. if not found[reply.arp_saddr_ip]
  58. print_status(sprintf(" %16s ALIVE",reply.arp_saddr_ip))
  59. addrs << [reply.arp_saddr_ip, reply.arp_saddr_mac]
  60. report_host(:host => reply.arp_saddr_ip, :mac=>reply.arp_saddr_mac)
  61. found[reply.arp_saddr_ip] = true
  62. end
  63. end
  64. end
  65. etime = ::Time.now.to_f + (hosts.length * 0.05)
  66. while (::Time.now.to_f < etime)
  67. while(reply = getreply())
  68. next unless reply.is_arp?
  69. if not found[reply.arp_saddr_ip]
  70. print_status(sprintf(" %16s ALIVE",reply.arp_saddr_ip))
  71. addrs << [reply.arp_saddr_ip, reply.arp_saddr_mac]
  72. report_host(:host => reply.arp_saddr_ip, :mac=>reply.arp_saddr_mac)
  73. found[reply.arp_saddr_ip] = true
  74. end
  75. end
  76. ::IO.select(nil, nil, nil, 0.50)
  77. end
  78. ensure
  79. close_pcap()
  80. end
  81. neighbor_discovery(addrs)
  82. end
  83. def map_neighbor(nodes, adv)
  84. nodes.each do |node|
  85. ipv4_addr, mac_addr = node
  86. next unless adv.eth_saddr == mac_addr
  87. ipv6_addr = adv.ipv6_saddr
  88. return {:eth => mac_addr, :ipv4 => ipv4_addr, :ipv6 => ipv6_addr}
  89. end
  90. nil
  91. end
  92. def neighbor_discovery(neighs)
  93. print_status("Discovering IPv6 addresses for IPv4 nodes...")
  94. print_status("")
  95. smac = @smac
  96. open_pcap({'SNAPLEN' => 68, 'FILTER' => "icmp6"})
  97. begin
  98. neighs.each do |neigh|
  99. host, dmac = neigh
  100. shost = ipv6_linklocaladdr(smac)
  101. neigh = ipv6_linklocaladdr(dmac)
  102. probe = buildsolicitation(smac, shost, neigh)
  103. capture.inject(probe)
  104. Kernel.select(nil,nil,nil,0.1)
  105. while(adv = getadvertisement())
  106. next unless adv.is_ipv6?
  107. addr = map_neighbor(neighs, adv)
  108. next if not addr
  109. print_status(sprintf(" %16s maps to %s",addr[:ipv4], addr[:ipv6]))
  110. report_note(
  111. :host => addr[:ipv4],
  112. :type => 'host.ipv4.ipv6.mapping',
  113. :data => "system with IPv4 address #{addr[:ipv4]} matches to IPv6 address #{addr[:ipv6]}"
  114. ) # with this we have the results in our database
  115. end
  116. end
  117. etime = ::Time.now.to_f + (neighs.length * 0.5)
  118. while (::Time.now.to_f < etime)
  119. while(adv = getadvertisement())
  120. next if not adv
  121. addr = map_neighbor(neighs, adv)
  122. next if not addr
  123. print_status(sprintf(" %16s maps to %s",addr[:ipv4], addr[:ipv6]))
  124. end
  125. ::IO.select(nil, nil, nil, 0.50)
  126. end
  127. ensure
  128. close_pcap()
  129. end
  130. end
  131. def buildprobe(shost, smac, dhost)
  132. p = PacketFu::ARPPacket.new
  133. p.eth_saddr = smac
  134. p.eth_daddr = "ff:ff:ff:ff:ff:ff"
  135. p.arp_opcode = 1
  136. p.arp_saddr_mac = p.eth_saddr
  137. p.arp_daddr_mac = p.eth_daddr
  138. p.arp_saddr_ip = shost
  139. p.arp_daddr_ip = dhost
  140. p.to_s
  141. end
  142. def getreply
  143. pkt = capture.next
  144. Kernel.select(nil,nil,nil,0.1)
  145. return if not pkt
  146. p = PacketFu::Packet.parse(pkt)
  147. return unless p.is_arp?
  148. return unless p.arp_opcode == 2
  149. p
  150. end
  151. def buildsolicitation(smac, shost, neigh)
  152. dmac = ipv6_soll_mcast_mac(neigh)
  153. dhost = ipv6_soll_mcast_addr6(neigh)
  154. p = PacketFu::IPv6Packet.new
  155. p.eth_saddr = smac
  156. p.eth_daddr = dmac
  157. p.ipv6_saddr = shost
  158. p.ipv6_daddr = dhost
  159. p.ipv6_next = 0x3a
  160. p.ipv6_hop = 255
  161. p.payload = ipv6_neighbor_solicitation(
  162. IPAddr.new(neigh).to_i,
  163. p.eth_src
  164. )
  165. p.ipv6_len = p.payload.size
  166. ipv6_checksum!(p)
  167. p.to_s
  168. end
  169. def getadvertisement
  170. pkt = capture.next
  171. Kernel.select(nil,nil,nil,0.1)
  172. return if not pkt
  173. p = PacketFu::Packet.parse(pkt)
  174. return unless p.is_ipv6?
  175. return unless p.ipv6_next == 0x3a
  176. return unless p.payload[0,2] == "\x88\x00"
  177. p
  178. end
  179. end