/lib/msf/core/exploit/ipv6.rb
Ruby | 263 lines | 170 code | 55 blank | 38 comment | 43 complexity | 6b620d6481dc93bfaf1d6f209a4df8f5 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause
- ##
- # $Id$
- ##
- module Msf
- ###
- #
- # This module provides common tools for IPv6
- #
- ###
- module Exploit::Remote::Ipv6
- require 'racket'
- #
- # Initializes an instance of an exploit module that captures traffic
- #
- def initialize(info = {})
- super
- register_options(
- [
- OptString.new('INTERFACE', [false, 'The name of the interface']),
- OptString.new("SMAC", [ false, "The source MAC address"]),
- OptAddress.new("SHOST", [ false, "The source IPv6 address" ] ),
- OptInt.new("TIMEOUT", [ true, "Timeout when waiting for host response.", 5])
- ], Msf::Exploit::Remote::Ipv6
- )
- begin
- require 'pcaprub'
- @pcaprub_loaded = true
- rescue ::Exception => e
- @pcaprub_loaded = false
- @pcaprub_error = e
- end
- end
- #
- # Shortcut method for resolving our local interface name
- #
- def ipv6_interface(opts={})
- opts['INTERFACE'] || datastore['INTERFACE'] || ::Pcap.lookupdev
- end
-
- #
- # Shortcut method for determining our link-local address
- #
- def ipv6_link_address(opts={})
- Rex::Socket.ipv6_link_address(ipv6_interface(opts))
- end
- #
- # Shortcut method for determining our MAC address
- #
- def ipv6_mac(opts={})
- Rex::Socket.ipv6_mac(ipv6_interface(opts))
- end
-
- #
- # Opens a pcaprub capture interface to inject packets, and sniff ICMPv6 packets
- #
- def open_icmp_pcap(opts = {})
- check_pcaprub_loaded
- dev = ipv6_interface(opts)
- len = 65535
- tim = 0
- @ipv6_icmp6_capture = ::Pcap.open_live(dev, len, true, tim)
- @ipv6_icmp6_capture.setfilter("icmp6")
- end
- #
- # Close the capture interface
- #
- def close_icmp_pcap()
- check_pcaprub_loaded
- return if not @ipv6_icmp6_capture
- @ipv6_icmp6_capture = nil
- GC.start()
- end
- #
- # Send out a ICMPv6 neighbor solicitation, and
- # return the associated MAC address
- #
- def solicit_ipv6_mac(dhost, opts = {})
- check_pcaprub_loaded
- dhost_intf = dhost + '%' + ipv6_interface(opts)
- smac = opts['SMAC'] || datastore['SMAC'] || ipv6_mac
- shost = opts['SHOST'] || datastore['SHOST'] || Rex::Socket.source_address(dhost_intf)
- timeout = opts['TIMEOUT'] || datastore['TIMEOUT'] || 3
- open_icmp_pcap()
- p = Racket::Racket.new()
- p.l2 = Racket::L2::Ethernet.new()
- p.l2.src_mac = smac
- p.l2.dst_mac = Racket::L3::Misc.soll_mcast_mac(dhost)
- p.l2.ethertype = Racket::L2::Ethernet::ETHERTYPE_IPV6
- p.l3 = Racket::L3::IPv6.new()
- p.l3.src_ip = Racket::L3::Misc.ipv62long(shost)
- p.l3.dst_ip = Racket::L3::Misc.ipv62long(Racket::L3::Misc.soll_mcast_addr6(dhost))
- p.l3.ttl = 255
- p.l3.nhead = 0x3a
- p.l3.fix!()
- p.l4 = Racket::L4::ICMPv6NeighborSolicitation.new()
- p.l4.address = Racket::L3::Misc.ipv62long(dhost)
- p.l4.add_option(0x01, Racket::L2::Misc.mac2string(p.l2.src_mac))
- p.l4.fix!(p.l3.src_ip, p.l3.dst_ip)
- @ipv6_icmp6_capture.inject(p.pack())
- # Wait for a response
- max_epoch = ::Time.now.to_i + timeout
- while(::Time.now.to_i < max_epoch)
- pkt = @ipv6_icmp6_capture.next()
- next if not pkt
- eth = Racket::L2::Ethernet.new(pkt)
- next if eth.ethertype != Racket::L2::Ethernet::ETHERTYPE_IPV6
- ipv6 = Racket::L3::IPv6.new(eth.payload)
- next if ipv6.nhead != 0x3a
- icmpv6 = Racket::L4::ICMPv6.new(ipv6.payload)
- next if icmpv6.type != Racket::L4::ICMPv6Generic::ICMPv6_TYPE_NEIGHBOR_ADVERTISEMENT
- icmpv6 = Racket::L4::ICMPv6NeighborAdvertisement.new(ipv6.payload)
- if(icmpv6 and
- ipv6.dst_ip == Racket::L3::Misc.ipv62long(shost) and
- ipv6.src_ip == Racket::L3::Misc.ipv62long(dhost))
- icmpv6options = icmpv6.get_options()
- icmpv6options.each() do |opt|
- id = opt[1]
- if(id == ICMPv6OptionLinkAddress::ICMPv6_OPTION_TYPE_ID)
- addr = ICMPv6OptionLinkAddress.new(opt[2]).lladdr
- close_icmp_pcap()
- return(addr)
- end
- end
- # If there is no addr option, return the ethernet mac
- close_icmp_pcap()
- return(eth.src_mac)
- end
- end
- close_icmp_pcap()
- return(nil)
- end
- #
- # Send a ICMPv6 Echo Request, and wait for the
- # associated ICMPv6 Echo Response
- #
- def ping6(dhost, opts={})
- check_pcaprub_loaded
- dhost_intf = dhost + '%' + ipv6_interface(opts)
- smac = opts['SMAC'] || datastore['SMAC'] || ipv6_mac
- shost = opts['SHOST'] || datastore['SHOST'] || Rex::Socket.source_address(dhost_intf)
- dmac = opts['DMAC'] || solicit_ipv6_mac(dhost)
- timeout = opts['TIMEOUT'] || datastore['TIMEOUT']
- wait = opts['WAIT']
- if(wait.eql?(nil))
- wait = true
- end
- dmac.eql?(nil) and return false
- open_icmp_pcap()
- # Create ICMPv6 Request
- p = Racket::Racket.new()
- p.l2 = Racket::L2::Ethernet.new()
- p.l2.src_mac = smac
- p.l2.dst_mac = dmac
- p.l2.ethertype = Racket::L2::Ethernet::ETHERTYPE_IPV6
- p.l3 = Racket::L3::IPv6.new()
- p.l3.src_ip = Racket::L3::Misc.ipv62long(shost)
- p.l3.dst_ip = Racket::L3::Misc.ipv62long(dhost)
- p.l3.nhead = 0x3a
- p.l3.fix!()
- p.l4 = Racket::L4::ICMPv6EchoRequest.new()
- p.l4.id = rand(65000)
- p.l4.sequence = 1
- p.l4.payload = Rex::Text.rand_text(8)
- p.l4.fix!(p.l3.src_ip, p.l3.dst_ip)
- @ipv6_icmp6_capture.inject(p.pack())
- if(wait.eql?(true))
- print_status("Waiting for ping reply...")
- print_line("")
- # Wait for a response
- max_epoch = ::Time.now.to_i + timeout
- while(::Time.now.to_i < max_epoch)
- pkt = @ipv6_icmp6_capture.next()
- next if not pkt
- eth = Racket::L2::Ethernet.new(pkt)
- next if eth.ethertype != Racket::L2::Ethernet::ETHERTYPE_IPV6
- ipv6 = Racket::L3::IPv6.new(eth.payload)
- next if ipv6.nhead != 0x3a
- icmpv6 = Racket::L4::ICMPv6.new(ipv6.payload)
- next if icmpv6.type != Racket::L4::ICMPv6Generic::ICMPv6_TYPE_ECHO_REPLY
- icmpv6 = Racket::L4::ICMPv6EchoReply.new(ipv6.payload)
- if(icmpv6 and
- ipv6.dst_ip == p.l3.src_ip and
- ipv6.src_ip == p.l3.dst_ip and
- icmpv6.id == p.l4.id and
- icmpv6.sequence == p.l4.sequence)
- close_icmp_pcap()
- return(true)
- end
- end # End while
- end
- close_icmp_pcap()
- return(false)
- end
- def check_pcaprub_loaded
- unless @pcaprub_loaded
- print_status("The Pcaprub module is not available: #{@pcaprub_error}")
- raise RuntimeError, "Pcaprub not available"
- else
- true
- end
- end
- class ICMPv6OptionLinkAddress < RacketPart
- ICMPv6_OPTION_TYPE_ID = 1
- hex_octets :lladdr, 48
- def initialize(*args)
- super(*args)
- end
- end
- end
- end