Two case files first: the labs published in full, with the code, configurations, packet captures and numbers to check every claim below. Then the rest of the series, one line each.
Case file 1 — ARP spoofing, stopped by Dynamic ARP Inspection
The network. One VLAN (10, 192.168.10.0/24) in GNS3: a Cisco IOSv router as DHCP server and NAT gateway, a Cisco IOSv-L2 access switch, an Ubuntu victim and a Kali attacker on DHCP, and an Apache/PHP login portal on a static address, served over plain HTTP.
The attack. ARP (RFC 826) is stateless and unauthenticated: a host accepts a reply it never asked for. arp_spoof.py, a bidirectional Scapy poisoner, tells the victim that the server's IP is at Kali's MAC and tells the server the same about the victim. With IP forwarding on and ICMP redirects off, Kali relays everything, so the victim keeps working.
- Time to compromise: under 5 seconds after launch.
- Impact: the victim's login form, captured in clear from the HTTP POST with
tshark. A second script, modify_http.py, goes further and rewrites HTTP responses in flight through NFQUEUE.
- What the victim saw: nothing. No error, no lost connection.
The fix. ip dhcp snooping on VLAN 10 with only the uplink trusted, so the switch builds a binding table of which MAC holds which IP from real DHCP handshakes. ip arp inspection vlan 10 then checks every ARP frame at ingress against that table. The server has a static address, so it gets an explicit ip source binding: without one, DAI would drop the server's own legitimate ARP replies.
The proof. The same script, run again:
show ip arp inspection statistics vlan 10: 12 forwarded, 47 dropped in about 60 seconds — every forged reply.
- The victim's ARP cache keeps the server's real MAC; nothing reaches Kali; the switch logs the drops against the attacker's port, which can be err-disabled automatically.
- Before and after captures (
mitm_capture.pcap, mitm_after_dai.pcap) are in the repository.
What it doesn't fix. DAI removes the on-path position on this segment; it does not make HTTP safe. The report ends on that residual risk: TLS is still required.
Repository · results · full report
Case file 2 — Hijacking IPv6 on a dual-stack network, stopped by RA Guard
The network. A dual-stack enterprise design in GNS3: a Cisco IOSv core router, an IOSvL2 distribution switch with an 802.1Q trunk, Corp users in VLAN 10 (10.1.0.0/24, 2001:db8:2:10::/64) and a guest segment in VLAN 99 holding the attacker. The addressing plan also reserves server and IoT/OT zones, each with an IPv4 subnet and an IPv6 /64.
The attack. IPv6 hosts trust any Router Advertisement on their link. rogue_ra.py sends five forged RAs (ICMPv6 type 134) to ff02::1, half a second apart, advertising 2001:db8:dead::/64 with the SLAAC flag set and a 9000-second router lifetime. The Corp hosts give themselves addresses in the attacker's prefix and install the attacker's link-local address as their default route. Their IPv4 traffic is untouched, which is exactly why this goes unnoticed on networks that only watch IPv4.
The fix.
- RA Guard: a
router policy on the uplink, a host policy on every access port, so RAs are only accepted from where the real router is.
- DHCPv6 Guard (
device-role client) on access ports against rogue DHCPv6 servers.
- ACL parity: the router's IPv4 ACL rewritten for IPv6 intent by intent — established TCP, DNS, HTTPS, ping, lateral movement to the guest prefix denied, implicit deny logged — plus what IPv6 needs that IPv4 does not: Neighbor Solicitation and Advertisement permitted before any deny, Packet-Too-Big for path MTU discovery, and
FE80::/10 denied as a source.
The proof. The same attack against the guarded switch: 5 RAs received, 5 dropped, 0 forwarded. The hosts kept only their legitimate prefix. The lab's 9 test cases all pass: IPv6 routing on, SLAAC addressing works, the IPv4 ACL blocks Corp-to-guest, the IPv6 ACL matches it, NDP still works, the rogue RA is accepted with RA Guard off, dropped with it on, the legitimate RA still gets through, and DHCPv6 Guard is applied on access ports.
What broke along the way — the part a lab teaches and a course doesn't:
- Without
ipv6 unicast-routing the router drops IPv6 silently; and show ipv6 unicast-routing does not exist — it is show running-config | include ipv6 unicast-routing.
- RA Guard needs IOS 15.2(4)S or later. Older images accept every command and enforce none of them.
- An NDP permit placed after a deny breaks neighbour resolution in a way that looks like anything but the ACL.
- Forgetting the
router policy on the uplink drops the legitimate RAs too, which looks like a broken trunk or a SLAAC bug.
Write-up · repository
The rest of the series
Same loop, same method; these write-ups are not published yet. Each line is the weakness, the Cisco IOS control that closes it, and the command that proves it.
Layer 2 and switching
- Rogue DHCP and DHCP starvation → DHCP snooping, trusted uplink only,
ip dhcp snooping limit rate on access ports · show ip dhcp snooping binding
- MAC flooding (
macof fills the CAM table and the switch floods like a hub) → switchport port-security with maximum, violation restrict and sticky MACs · show port-security interface
- VLAN hopping (DTP trunk negotiation, double tagging) →
switchport nonegotiate, an unused native VLAN, vlan dot1q tag native · show interfaces switchport
- STP root takeover (superior BPDUs from Kali) → BPDU Guard on PortFast edges, Root Guard toward the fabric · the rogue port goes
err-disabled
- CDP / LLDP reconnaissance (model, IOS version and management IP broadcast to anyone) → discovery off on user-facing ports ·
show cdp neighbors from the user segment is empty
- IP source spoofing → IP Source Guard (
ip verify source) pinned to the snooping bindings · show ip verify source
IPv6
- NDP spoofing (forged Neighbor Advertisements poison the cache, ARP spoofing's IPv6 twin) → IPv6 snooping and ND inspection ·
show ipv6 neighbors binding
Routing
- OSPF route injection (a rogue router forms an adjacency and advertises a cheaper route) → per-interface key-chain authentication,
passive-interface default · show ip ospf neighbor
- HSRP gateway takeover (a higher-priority hello claims the virtual IP) → HSRP authentication, pinned priority with
preempt · show standby
Network services
- Flat inter-VLAN reachability → extended ACLs near the source, default-deny, mirrored for IPv6 ·
show access-lists hit counts
- NAT / PAT exposure → PAT outbound, narrowly scoped static NAT, inbound edge ACL ·
show ip nat translations and outside-in scans
- DNS spoofing from an on-path position → remove the position (DAI, RA Guard), restrict resolvers by ACL · post-hardening capture
- NTP time skew and lost logs → authenticated NTP, central Syslog with timestamps ·
show ntp associations
Device hardening and management
- Telnet credential sniffing → SSHv2 only,
login block-for, VTY ACL · the capture shows only encrypted SSH
- Shared local passwords →
aaa new-model, RADIUS with local fallback, privilege levels · per-user accounting on the server
- SNMPv2c community guessing (
snmpwalk dumps the device) → SNMPv3 auth priv with a restricted view · v2c walks refused
- Control-plane exposure → management ACL and Control-Plane Policing ·
show policy-map control-plane
Wireless and remote access
- WPA2-PSK handshake capture and offline cracking → WPA3 / 802.1X in the Packet Tracer design, site-to-site IPsec between sites · per-user authentication, encrypted tunnel confirmed
Skills it shows
Cisco IOS switch and router hardening (DHCP snooping, DAI, IP Source Guard, port security, BPDU/Root Guard, RA Guard, DHCPv6 Guard, ACLs in IPv4 and IPv6, OSPF and HSRP authentication, SSHv2, AAA/RADIUS, SNMPv3, CoPP); offensive tooling written from scratch in Python and Scapy; packet analysis in Wireshark and tshark; dual-stack network design; and technical reporting with a stated residual risk for every control.