Introduction

ARP spoofing is a rather nasty network attack which is not very popular because the attacker needs to be on the same LAN as the victim. This is impractical in most cases, however, if that happens to be the case, a malicious user can easily perform attacks such as Man-In-The-Middled(MitM) and/or Denied of Service(DoS).

Recently I have been working on creating a attack-defense style CTF environment and ARP spoofing in the challenge network is definitely a concern. In this blog post I’ll share the basics of ARP spoofiing - what it is, how to do it, how to detect it and finally how to prevent it from happening on your network.

What is ARP?

The ARP protocol is a network protocol that lies in between layer 2 and 3 of the OSI model (link layer and network layer). It provides simple means to discover the link-layer address of a node on your local network.

Remember, link-layer addresses (MAC addresses) are used in the last hop before your packet reaches the destination node - you can use MAC addresses to address nodes on your local network but not on a remote network. If you want to reach a remote machine you will do IP (network layer) routing and when the packet reaches the destination network it will use the destination node’s link-layer address.

To keep it simple, let’s look how ARP works when we want to ping a node on our local network:

What’s the issue then?

It all sounds easy and simple, however, being one of the ancient protocols, ARP does not include any security whatsoever. All messages sent are in plain text, meaning that they can be viewed, modified, spoofed, replied… you get the picture.

Since all communications require the MAC address of the node on the local network, generating ARP traffic is a easy as pinging some address (provided you don’t have their address in your ARP table cache). To do so you can simply use ping, for the purposes of the demo I used arping:

$ arping -b 192.168.0.1

Wireshark helps inspect the ARP frame’s body:

The first packet is a broadcast that I sent to find out the physical layer address of the node. This packet is broadcasted to FF:FF:FF:FF:FF:FF which is the broadcast address at layer 2. It asks everybody whether anyone has the MAC address I am looking for. Hopefully only the device that has that MAC address will respond with their MAC address to Source MAC address I have put in the frame.

This happens in the other captured packet:

Now I bet that you already see an issue with this.

If you don’t let me make it more clear:

How can this be exploited?

What happens if a malicious node listens for Who has broadcast packets and responds with a malicious response? Say their own MAC address. Well, the client/victim has no way to verify whether or not that is a response from the genuine node or not so by default they trust the response. Thus, every time the client tries to reach that IP address, it will send their packets to the attackers MAC address instead.

Now the attacker has the full power to do a lot of powerful attacks. When they receive packets from the victim, they can choose to drop them (effectively DoS-ing the victim) or forward them, but also inspect/modify them (MiTM-ing the victim).

Segway into attacks and tools

You can see that the attacker has full control over the victim’s traffic from now on. I won’t go into details of what they can do.

There are a lot of great tools for doing Man in the Middle(MiTM) attacks including the Man in the middle framework, arpspoof, driftnet, dsniff and many others. Their success will depend on the security of the application that is snooped e.g Facebook traffic is all using TLS so you won’t have much success hacking somebody’s profile but you may be able to figure out their DNS traffic and hence the sites they are visiting (see mitigation here).

Unsolicited/Gratuitous ARP reply

In a traditional production network most devices don’t change IP addresses often. This is especially true for the default gateway. This means that the same IP address will be at the same MAC address most of the time so a node can easily cache it instead of asking everyone each time.

However, due to the insecure nature of ARP, you can send responses to ARP requests even if there is no ARP request in the first place! Basically you can tell the victim - Hey, the default gateway is now at this MAC address and the client will happily update their ARP table.

If we look at the packet attributes in the image above, to build a unsolicited ARP reply you would use the following parameters:

This is called an unsolicited or gratuitous ARP reply. The worst part is that this is part of the protocol so everybody has (and must) implemented it otherwise they would not be compatible with the RFC and people will be angry.

All of the tools I mentioned earlier use this technique to make ARP spoofing faster.

ARP spoofing is a easy as running

$ arpspoof -i <interface name> -t <target> <host>

