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

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

https://bitbucket.org/technopunk2099/metasploit-framework
Ruby | 187 lines | 185 code | 2 blank | 0 comment | 2 complexity | fa35d8ae24dec7a87fbc129dded0c626 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-2.1, GPL-2.0, MIT
  1. require 'msf/core'
  2. class Metasploit3 < Msf::Auxiliary
  3. include Msf::Exploit::Remote::Capture
  4. include Msf::Exploit::Remote::Ipv6
  5. include Msf::Auxiliary::Report
  6. def initialize
  7. super(
  8. 'Name' => 'IPv6 Local Neighbor Discovery Using Router Advertisement',
  9. 'Description' => %q{
  10. Send a spoofed router advertisement with high priority to force hosts to
  11. start the IPv6 address auto-config. Monitor for IPv6 host advertisements,
  12. and try to guess the link-local address by concatinating the prefix, and
  13. the host portion of the IPv6 address. Use NDP host solicitation to
  14. determine if the IP address is valid'
  15. },
  16. 'Author' => 'wuntee',
  17. 'License' => MSF_LICENSE,
  18. 'References' =>
  19. [
  20. ['URL','http://wuntee.blogspot.com/2010/11/ipv6-link-local-host-discovery-concept.html']
  21. ]
  22. )
  23. register_options(
  24. [
  25. OptInt.new('TIMEOUT_NEIGHBOR', [true, "Time (seconds) to listen for a solicitation response.", 1])
  26. ], self.class)
  27. register_advanced_options(
  28. [
  29. OptString.new('PREFIX', [true, "Prefix that each host should get an IPv6 address from",
  30. "2001:1234:DEAD:BEEF::"]
  31. )
  32. ], self.class)
  33. deregister_options('SNAPLEN', 'FILTER', 'RHOST', 'PCAPFILE')
  34. end
  35. def listen_for_neighbor_solicitation(opts = {})
  36. hosts = []
  37. timeout = opts['TIMEOUT'] || datastore['TIMEOUT']
  38. prefix = opts['PREFIX'] || datastore['PREFIX']
  39. max_epoch = ::Time.now.to_i + timeout
  40. autoconf_prefix = IPAddr.new(prefix).to_string().slice(0..19)
  41. while(::Time.now.to_i < max_epoch)
  42. pkt = capture.next()
  43. next if not pkt
  44. p = PacketFu::Packet.parse(pkt)
  45. next unless p.is_ipv6?
  46. next unless p.payload
  47. next if p.payload.empty?
  48. next unless p.payload[0,1] == "\x87" # Neighbor solicitation
  49. host_addr = PacketFu::AddrIpv6.new.read(p.payload[8,16]).to_x # Fixed position yay
  50. # Make sure host portion is the same as what we requested
  51. host_addr_prefix = IPAddr.new(host_addr).to_string().slice(0..19)
  52. next unless host_addr_prefix == autoconf_prefix
  53. next unless hosts.index(host_addr).nil?
  54. hosts.push(host_addr)
  55. print_status(" |*| #{host_addr}")
  56. end
  57. return(hosts)
  58. end
  59. def find_link_local(opts = {})
  60. shost = opts['SHOST'] || datastore['SHOST'] || ipv6_link_address
  61. hosts = opts['HOSTS'] || []
  62. smac = @smac
  63. timeout = opts['TIMEOUT_NEIGHBOR'] || datastore['TIMEOUT_NEIGHBOR']
  64. network_prefix = Rex::Socket.addr_aton(shost)[0,8]
  65. hosts.each() do |g|
  66. host_postfix = Rex::Socket.addr_aton(g)[8,8]
  67. local_ipv6 = Rex::Socket.addr_ntoa(network_prefix + host_postfix)
  68. mac = solicit_ipv6_mac(local_ipv6, {"TIMEOUT" => timeout})
  69. if mac
  70. # report_host(:mac => mac, :host => local_ipv6)
  71. print_status(" |*| #{local_ipv6} -> #{mac}")
  72. end
  73. end
  74. end
  75. def create_router_advertisment(opts={})
  76. dhost = "FF02::1"
  77. smac = @smac
  78. shost = opts['SHOST'] || datastore['SHOST'] || ipv6_link_address
  79. lifetime = opts['LIFETIME'] || datastore['TIMEOUT']
  80. prefix = opts['PREFIX'] || datastore['PREFIX']
  81. plen = 64
  82. dmac = "33:33:00:00:00:01"
  83. p = PacketFu::IPv6Packet.new
  84. p.eth_saddr = smac
  85. p.eth_daddr = dmac
  86. p.ipv6_hop = 255
  87. p.ipv6_next = 0x3a
  88. p.ipv6_saddr = shost
  89. p.ipv6_daddr = dhost
  90. payload = router_advertisement_payload
  91. payload << opt60_payload(lifetime, prefix)
  92. payload << slla_payload(smac)
  93. p.payload = payload
  94. p.ipv6_len = payload.size
  95. ipv6_checksum!(p)
  96. return p
  97. end
  98. def opt60_payload(lifetime, prefix)
  99. type = 3
  100. len = 4
  101. prefix_len = 64
  102. flag = 0xc0
  103. valid_lifetime = lifetime || 5
  104. preferred_lifetime = lifetime || 5
  105. reserved = 0
  106. prefix = IPAddr.new(prefix).to_i.to_s(16).scan(/../).map {|x| x.to_i(16)}.pack("C*")
  107. [type, len, prefix_len, flag, valid_lifetime,
  108. preferred_lifetime, reserved, prefix].pack("CCCCNNNa16")
  109. end
  110. def slla_payload(smac)
  111. type = 1
  112. len = 1
  113. addr = PacketFu::EthHeader.mac2str(smac)
  114. [type,len,addr].pack("CCa6")
  115. end
  116. def router_advertisement_payload
  117. type = 0x86
  118. code = 0
  119. checksum = 0
  120. hop_limit = 0
  121. flags = 0x08
  122. lifetime = 1800
  123. reachable = 0
  124. retrans = 0
  125. [type, code, checksum, hop_limit, flags,
  126. lifetime, reachable, retrans].pack("CCnCCnNN")
  127. end
  128. def run
  129. # Start caputure
  130. open_pcap({'FILTER' => "icmp6"})
  131. @netifaces = true
  132. if not netifaces_implemented?
  133. print_error("WARNING : Pcaprub is not uptodate, some functionality will not be available")
  134. @netifaces = false
  135. end
  136. @interface = datastore['INTERFACE'] || Pcap.lookupdev
  137. @shost = datastore['SHOST']
  138. @shost ||= get_ipv4_addr(@interface) if @netifaces
  139. raise RuntimeError ,'SHOST should be defined' unless @shost
  140. @smac = datastore['SMAC']
  141. @smac ||= get_mac(@interface) if @netifaces
  142. @smac ||= ipv6_mac
  143. raise RuntimeError ,'SMAC should be defined' unless @smac
  144. # Send router advertisement
  145. print_status("Sending router advertisement...")
  146. pkt = create_router_advertisment()
  147. capture.inject(pkt.to_s)
  148. # Listen for host advertisements
  149. print_status("Listening for neighbor solicitation...")
  150. hosts = listen_for_neighbor_solicitation()
  151. if(hosts.size() == 0)
  152. print_status("No hosts were seen sending a neighbor solicitation")
  153. else
  154. # Attempt to get link local addresses
  155. print_status("Attempting to solicit link-local addresses...")
  156. find_link_local({"HOSTS" => hosts})
  157. end
  158. # Close capture
  159. close_pcap()
  160. end
  161. end