Layer 2 switching is one of the most common services found on modern networks. For the most part, it just works; but as with any technology, there are pathological cases that can cause things to go awry. Most layer 2 attacks work by poising hosts’ ARP tables, which works well on simple networks, but is easily detectable. Instead, it is possible to make limited progress by targeting a switch’s CAM table.
First, it might be a good idea to brush up on what a switch is and how it forwards traffic. Roughly, a switch is a piece of hardware or software that connects a number of physical or virtual ports (or “interfaces”) and forwards traffic between them at the data link layer. For example, if Alice, who is connected to port 1 and has MAC address
aa:aa:aa:aa:aa:aa, wants to send a message to Bob, who is connected to port 2 and has mac address
bb:bb:bb:bb:bb:bb, she would craft an Ethernet frame with its destination field set to
bb:bb:bb:bb:bb:bb, and put it on the wire. When the switch receives the frame on port 1 (where Alice is connected), it inspects the destination field and looks up Bob’s MAC address in its CAM table. In this case, it finds a match; Bob’s MAC address corresponds to port 2. The switch puts the frame on the wire, and everybody is happy.
But how does the switch know Bob is on port 2? It keeps a table of mappings from MAC address to port numbers, and populates it using something called the “backwards learning algorithm.” You see, when Bob first connects, the switch doesn’t know who is there, because Bob hasn’t sent anything yet. However, when he sends his first frame, he will invariably set the source address to his own MAC (unless he is doing something evil). When the switch receives the frame, it will inspect the source field, notice that it doesn’t have a mapping for
bb:bb:bb:bb:bb:bb, and create one that maps to port 2.
Of course, being physical objects, switches are limited to a finite number of mappings. Hardware switches use a technology called content-addressable memory, or CAM, which you can think of as a hardware-based associative array or hash table. As such, they do a great job of solving the MAC address-to-port problem illustrated above. (If you’re interested, their implementation has a lot in common with CPU caches. Think of CAM as a fully associative cache, but with MAC addresses where the tag bits would go, and port numbers instead of data blocks. On a lookup, the stored addresses are compared to the search key in parallel, and the corresponding port number is returned.) If that sounds a bit over your head, there’s one important thing to remember here: CAMs map a key to a single value; there can never be a situation in which the CAM table maps a MAC address to multiple different ports.
Source address spoofing
So what happens when Mallory, who is evil and connected on port 13, puts a frame on the wire with the source field set to Bob’s MAC address (
bb:bb:bb:bb:bb:bb)? The switch will look up the address in its CAM table, find that it’s already got an entry that maps to port 2, and unquestioningly replace the mapping with a new one for port 13. Now, when Alice tries to send Bob a message, Mallory will get it instead.
Of course, the next time Bob sends, the attack will be undone, and Mallory will have to repeat it. If she wants to keep up, she could try to flood the network with something like this (using scapy):
#!/usr/bin/env python import sys from scapy.all import * victim_mac = sys.argv broadcast_mac = "ff:ff:ff:ff:ff:ff" # Flood all switches frame = Ether(src=victim_mac, dst=broadcast_mac) # No payload is necessary while (1): sendp(frame)
There are limits to this approach, however. It’s not an effective man-in-the-middle attack because it completely denies Bob of service. And Mallory can’t try to cover her tracks by forwarding the intercepted frames on to Bob, because the switch will just forward those frames back to her.
(Actually, it might be possible to develop an implementation that works, at least partially. Mallory could collect Bob’s incoming traffic for several milliseconds at a time, and periodically suspend her attack while she dumps the frames back to him, modified or not. I haven’t tried it, though.)
Filling the CAM table
There’s something I didn’t tell you earlier. We already know that when a switch receives a frame with a source address that’s in its CAM table, it just adds the entry and kicks out whatever was there before it. But what happens when a switch receives a frame with a destination address that’s not in the table? In this case, it has only one choice: forward the frame onto all ports, just like a hub. Hopefully, whoever the frame was destined for will respond; then, the switch can add their MAC address to its CAM table and start forwarding frames just to them.
On some switches, Mallory can take advantage of this by knocking all the legitimate addresses out of the switch’s CAM table. Then, the next time a frame comes in, it won’t be in the table, and the switch will broadcast it to all ports. In other words, Mallory can turn the switch into a hub by spamming it with lots of random MAC addresses:
#!/usr/bin/env python from scapy.all import * def gen_rand_mac(): mac = [random.randint(0, 255) for _ in range(6)] mac |= 0x02 # Set the locally-administered bit mac &= ~0x01 # Unset the multicast bit return ":".join("%02x" % octet for octet in mac) while (1): frame = Ether(src=gen_rand_mac()) sendp(frame)
If Mallory’s attack succeeds, she can use her capability to spy on other users.
Mid- to high-end switches offer a feature, which Cisco calls “port security,” that is designed to prevent exactly this kind of CAM table mischief. Port security allows an admin to lock down exactly which MAC addresses are allowed to communicate over which ports, or to limit the number of unknown MACs that a given port can map to. Obviously, this won't always be practical, but it's one more tool in the bag.
There are other options too, like VLANs. But before you go feature-crazy, it's useful to take a step back and remember that switched Ethernet was an upgrade to an older technology, which people now call “classic” Ethernet. In classic Ethernet, everything was broadcast: if you wanted to send a message to someone, you sent it to everybody; receivers got everyone’s traffic, but ignored it unless it was addressed to them. Switches were introduced to add some intelligence to noisy Ethernet networks, but that basic broadcast behavior lives on in them.
If you want to be able to control traffic between two hosts, make sure they’re not on the same LAN, full stop. Even if you can prevent the kind of CAM table smashing I describe here, there are a ton of other fun tricks an attacker can try if they're on a LAN with a potential target. Maybe I will explore some of those in the future. Thanks for reading.