If you open Wireshark on the victim machine, you will see the avalanche of ARP responses which trick the operating system into using the spoofed MAC address.

Even worse, you omit the target parameter and spoof the default gateway, you will broadcast yourself as being the default gateway on your LAN which will effectively trick all nodes to send their internet traffic via you!

How to fix this mess?

Well, fixing insecurities built-in a protocol is quite hard.

One solution is to use static MAC addresses. This works by hard-coding a MAC-IP at each machine. This way you know which IP is at which MAC so you can disable ARP requests altogether! Unfortunately this solution quickly becomes a nightmare to manage. Effectively you will have to manage N^2 number of MAC address entries where N is the number of machines in your network. Not ideal nor practical.

arptables

A workaround I came up with is arptables. arptables is iptables for layer 2!. It has a similar syntax for writing rules and is quite easy to filter ARP frames.

Listing your existing arp rules using arptables is exactly the way you would using iptables:

$ sudo arptables -nvL

Chain INPUT (policy ACCEPT 237K packets, 6623K bytes)

Chain OUTPUT (policy ACCEPT 21934 packets, 614K bytes)

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)

Inserting rules is also the same as in iptables. For instance:

$ sudo arptables -A INPUT --source-mac \! <some mac> -s 192.168.0.1 -j DROP

In fact, the rule above is what I am using to prevent arp spoofing on my machine.

Let’s break it down:

One of the networks I use has a default gateway 192.168.0.1 and when I replace the <mac address> part with the actual MAC address of the device I create a rule that states:

If you receive an ARP frame that states it is from the default gateway (-s 192.168.0.1) but does not have the source MAC address set to the one I trust (–source-mac <>), drop it

Now this method will work given that you know the genuine MAC address of your default gateway.

Automate the defense

Now the previous section gives a one-liner rule that will fix the ARP spoofing problem, however, it has a small disadvantage - as you roam networks the default gateway will have different IP address as well as different MAC address, so you will have to update this rule every time you change a network and this is quite impractical.

It is a simple task to automate - you just need to receive an event when you join a new network. Then you can grep for you default gateway’s IP and MAC addresses. Assuming you use Linux and NetworkManager, you can use the script I wrote to automatically insert a new arptables rule in your ARP firewall.

The file you should create (if missing) is

/etc/NetworkManager/dispatcher.d/up

Also make sure it is executable (chmod +x)

#!/bin/bash

interface="wlp59s0"  # change this to match your default interface (ethernet or wireless)

if [[ "$1" == "$interface" ]]; then
	gw_ip=$(arp -a | grep _gateway | awk '{print $2}' | sed 's/(//' | sed 's/)//')
	gw_mac=$(arp -a | grep _gateway | awk '{print $4}')
	arptables -A INPUT --source-mac \! $gw_mac -s $gw_ip -j DROP
fi

It uses some basic linux tools to find the IP and MAC address of the gateway and insert a rule in arptables.

Thus, every time you connect to a newtork (up event in NetworkManager) this script will be run to secure you from ARP spoofing attacks.

Gotcha’s

Now this script will work only against people spoofing the default gateway. It will not help against people spoofing other devices on the same network. If you care about other devices, you will need to extend this script.

Also, this script assumes that there isn’t an active ARP spoofing attack going on in the network at the time when you join. If there is one, you might insert the MAC address of the attacker in your arptables and effectively block the genuine gateway from readvertising its MAC address to you later on. This script is for the 99% case. If you are on a compromised network you will need to take manual steps anyway

Conclusion

ARP spoofing is quite unpopular attack, due to the requirement of being on the same network as the victim, however, if that condition is satisfied, it is a very powerful attack that people should be aware of.

Unless they have some Intrusion Detection System or an Intrusion Prevention System, which most sane people don’t have, or you have deployed static MACs to all of the ports on your switch, which is a nightmare to maintain as discussed, the average user will have a hard time detecting and mitigating when such an attack is happening.

I hope you found this article useful. See you next time :)