Files
Anthropic-Cybersecurity-Skills/skills/performing-iot-security-assessment/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

242 lines
8.4 KiB
Python

#!/usr/bin/env python3
"""Agent for performing IoT security assessment.
Automates IoT device reconnaissance, firmware extraction with binwalk,
network traffic analysis, and service scanning for security testing.
"""
import subprocess
import json
import sys
import hashlib
from pathlib import Path
class IoTSecurityAgent:
"""Performs automated IoT device security assessments."""
def __init__(self, target_ip, output_dir):
self.target_ip = target_ip
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
def scan_services(self):
"""Scan target for open services using nmap."""
result = subprocess.run(
["nmap", "-sV", "-sC", "-p-", "-oJ", "-", self.target_ip],
capture_output=True, text=True, timeout=300,
)
services = []
for line in result.stdout.splitlines():
if "/tcp" in line or "/udp" in line:
parts = line.split()
if len(parts) >= 3:
services.append({
"port": parts[0],
"state": parts[1],
"service": " ".join(parts[2:]),
})
return {"target": self.target_ip, "services": services, "raw": result.stdout}
def check_default_credentials(self):
"""Test common default credentials against discovered services."""
default_creds = [
("admin", "admin"), ("admin", "password"), ("admin", "1234"),
("root", "root"), ("root", "admin"), ("root", "password"),
("admin", ""), ("user", "user"), ("guest", "guest"),
]
results = []
for username, password in default_creds:
result = subprocess.run(
["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
"-u", f"{username}:{password}",
f"http://{self.target_ip}/", "--max-time", "5"],
capture_output=True, text=True,
timeout=120,
)
status = result.stdout.strip()
if status in ("200", "301", "302"):
results.append({
"username": username,
"password": password,
"status": status,
"vulnerable": True,
})
return results
def analyze_firmware(self, firmware_path):
"""Analyze firmware image with binwalk."""
fw_path = Path(firmware_path)
if not fw_path.exists():
return {"error": f"Firmware file not found: {firmware_path}"}
sha256 = hashlib.sha256(fw_path.read_bytes()).hexdigest()
scan_result = subprocess.run(
["binwalk", str(fw_path)], capture_output=True, text=True,
timeout=120,
)
extract_dir = self.output_dir / "firmware_extracted"
subprocess.run(
["binwalk", "-eM", "-C", str(extract_dir), str(fw_path)],
capture_output=True, text=True,
timeout=120,
)
creds_found = []
for root, dirs, files in (extract_dir).rglob("*") if extract_dir.exists() else []:
pass
if extract_dir.exists():
grep_result = subprocess.run(
["grep", "-rn", "-i", "password\\|passwd\\|secret",
str(extract_dir)],
capture_output=True, text=True,
timeout=120,
)
for line in grep_result.stdout.splitlines()[:20]:
creds_found.append(line.strip())
return {
"sha256": sha256,
"size": fw_path.stat().st_size,
"binwalk_scan": scan_result.stdout,
"credentials_found": creds_found,
"extract_dir": str(extract_dir),
}
def capture_traffic(self, interface="eth0", duration=30):
"""Capture network traffic from the IoT device."""
pcap_path = self.output_dir / "iot_capture.pcap"
subprocess.run(
["timeout", str(duration), "tcpdump", "-i", interface,
f"host {self.target_ip}", "-w", str(pcap_path)],
capture_output=True, timeout=duration + 10,
)
if pcap_path.exists():
stats = subprocess.run(
["capinfos", str(pcap_path)], capture_output=True, text=True,
timeout=120,
)
return {"pcap": str(pcap_path), "stats": stats.stdout}
return {"error": "Capture failed"}
def check_tls_configuration(self, port=443):
"""Check TLS configuration on HTTPS services."""
result = subprocess.run(
["openssl", "s_client", "-connect", f"{self.target_ip}:{port}",
"-brief"],
input="", capture_output=True, text=True, timeout=10,
)
tls_info = {
"raw": result.stdout + result.stderr,
"self_signed": "self signed" in (result.stdout + result.stderr).lower(),
}
for line in (result.stdout + result.stderr).splitlines():
if "Protocol" in line:
tls_info["protocol"] = line.strip()
if "Cipher" in line:
tls_info["cipher"] = line.strip()
return tls_info
def check_upnp_exposure(self):
"""Check for UPnP service exposure."""
result = subprocess.run(
["nmap", "-sU", "-p", "1900", "--script=upnp-info", self.target_ip],
capture_output=True, text=True, timeout=30,
)
return {
"upnp_detected": "upnp" in result.stdout.lower(),
"output": result.stdout,
}
def check_mqtt(self, port=1883):
"""Check for unauthenticated MQTT access."""
try:
import paho.mqtt.client as mqtt
connected = False
topics = []
def on_connect(client, userdata, flags, rc):
nonlocal connected
connected = rc == 0
if connected:
client.subscribe("#")
def on_message(client, userdata, msg):
topics.append({"topic": msg.topic, "payload_len": len(msg.payload)})
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(self.target_ip, port, 5)
client.loop_start()
import time
time.sleep(5)
client.loop_stop()
client.disconnect()
return {
"unauthenticated_access": connected,
"topics_found": len(topics),
"sample_topics": topics[:10],
}
except Exception as e:
return {"error": str(e)}
def generate_report(self, firmware_path=None):
"""Run full IoT security assessment and generate report."""
report = {"target": self.target_ip, "findings": []}
services = self.scan_services()
report["services"] = services
creds = self.check_default_credentials()
if creds:
report["findings"].append({
"id": "IOT-001", "severity": "Critical",
"title": "Default Credentials Accepted",
"details": creds,
})
tls = self.check_tls_configuration()
if tls.get("self_signed"):
report["findings"].append({
"id": "IOT-002", "severity": "Medium",
"title": "Self-Signed TLS Certificate",
"details": tls,
})
if firmware_path:
fw = self.analyze_firmware(firmware_path)
report["firmware_analysis"] = fw
if fw.get("credentials_found"):
report["findings"].append({
"id": "IOT-003", "severity": "Critical",
"title": "Hardcoded Credentials in Firmware",
"count": len(fw["credentials_found"]),
})
report_path = self.output_dir / "iot_assessment_report.json"
with open(report_path, "w") as f:
json.dump(report, f, indent=2)
print(json.dumps(report, indent=2))
return report
def main():
if len(sys.argv) < 3:
print("Usage: agent.py <target_ip> <output_dir> [firmware_path]")
sys.exit(1)
target_ip = sys.argv[1]
output_dir = sys.argv[2]
firmware_path = sys.argv[3] if len(sys.argv) > 3 else None
agent = IoTSecurityAgent(target_ip, output_dir)
agent.generate_report(firmware_path)
if __name__ == "__main__":
main()