#!/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 [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()