In this article:
Knowing where difference with real gears lies
For performance reasons, a lot of switch things are actually not part of the IOS code but are implemented in hardware. This includes the ARL, or Address Resolution Logic, which provides all the methods to add, remove and lookup entries in the MAC address table.
Therefore, for the NM-16ESW module to work in GNS3, Dynamips had to reimplement all these normally hardware provided services, or at least push this far enough to allow an unmodified IOS to run on it correctly.
The sad thing is indeed that this is unfinished work, as stated in this module’s source code header:
1 2 3 4 5 6 7 8 9 10 11 | /* * Cisco router simulation platform. * Copyright (c) 2006 Christophe Fillot (cf@utc.fr) * * NM-16ESW ethernet switch module (experimental!) * * It's an attempt of proof of concept, so not optimized at all at this time. * Only L2 switching will be managed (no L3 at all). * * To do next: QoS features (CoS/DSCP handling). */ |
So you’re warned: forget about QoS and expect some oddities.
Hopefully here we are not dealing with QoS but with CAM overflow, and except the final bug (of which the correction should be included in a future versoin of GNS3) there are two main oddities which are of concern to us: one is affecting the MAC address table size and the other the MAC address aging process.
First difference: the MAC address table size tops at 8189 entries
This is actually a non-issue.
The CAM overflow attack exploits the fact that a switch is not able to add any new entry to its CAM table, and therefore fallbacks into “behaving like a hub” (as it is often described, I’ll come on this later).
Most probably due to a minor bug, it seems that the MAC table is considered full at 8189 entries instead of 8192. However, full still means full: the ARL should still fail to store any supplementary entry and the CAM overflow attack should still be successful.
Second difference: the aging-time
setting is not honored
By default, MAC entries should remain the MAC address table for at least 5
minutes (=300 seconds), as defined by the aging-time
setting:
SW1#show mac-address-table aging-time Mac address aging time 300
However, in real gear the whole process behind this parameter is implemented in hardware, and this setting is currently simply ignored by Dynamips’ implementation of the NM-16ESW module.
Dynamips implements its own garbage collection system which deletes old MAC entries after only 30 seconds, making CAM overflow attacks noticeably more tricky to stabilize (but may be a good training against the “backpressure” functionality, designed to allow faster MAC aging when there is a flood of new addresses according to Lukasz.).
The code in charge of this can be found around line 2515 of the dev_nm_16esw.c file:
/* Start the MAC address ager */ data->ager_tid = timer_create_entry(15000,FALSE,10, (timer_proc)bcm5600_arl_ager,data);
This launches the bcm5600_arl_ager()
function every 15 seconds. What this
function does is to scan the whole CAM table and check a hit flag associated to
each MAC address:
- If the flag is set, unset it.
- If the flag is unset, delete the MAC address from the table.
This flag is re-enabled whenever the switch receives a new packet from the corresponding MAC address, keeping active addresses in the table.
You will have to take this behavior into account in order to design a successful CAM overflow attack:
-
Using only random MAC addresses will not do it (sorry
macof
…) since it would allow the switch to flush all faked addresses at once every 30 seconds, making the exploit unstable. -
Each MAC address must be used as a sender at least once every 15 seconds.
-
Actually due to possible issues caused by the increased load, in order to avoid a single packet to be lost or arrive later you would prefer each MAC address to be used two or three times in less than 15 seconds. This should be enough to make your flood both stable and reliable, with CAM tables consistently and constantly filled on all switches on the whole LAN.
Understanding what you can really expect
As explained in the introduction, a lot of literature explains this attack as “making the switch behave like a hub”. While a good overview for the layman, this oversimplified description is wrong from a technical point of view.
To explain this I will first detail how a switches works under normal circumstances, what’s the algorithm behind them:
-
The switch receives an incoming packet on a some port,
-
The switch then checks if the source MAC address is already stored in the MAC address table. If it isn’t and there is a free slot, it records this new MAC address associated to its incoming port (and by the way if the address is already present but associated to another port, it will update the record with the new port). This is also the occasion to reset the aging timer associated to this entry, no matter if it is new or not.
-
The switch then checks if the destination MAC address is already stored in the MAC address table. If it is, then this is all good and the switch outputs the packet on the interface associated to the matching CAM table entry. If it isn’t, the switch outputs the packet on all interfaces except the incoming one (all interfaces belonging to the same VLAN + trunk ports as long as this VLAN is not pruned).
Now, let’s see how a switch works when the CAM overflow condition has been triggered and he did fallback into the so-called “hub” mode… Actually all of this is just nonsense: there is no hub mode and the CAM overflow triggered strictly nothing. The switch just continues to work as it always did:
-
On incoming packets, if and only if the source MAC address is not present in the table will the CAM overflow have any effect since the switch will have no free slot to add this new one and will therefore skip this step. If the address is already present in the table, the switch will reset its aging timer as usual.
-
On outgoing packets, if and only if the destination MAC address is not present in the table will the switch indeed send the packet through “all” of its interfaces. If the MAC address is present in the table, the switch has strictly no reason to act weirdly: it will simply proceed as usual and send the packet only through the port associated to the MAC address.
The main consequences of this are:
-
Despite what is often told, CAM overflow attacks are not a magical way to turn switches into hubs. You will not be forwarded all the traffic passing through the switch.
-
You will not be able to eavesdrop any already active communication (ie. any communication initiated before the MAC flood start). The devices’ MAC address will be already known to the switch and legitimate packets will regularly reset the switch’s aging counters. No matter how hard you flood it these devices’ MAC addresses will stay in the switch’s CAM table and the switch will only forward the traffic to the appropriate ports.
-
You will most likely be able to eavesdrop only a one-side communication from the router to previously inactive devices (shut down or in sleep mode for instance). In real world scenarios, at least during business hours the switch will nearly permanently have the router’s MAC address in its CAM table since almost any traffic on the network will pass through it and, therefore, constantly refresh the aging timer. The main goal of the MAC flood will therefore be to keep previously inactive devices from successfully register their MAC address too onto the switch.
To give a concrete example of the result, most chances are that you will not be able to eavesdrop the user’s password and requests, but you may be able to get the server provided session identifiers and data.
-
But to end with depressing news, what you will achieve is that if you take care to not overload the switches, they will happily forward your flooding packets from switch-to-switch until they contaminate the whole Layer 2 LAN. Only VLAN pruning or a Layer 3 device on the way may limit this dissemination, without that even switches offering only unrelated VLANs ports will see their CAM table being filled-up.
In other words, depending on the topology details launching the attack from VLAN 2 can allow you to access VLAN 2 traffic forwarded from several switches away and can also allow you to affect VLAN 3 switches behavior.
Using the right tool
The tool classically recommended for CAM table overflow attacks is macof
(from the dsniff project, unmaintained for years).
However, this tool makes me the effect of a primitive barbarian from some
fantasy story: brutal, inefficient and unreliable.
This tool generates packets using fully random MAC addresses generated on the fly. This is wrong for two reasons:
-
As we saw above, every inactive MAC addresses are automatically deleted from the CAM table, temporarily freeing a large amount of slots available to record genuine MAC addresses until we managed to fill the table again (which may take a few time if the target is several switches away). And as we also saw, a single genuine packet is sufficient to update the CAM table with a true information and put a definitive end on our eavesdropping on this particular target.
-
Statistically half of the randomly generated MACs have the I/G group bit set. However, it is forbidden to use a group MAC address as sender, as stated in IEEE 802.3-2002, Section 3.2.3(b):
In the Source Address field, the first bit is reserved and set to 0.
Cisco switches (and probably others) are aware of that, and consider such packets as malformed and drop them. This means that half of the packets generated by
macof
are dropped by the first switch they encounter.
macof
also relies on some brute-force strategy by sending its malicious
packets as fast as the attacker’s device and the network allows.
This cause several issues:
-
Switches may malfunction or even crash during the flooding process (several reports state that the switch’s management plane was frozen during such flooding).
-
Due to the load caused on switch-side, these packets may not be reliably relayed from switch-to-switch, causing only the first attacker-facing switch to have its CAM table effectively overflown.
-
Due to the load on attacker’s side, either the network card is fully congested or the CPU usage maxes out. In all cases it is impossible to capture any traffic from the same device, which is sad since capturing traffic is precisely the goal of this attack. The usual advice is to stop flooding when capturing, and alternate between flooding and capturing on a regular basis (every minute for instance given the 5 minutes default aging on real gears, and regarding Dynamips’ 30 seconds it becomes just hopeless). I would also advise to have enough luck to be indeed capturing when interesting information was being exchanged and enough luck to be able to properly counter the periodic MAC table cleaning which seems pretty unfeasible in such conditions.
A good CAM overflow attack tool should:
- Not use more resources than necessary in order to allow a reliable eavesdropping.
- Generate well-formed packets (ie. no useless packets which will get dropped anyway and no packets which will make Wireshark (or an IDS…) complain).
- Ensure that the CAM tables remain constantly filled so new devices will have no chance to register their MAC address.
macof
fails on these three requirements and is therefore not a suitable tool.
A quick search did not revealed any relevant alternative, so I went the
Scapy route (Scapy is a Python library and interactive tool allowing to
freely build and manipulate network packets).
Here is the code I used to successfully test CAM table overflow in a GNS3 environment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #! /usr/bin/python nbpkts = 8192 iface = "eth0" import sys from scapy.all import sendpfast, Ether, IP, RandIP, RandMAC, TCP print("Initializing...") # We first build all packets... pkts = [] for i in xrange(0, nbpkts): macaddr = str(RandMAC()) # Quick-and-dirty way to ensure that the I/G remains unset macaddr = macaddr[:1] + "0" + macaddr[2:] # This packet structure mimics a TCP SYN sent to a HTTP server. # A random dst mac should also work, setting one fixed can be useful # to easily filter-out flood-related packets when capturing traffic. # You can use IPs valid for your range, but be cautious that if any # host is made to send some RST for instance its MAC address will be # registered by the switches. pkts.append(Ether(src=macaddr, dst="ff:ff:ff:ff:ff:ff")/ IP(src=str(RandIP()), dst=str(RandIP()))/ TCP(dport=80, flags="S", options=[('Timestamp', (0, 0))])) print("Launching attack, press Ctrl+C to stop...") # ...and then we send them in loop. while True: # Adapt pps (Packets Per Second) to your needs. Running a complex # GNS3 topology on a low-end machine will take all the CPU causing # packet loss, pps will then need to be high to replay lost packets. # Given enough CPU, packet loss can remain low and pps can be lowered # too. sendpfast(pkts, iface=iface, file_cache=True, pps=5000, loop=999) |
This is a quick-and-dirty, few-lines examples which could be improved in several ways. For instance, would it be used against real gears it may make sense to use two successive sending iterations, the first one being quick in order to rapidly take over CAM tables, and the second one working at a far more slowly pace, taking full advantage of the 5 minutes aging delay to stay below the radar as much as possible (when this default delay is changed, it is generally to be raised and not diminished, and moreover I have some doubts that someone who do not take care of enabling port security on his switches will really bother changing such kind of setting).
Correct a bug currently affecting dynamips
Sadly, when you are through all this, you will discover that when their CAM table is properly filled, the switches in GNS3 will not start to flood packets through “all” of their ports, but they will drop them instead.
This is due to a bug affecting the bcm5600_handle_rx_pkt()
function in charge
of handling received packets and located around line 2170 of the
dev_nm_16esw.c file:
/* Source MAC address learning */ if (!bcm5600_src_mac_learning(d,p)) return(FALSE);
Currently, when the ARL failed to store a new MAC address, the handling of the incoming packet is aborted, effectively resulting in it being drop. The fix is just to ignore the ARL status and continue processing the packet anyway, since this what real gear actually do:
/* Source MAC address learning */ bcm5600_src_mac_learning(d,p);
I’ve raised this issue to GNS3 teams so it can be fixed in GNS3 future updates. I also advocated to raise the MAC table garbage collection timeout from the current 15 seconds to 5 minutes in order to be closer to real gear behavior.
Until this gets fixed upstream, it requires a manual modification and
recompilation of Dynamips source code but this is a very quick and simple
process (there is no need to recompile the whole GNS3, only the dynamips
binary, and I provided the patches in the tickets linked above).
Final notes
After you do that, you will be able to test and repeat MAC overflow attacks in GNS3 with router-based switches in a stable and predictable manner.
Here are two final notes:
-
While router-based switches allow to test CAM overflow attacks, they will not allow to test proper mitigation techniques as they do not implement port security. I think this is a limitation from IOS rather than GNS3 since the relevant options are not even prevent in the shell. IOU proposes these options, however due to its CAM table allowing nearly 200 million entries (compared to the 8192 of a real IOS) it seems out of reach for a traditional CAM overflow attack. So IOU is at the opposite of router-based switches: they can be used to test mitigation techniques but not to reproduce the attack. Be aware also that IOU implementation of the Spanning Tree Protocol (STP) is heavily buggy and topology loops must be avoided.
-
Speaking of STP and depending on the topology, becoming STP Root (
yersinia stp -attack 4
) should induce a clearing of most MAC tables dynamic entries due to the topology change and may provide you a more efficient flooding and eavesdropping experience ;).
Article based on a StackExchange answer.