Path: blob/master/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb
19500 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::Ipv67include Msf::Exploit::Remote::Capture8include Msf::Auxiliary::Report9include Msf::Auxiliary::Scanner1011def initialize12super(13'Name' => 'IPv6 Local Neighbor Discovery',14'Description' => %q{15Enumerate local IPv6 hosts which respond to Neighbor Solicitations with a link-local address.16Note, that like ARP scanning, this usually cannot be performed beyond the local17broadcast network.18},19'Author' => 'belch',20'License' => MSF_LICENSE,21'Notes' => {22'Stability' => [CRASH_SAFE],23'SideEffects' => [],24'Reliability' => []25}26)2728register_options(29[30OptString.new('SHOST', [false, 'Source IP Address']),31OptString.new('SMAC', [false, 'Source MAC Address']),32OptInt.new('TIMEOUT', [true, 'The number of seconds to wait for new data', 5]),33]34)3536deregister_options('SNAPLEN', 'FILTER')37end3839def run_batch_size40datastore['BATCHSIZE'] || 25641end4243def run_batch(hosts)44open_pcap({ 'SNAPLEN' => 68, 'FILTER' => 'arp[6:2] == 0x0002' })4546@netifaces = true47if !netifaces_implemented?48print_error('WARNING : Pcaprub is not up-to-date, some functionality will not be available')49@netifaces = false50end5152print_status('Discovering IPv4 nodes via ARP...')5354@interface = datastore['INTERFACE'] || Pcap.lookupdev55@shost = datastore['SHOST']56@shost ||= get_ipv4_addr(@interface) if @netifaces57raise 'SHOST should be defined' unless @shost5859@smac = datastore['SMAC']60@smac ||= get_mac(@interface) if @netifaces61raise 'SMAC should be defined' unless @smac6263addrs = []6465begin66found = {}67hosts.each do |dhost|68probe = buildprobe(@shost, @smac, dhost)69capture.inject(probe)70while (reply = getreply)71next unless reply.is_arp?7273next if found[reply.arp_saddr_ip]7475print_good(sprintf(' %16s ALIVE', reply.arp_saddr_ip))76addrs << [reply.arp_saddr_ip, reply.arp_saddr_mac]77report_host(host: reply.arp_saddr_ip, mac: reply.arp_saddr_mac)78found[reply.arp_saddr_ip] = true79end80end8182etime = ::Time.now.to_f + datastore['TIMEOUT']8384while (::Time.now.to_f < etime)85while (reply = getreply)86next unless reply.is_arp?8788next if found[reply.arp_saddr_ip]8990print_good(sprintf(' %16s ALIVE', reply.arp_saddr_ip))91addrs << [reply.arp_saddr_ip, reply.arp_saddr_mac]92report_host(host: reply.arp_saddr_ip, mac: reply.arp_saddr_mac)93found[reply.arp_saddr_ip] = true94end9596::IO.select(nil, nil, nil, 0.50)97end98ensure99close_pcap100end101102neighbor_discovery(addrs)103end104105def map_neighbor(nodes, adv)106nodes.each do |node|107ipv4_addr, mac_addr = node108next unless adv.eth_saddr == mac_addr109110ipv6_addr = adv.ipv6_saddr111return { eth: mac_addr, ipv4: ipv4_addr, ipv6: ipv6_addr }112end113nil114end115116def neighbor_discovery(neighs)117print_status('Discovering IPv6 addresses for IPv4 nodes...')118print_status('')119120smac = @smac121open_pcap({ 'SNAPLEN' => 68, 'FILTER' => 'icmp6' })122123begin124neighs.each do |neigh|125_, dmac = neigh126127shost = ipv6_linklocaladdr(smac)128neigh = ipv6_linklocaladdr(dmac)129130probe = buildsolicitation(smac, shost, neigh)131132capture.inject(probe)133Kernel.select(nil, nil, nil, 0.1)134135while (adv = getadvertisement)136next unless adv.is_ipv6?137138addr = map_neighbor(neighs, adv)139next if !addr140141print_status(format(' %<ipv4>16s maps to %<ipv6>s', ipv4: addr[:ipv4], ipv6: addr[:ipv6]))142report_note(143host: addr[:ipv4],144type: 'host.ipv4.ipv6.mapping',145data: {146ipv4_address: addr[:ipv4],147ipv6_address: addr[:ipv6],148matches: 'true'149}150) # with this we have the results in our database151152end153end154155etime = ::Time.now.to_f + (neighs.length * 0.5)156157while (::Time.now.to_f < etime)158while (adv = getadvertisement)159next if !adv160161addr = map_neighbor(neighs, adv)162next if !addr163164print_status(format(' %<ipv4>16s maps to %<ipv6>s', ipv4: addr[:ipv4], ipv6: addr[:ipv6]))165end166::IO.select(nil, nil, nil, 0.50)167end168ensure169close_pcap170end171end172173def buildprobe(shost, smac, dhost)174p = PacketFu::ARPPacket.new175p.eth_saddr = smac176p.eth_daddr = 'ff:ff:ff:ff:ff:ff'177p.arp_opcode = 1178p.arp_saddr_mac = p.eth_saddr179p.arp_daddr_mac = p.eth_daddr180p.arp_saddr_ip = shost181p.arp_daddr_ip = dhost182p.to_s183end184185def getreply186pkt = capture.next187Kernel.select(nil, nil, nil, 0.1)188return if !pkt189190p = PacketFu::Packet.parse(pkt)191return unless p.is_arp?192return unless p.arp_opcode == 2193194p195end196197def buildsolicitation(smac, shost, neigh)198dmac = ipv6_soll_mcast_mac(neigh)199dhost = ipv6_soll_mcast_addr6(neigh)200201p = PacketFu::IPv6Packet.new202p.eth_saddr = smac203p.eth_daddr = dmac204p.ipv6_saddr = shost205p.ipv6_daddr = dhost206p.ipv6_next = 0x3a207p.ipv6_hop = 255208p.payload = ipv6_neighbor_solicitation(209IPAddr.new(neigh).to_i,210p.eth_src211)212p.ipv6_len = p.payload.size213ipv6_checksum!(p)214p.to_s215end216217def getadvertisement218pkt = capture.next219Kernel.select(nil, nil, nil, 0.1)220return if !pkt221222p = PacketFu::Packet.parse(pkt)223return unless p.is_ipv6?224return unless p.ipv6_next == 0x3a225return unless p.icmpv6_type == 136 && p.icmpv6_code == 0226227p228end229end230231232