## # $Id$ ## ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/projects/Framework/ ## require 'msf/core' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::Capture include Msf::Auxiliary::Report include Msf::Auxiliary::Scanner def initialize super( 'Name' => 'IPv6 Local Neighbor Discovery', 'Version' => '$Revision$', 'Description' => %q{ Enumerate local IPv6 hosts which respond to Neighbor Solicitations with a link-local address. Note, that like ARP scanning, this usually cannot be performed beyond the local broadcast network. }, 'Author' => 'belch', 'License' => MSF_LICENSE ) register_options( [ OptString.new('SHOST', [true, "Source IP Address"]), OptString.new('SMAC', [true, "Source MAC Address"]), ], self.class) deregister_options('SNAPLEN', 'FILTER') end def run_batch_size datastore['BATCHSIZE'] || 256 end def run_batch(hosts) print_status("IPv4 Hosts Discovery") shost = datastore['SHOST'] smac = datastore['SMAC'] addrs = [] open_pcap({'SNAPLEN' => 68, 'FILTER' => "arp[6:2] == 0x0002"}) begin hosts.each do |dhost| probe = buildprobe(datastore['SHOST'], datastore['SMAC'], dhost) capture.inject(probe) while(reply = getreply()) next if not reply[:arp] print_status("#{reply[:arp].spa} is alive.") addrs << [reply[:arp].spa, reply[:arp].sha] report_host(:host => reply[:arp].spa, :mac=>reply[:arp].sha) end end etime = Time.now.to_f + (hosts.length * 0.05) while (Time.now.to_f < etime) while(reply = getreply()) next if not reply[:arp] print_status("#{reply[:arp].spa} is alive.") addrs << [reply[:arp].spa, reply[:arp].sha] end Kernel.select(nil, nil, nil, 0.50) end ensure close_pcap() end neighbor_discovery(addrs) end def map_neighbor(nodes, adv) nodes.each do |node| ipv4_addr, mac_addr = node next if not adv[:eth].src_mac.eql? mac_addr ipv6_addr = Racket::L3::Misc.long2ipv6(adv[:ipv6].src_ip) return {:eth => mac_addr, :ipv4 => ipv4_addr, :ipv6 => ipv6_addr} end nil end def neighbor_discovery(neighs) print_status("IPv6 Neighbor Discovery") smac = datastore['SMAC'] open_pcap({'SNAPLEN' => 68, 'FILTER' => "icmp6"}) begin neighs.each do |neigh| host, dmac = neigh shost = Racket::L3::Misc.linklocaladdr(smac) neigh = Racket::L3::Misc.linklocaladdr(dmac) probe = buildsolicitation(smac, shost, neigh) capture.inject(probe) while(adv = getadvertisement()) next if not adv[:icmpv6] addr = map_neighbor(neighs, adv) next if not addr print_status("#{addr[:ipv4]} maps to IPv6 link local address #{addr[:ipv6]}") end end etime = Time.now.to_f + (neighs.length * 0.5) while (Time.now.to_f < etime) while(adv = getadvertisement()) next if not adv[:icmpv6] addr = map_neighbor(neighs, adv) next if not addr print_status("#{addr[:ipv4]} maps to IPv6 link local address #{addr[:ipv6]}") end Kernel.select(nil, nil, nil, 0.50) end ensure close_pcap() end end def buildprobe(shost, smac, dhost) n = Racket::Racket.new n.l2 = Racket::L2::Ethernet.new(Racket::Misc.randstring(14)) n.l2.src_mac = smac n.l2.dst_mac = 'ff:ff:ff:ff:ff:ff' n.l2.ethertype = 0x0806 n.l3 = Racket::L3::ARP.new n.l3.opcode = Racket::L3::ARP::ARPOP_REQUEST n.l3.sha = n.l2.src_mac n.l3.tha = n.l2.dst_mac n.l3.spa = shost n.l3.tpa = dhost n.pack end def getreply pkt = capture.next return if not pkt eth = Racket::L2::Ethernet.new(pkt) return if not eth.ethertype == 0x0806 arp = Racket::L3::ARP.new(eth.payload) return if not arp.opcode == Racket::L3::ARP::ARPOP_REPLY {:raw => pkt, :eth => eth, :arp => arp} end def buildsolicitation(smac, shost, neigh) dmac = Racket::L3::Misc.soll_mcast_mac(neigh) dhost = Racket::L3::Misc.soll_mcast_addr6(neigh) n = Racket::Racket.new n.l2 = Racket::L2::Ethernet.new(Racket::Misc.randstring(14)) n.l2.src_mac = smac n.l2.dst_mac = dmac n.l2.ethertype = 0x86dd n.l3 = Racket::L3::IPv6.new n.l3.src_ip = Racket::L3::Misc.ipv62long(shost) n.l3.dst_ip = Racket::L3::Misc.ipv62long(dhost) n.l3.nhead = 0x3a n.l3.ttl = 0xff n.l4 = Racket::L4::ICMPv6NeighborSolicitation.new n.l4.address = Racket::L3::Misc.ipv62long(neigh) n.l4.slla = smac n.l4.fix!(n.l3.src_ip, n.l3.dst_ip) n.pack end def getadvertisement pkt = capture.next return if not pkt eth = Racket::L2::Ethernet.new(pkt) return if not eth.ethertype == 0x86dd ipv6 = Racket::L3::IPv6.new(eth.payload) return if not ipv6.nhead == 0x3a icmpv6 = Racket::L4::ICMPv6.new(ipv6.payload) return if not icmpv6.type == Racket::L4::ICMPv6::ICMPv6_TYPE_NEIGHBOR_ADVERTISEMENT icmpv6 = Racket::L4::ICMPv6NeighborAdvertisement.new(ipv6.payload) {:raw => pkt, :eth => eth, :ipv6 => ipv6, :icmpv6 => icmpv6} end end