PageRenderTime 76ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/Jonono2/metasploit-framework
Ruby | 192 lines | 185 code | 3 blank | 4 comment | 2 complexity | db2f855f904a2117d64b6360a1c827fc MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, LGPL-2.1, GPL-2.0
  1. ##
  2. # This module requires Metasploit: http//metasploit.com/download
  3. # Current source: https://github.com/rapid7/metasploit-framework
  4. ##
  5. require 'msf/core'
  6. class Metasploit3 < Msf::Auxiliary
  7. include Msf::Exploit::Remote::Capture
  8. include Msf::Exploit::Remote::Ipv6
  9. include Msf::Auxiliary::Report
  10. def initialize
  11. super(
  12. 'Name' => 'IPv6 Local Neighbor Discovery Using Router Advertisement',
  13. 'Description' => %q{
  14. Send a spoofed router advertisement with high priority to force hosts to
  15. start the IPv6 address auto-config. Monitor for IPv6 host advertisements,
  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. p = PacketFu::Packet.parse(pkt)
  49. next unless p.is_ipv6?
  50. next unless p.payload
  51. next if p.payload.empty?
  52. next unless p.payload[0,1] == "\x87" # Neighbor solicitation
  53. host_addr = PacketFu::AddrIpv6.new.read(p.payload[8,16]).to_x # Fixed position yay
  54. # Make sure host portion is the same as what we requested
  55. host_addr_prefix = IPAddr.new(host_addr).to_string().slice(0..19)
  56. next unless host_addr_prefix == autoconf_prefix
  57. next unless hosts.index(host_addr).nil?
  58. hosts.push(host_addr)
  59. print_status(" |*| #{host_addr}")
  60. end
  61. return(hosts)
  62. end
  63. def find_link_local(opts = {})
  64. shost = opts['SHOST'] || datastore['SHOST'] || ipv6_link_address
  65. hosts = opts['HOSTS'] || []
  66. smac = @smac
  67. timeout = opts['TIMEOUT_NEIGHBOR'] || datastore['TIMEOUT_NEIGHBOR']
  68. network_prefix = Rex::Socket.addr_aton(shost)[0,8]
  69. hosts.each() do |g|
  70. host_postfix = Rex::Socket.addr_aton(g)[8,8]
  71. local_ipv6 = Rex::Socket.addr_ntoa(network_prefix + host_postfix)
  72. mac = solicit_ipv6_mac(local_ipv6, {"TIMEOUT" => timeout})
  73. if mac
  74. # report_host(:mac => mac, :host => local_ipv6)
  75. print_status(" |*| #{local_ipv6} -> #{mac}")
  76. end
  77. end
  78. end
  79. def create_router_advertisment(opts={})
  80. dhost = "FF02::1"
  81. smac = @smac
  82. shost = opts['SHOST'] || datastore['SHOST'] || ipv6_link_address
  83. lifetime = opts['LIFETIME'] || datastore['TIMEOUT']
  84. prefix = opts['PREFIX'] || datastore['PREFIX']
  85. plen = 64
  86. dmac = "33:33:00:00:00:01"
  87. p = PacketFu::IPv6Packet.new
  88. p.eth_saddr = smac
  89. p.eth_daddr = dmac
  90. p.ipv6_hop = 255
  91. p.ipv6_next = 0x3a
  92. p.ipv6_saddr = shost
  93. p.ipv6_daddr = dhost
  94. payload = router_advertisement_payload
  95. payload << opt60_payload(lifetime, prefix)
  96. payload << slla_payload(smac)
  97. p.payload = payload
  98. p.ipv6_len = payload.size
  99. ipv6_checksum!(p)
  100. return p
  101. end
  102. def opt60_payload(lifetime, prefix)
  103. type = 3
  104. len = 4
  105. prefix_len = 64
  106. flag = 0xc0
  107. valid_lifetime = lifetime || 5
  108. preferred_lifetime = lifetime || 5
  109. reserved = 0
  110. prefix = IPAddr.new(prefix).to_i.to_s(16).scan(/../).map {|x| x.to_i(16)}.pack("C*")
  111. [type, len, prefix_len, flag, valid_lifetime,
  112. preferred_lifetime, reserved, prefix].pack("CCCCNNNa16")
  113. end
  114. def slla_payload(smac)
  115. type = 1
  116. len = 1
  117. addr = PacketFu::EthHeader.mac2str(smac)
  118. [type,len,addr].pack("CCa6")
  119. end
  120. def router_advertisement_payload
  121. type = 0x86
  122. code = 0
  123. checksum = 0
  124. hop_limit = 0
  125. flags = 0x08
  126. lifetime = 1800
  127. reachable = 0
  128. retrans = 0
  129. [type, code, checksum, hop_limit, flags,
  130. lifetime, reachable, retrans].pack("CCnCCnNN")
  131. end
  132. def run
  133. # Start caputure
  134. open_pcap({'FILTER' => "icmp6"})
  135. @netifaces = true
  136. if not netifaces_implemented?
  137. print_error("WARNING : Pcaprub is not uptodate, some functionality will not be available")
  138. @netifaces = false
  139. end
  140. @interface = datastore['INTERFACE'] || Pcap.lookupdev
  141. @shost = datastore['SHOST']
  142. @shost ||= get_ipv4_addr(@interface) if @netifaces
  143. raise RuntimeError ,'SHOST should be defined' unless @shost
  144. @smac = datastore['SMAC']
  145. @smac ||= get_mac(@interface) if @netifaces
  146. @smac ||= ipv6_mac
  147. raise RuntimeError ,'SMAC should be defined' unless @smac
  148. # Send router advertisement
  149. print_status("Sending router advertisement...")
  150. pkt = create_router_advertisment()
  151. capture.inject(pkt.to_s)
  152. # Listen for host advertisements
  153. print_status("Listening for neighbor solicitation...")
  154. hosts = listen_for_neighbor_solicitation()
  155. if(hosts.size() == 0)
  156. print_status("No hosts were seen sending a neighbor solicitation")
  157. else
  158. # Attempt to get link local addresses
  159. print_status("Attempting to solicit link-local addresses...")
  160. find_link_local({"HOSTS" => hosts})
  161. end
  162. # Close capture
  163. close_pcap()
  164. end
  165. end