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

/modules/auxiliary/scanner/discovery/ipv6_neighbor_router_advertisement.rb

https://bitbucket.org/jrossi/metasploit
Ruby | 217 lines | 211 code | 3 blank | 3 comment | 2 complexity | fb1e1414f05eaf8c4d3a2187e2794819 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. ##
  2. # $Id$
  3. ##
  4. require 'msf/core'
  5. class Metasploit3 < Msf::Auxiliary
  6. include Msf::Exploit::Remote::Capture
  7. include Msf::Exploit::Remote::Ipv6
  8. include Msf::Auxiliary::Report
  9. def initialize
  10. super(
  11. 'Name' => 'IPv6 Local Neighbor Discovery Using Router Advertisment',
  12. 'Version' => '$Revision$',
  13. 'Description' => %q{
  14. Send a spoofed router advertisment with high priority to force hosts to
  15. start the IPv6 address auto-config. Monitor for IPv6 host advertisments,
  16. and try to guess the link-local address by concatinating the prefix, and
  17. the host portion of the IPv6 address. Use NDP host solicitation to
  18. determine if the IP address is valid'
  19. },
  20. 'Author' => 'wuntee',
  21. 'License' => MSF_LICENSE,
  22. 'References' =>
  23. [
  24. ['URL','http://wuntee.blogspot.com/2010/11/ipv6-link-local-host-discovery-concept.html']
  25. ]
  26. )
  27. register_options(
  28. [
  29. OptInt.new('TIMEOUT_NEIGHBOR', [true, "Time (seconds) to listen for a solicitation response.", 1])
  30. ], self.class)
  31. register_advanced_options(
  32. [
  33. OptString.new('PREFIX', [true, "Prefix that each host should get an IPv6 address from",
  34. "2001:1234:DEAD:BEEF::"]
  35. )
  36. ], self.class)
  37. deregister_options('SNAPLEN', 'FILTER', 'RHOST', 'PCAPFILE')
  38. end
  39. def listen_for_neighbor_solicitation(opts = {})
  40. hosts = []
  41. timeout = opts['TIMEOUT'] || datastore['TIMEOUT']
  42. prefix = opts['PREFIX'] || datastore['PREFIX']
  43. max_epoch = ::Time.now.to_i + timeout
  44. autoconf_prefix = IPAddr.new(prefix).to_string().slice(0..19)
  45. while(::Time.now.to_i < max_epoch)
  46. pkt = capture.next()
  47. next if not pkt
  48. eth = Racket::L2::Ethernet.new(pkt)
  49. next if not eth.ethertype.eql?(Racket::L2::Ethernet::ETHERTYPE_IPV6)
  50. ipv6 = Racket::L3::IPv6.new(eth.payload)
  51. next if not ipv6.nhead == 0x3a
  52. icmpv6 = Racket::L4::ICMPv6.new(ipv6.payload)
  53. next if not icmpv6.type == Racket::L4::ICMPv6Generic::ICMPv6_TYPE_NEIGHBOR_SOLICITATION
  54. icmpv6 = Racket::L4::ICMPv6NeighborAdvertisement.new(ipv6.payload)
  55. host_addr = Racket::L3::Misc.long2ipv6(icmpv6.address)
  56. # Make sure host portion is the same as what we requested
  57. host_addr_prefix = IPAddr.new(host_addr).to_string().slice(0..19)
  58. next if not host_addr_prefix.eql?(autoconf_prefix)
  59. next if not hosts.index(host_addr).eql?(nil)
  60. hosts.push(host_addr)
  61. print_status(" |*| #{host_addr}")
  62. end
  63. return(hosts)
  64. end
  65. def find_link_local(opts = {})
  66. shost = opts['SHOST'] || datastore['SHOST'] || ipv6_link_address
  67. hosts = opts['HOSTS'] || []
  68. smac = opts['SMAC'] || datastore['SMAC'] || ipv6_mac
  69. timeout = opts['TIMEOUT_NEIGHBOR'] || datastore['TIMEOUT_NEIGHBOR']
  70. network_prefix = Rex::Socket.addr_aton(shost)[0,8]
  71. hosts.each() do |g|
  72. host_postfix = Rex::Socket.addr_aton(g)[8,8]
  73. local_ipv6 = Rex::Socket.addr_ntoa(network_prefix + host_postfix)
  74. mac = solicit_ipv6_mac(local_ipv6, {"TIMEOUT" => timeout})
  75. if mac
  76. # report_host(:mac => mac, :host => local_ipv6)
  77. print_status(" |*| #{local_ipv6} -> #{mac}")
  78. end
  79. end
  80. end
  81. def create_router_advertisment(opts = {})
  82. dhost = "FF02::1"
  83. smac = opts['SMAC'] || datastore['SMAC'] || ipv6_mac
  84. shost = opts['SHOST'] || datastore['SHOST'] || ipv6_link_address
  85. lifetime = opts['LIFETIME'] || datastore['TIMEOUT']
  86. prefix = opts['PREFIX'] || datastore['PREFIX']
  87. plen = 64
  88. dmac = "33:33:00:00:00:01"
  89. p = Racket::Racket.new
  90. p.l2 = Racket::L2::Ethernet.new()
  91. p.l2.src_mac = smac
  92. p.l2.dst_mac = dmac
  93. p.l2.ethertype = Racket::L2::Ethernet::ETHERTYPE_IPV6
  94. p.l3 = Racket::L3::IPv6.new()
  95. p.l3.ttl = 255
  96. p.l3.nhead = 58
  97. p.l3.src_ip = Racket::L3::Misc.ipv62long(shost)
  98. p.l3.dst_ip = Racket::L3::Misc.ipv62long(dhost)
  99. p.l4 = ICMPv6RouterAdvertisementFixed.new()
  100. p.l4.managed_config = 0
  101. p.l4.other_config = 0
  102. p.l4.preference = 1
  103. p.l4.lifetime = 1800
  104. p.l4.hop_limit = 0
  105. # OPTION lladdress
  106. option_dst_lladdr = ICMPv6OptionLinkAddress.new()
  107. option_dst_lladdr.lladdr = smac
  108. p.l4.add_option(ICMPv6OptionLinkAddress::ICMPv6_OPTION_TYPE_ID, option_dst_lladdr)
  109. # OPTION Prefix Information
  110. option_prefix = ICMPv6OptionPrefixInformation.new()
  111. option_prefix.plen = plen
  112. option_prefix.on_link = 1
  113. option_prefix.addrconf = 1
  114. option_prefix.valid_lifetime = lifetime
  115. option_prefix.preferred_lifetime = lifetime
  116. option_prefix.prefix = Racket::L3::Misc.ipv62long(prefix)
  117. p.l4.add_option(ICMPv6OptionPrefixInformation::ICMPv6_OPTION_TYPE_ID, option_prefix)
  118. p.l4.fix!(p.l3.src_ip, p.l3.dst_ip)
  119. return(p)
  120. end
  121. def run
  122. # Start caputure
  123. open_pcap({'FILTER' => "icmp6"})
  124. # Send router advertisment
  125. print_status("Sending router advertisment...")
  126. pkt = create_router_advertisment()
  127. capture.inject(pkt.pack())
  128. # Listen for host advertisments
  129. print_status("Listening for neighbor solicitation...")
  130. hosts = listen_for_neighbor_solicitation()
  131. if(hosts.size() == 0)
  132. print_status("No hosts were seen sending a neighbor solicitation")
  133. else
  134. # Attempt to get link local addresses
  135. print_status("Attempting to solicit link-local addresses...")
  136. find_link_local({"HOSTS" => hosts})
  137. end
  138. # Close capture
  139. close_pcap()
  140. end
  141. class ICMPv6OptionPrefixInformation < RacketPart
  142. ICMPv6_OPTION_TYPE_ID = 3
  143. unsigned :plen, 8
  144. unsigned :on_link, 1
  145. unsigned :addrconf, 1
  146. unsigned :reserved, 6
  147. unsigned :valid_lifetime, 32
  148. unsigned :preferred_lifetime, 32
  149. unsigned :reserved2, 32
  150. unsigned :prefix, 128
  151. def initialize(*args)
  152. super(*args)
  153. end
  154. end
  155. class ICMPv6RouterAdvertisementFixed < Racket::L4::ICMPv6Generic
  156. # default value that should be placed in the hop count field of the IP header
  157. # for outgoing IP packets
  158. unsigned :hop_limit, 8
  159. # boolean, managed address configuration?
  160. unsigned :managed_config, 1
  161. # boolean, other configuration?
  162. unsigned :other_config, 1
  163. unsigned :home_config, 1
  164. unsigned :preference, 2
  165. unsigned :proxied, 1
  166. # set to 0, never used.
  167. unsigned :reserved, 2
  168. # lifetime associated with the default router in seconds
  169. unsigned :lifetime, 16
  170. # time in milliseconds that a node assumes a neighbor is reachable after
  171. # having received a reachability confirmation
  172. unsigned :reachable_time, 32
  173. # time in milliseconds between retransmitted neighbor solicitation messages
  174. unsigned :retrans_time, 32
  175. rest :payload
  176. def initialize(*args)
  177. super(*args)
  178. self.type = ICMPv6_TYPE_ROUTER_ADVERTISEMENT
  179. end
  180. end
  181. end