#!/usr/bin/env python3 """Honeypot Deployment Agent - deploys OpenCanary honeypots and analyzes interaction logs.""" import json import argparse import logging import subprocess import os from collections import defaultdict from datetime import datetime logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") logger = logging.getLogger(__name__) OPENCANARY_CONFIG_TEMPLATE = { "device.node_id": "opencanary-001", "ip.ignorelist": [], "logtype.console.enabled": True, "logger": { "class": "PyLogger", "kwargs": { "formatters": {"plain": {"format": "%(message)s"}}, "handlers": { "file": { "class": "logging.FileHandler", "filename": "/var/tmp/opencanary.log", }, "console": { "class": "logging.StreamHandler", "stream": "ext://sys.stdout", }, }, }, }, "ftp.enabled": False, "ftp.port": 21, "ftp.banner": "FTP server ready", "http.enabled": False, "http.port": 80, "http.banner": "Apache/2.4.41 (Ubuntu)", "http.skin": "nasLogin", "httpproxy.enabled": False, "httpproxy.port": 8080, "ssh.enabled": False, "ssh.port": 22, "ssh.version": "SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3", "smb.enabled": False, "smb.filelist": [{"name": "passwords.xlsx", "type": "xlsx"}, {"name": "backup-credentials.txt", "type": "txt"}], "telnet.enabled": False, "telnet.port": 23, "telnet.banner": "Welcome to the management console", "rdp.enabled": False, "rdp.port": 3389, "mysql.enabled": False, "mysql.port": 3306, "snmp.enabled": False, "snmp.port": 161, } def generate_config(services, node_id="opencanary-001", log_path="/var/tmp/opencanary.log"): """Generate OpenCanary configuration with specified services enabled.""" config = OPENCANARY_CONFIG_TEMPLATE.copy() config["device.node_id"] = node_id config["logger"]["kwargs"]["handlers"]["file"]["filename"] = log_path for service in services: key = f"{service}.enabled" if key in config: config[key] = True enabled = [s for s in services if f"{s}.enabled" in config] logger.info("Generated config with %d services: %s", len(enabled), ", ".join(enabled)) return config def deploy_opencanary(config, config_path="/etc/opencanaryd/opencanary.conf"): """Deploy OpenCanary with generated configuration.""" os.makedirs(os.path.dirname(config_path), exist_ok=True) with open(config_path, "w") as f: json.dump(config, f, indent=2) logger.info("Configuration written to %s", config_path) start_cmd = ["opencanaryd", "--start"] result = subprocess.run(start_cmd, capture_output=True, text=True, timeout=120) return {"config_path": config_path, "started": result.returncode == 0, "output": result.stdout[:200]} def parse_opencanary_log(log_path="/var/tmp/opencanary.log"): """Parse OpenCanary JSON log file for interaction events.""" events = [] try: with open(log_path) as f: for line in f: line = line.strip() if not line: continue try: event = json.loads(line) events.append({ "timestamp": event.get("utc_time", ""), "dst_host": event.get("dst_host", ""), "dst_port": event.get("dst_port", 0), "src_host": event.get("src_host", ""), "src_port": event.get("src_port", 0), "logtype": event.get("logtype", 0), "node_id": event.get("node_id", ""), "logdata": event.get("logdata", {}), }) except json.JSONDecodeError: continue except FileNotFoundError: logger.warning("Log file not found: %s", log_path) return events def analyze_interactions(events): """Analyze honeypot interactions for threat intelligence.""" by_source = defaultdict(lambda: {"count": 0, "services": set(), "credentials": []}) by_service = defaultdict(int) credential_attempts = [] log_type_map = { 1001: "ftp_login", 2001: "http_login", 3001: "ssh_login", 5001: "smb_file_open", 6001: "telnet_login", 7001: "mysql_login", 8001: "rdp_login", } for event in events: src = event["src_host"] service = log_type_map.get(event["logtype"], f"type_{event['logtype']}") by_source[src]["count"] += 1 by_source[src]["services"].add(service) by_service[service] += 1 logdata = event.get("logdata", {}) username = logdata.get("USERNAME", logdata.get("username", "")) password = logdata.get("PASSWORD", logdata.get("password", "")) if username: cred = {"username": username, "password": password, "service": service, "source": src} credential_attempts.append(cred) by_source[src]["credentials"].append(cred) source_summary = {} for ip, data in sorted(by_source.items(), key=lambda x: x[1]["count"], reverse=True): source_summary[ip] = { "interaction_count": data["count"], "services_targeted": list(data["services"]), "credential_attempts": len(data["credentials"]), } return { "total_interactions": len(events), "unique_sources": len(by_source), "service_distribution": dict(sorted(by_service.items(), key=lambda x: x[1], reverse=True)), "top_sources": dict(list(source_summary.items())[:20]), "credential_attempts": len(credential_attempts), "unique_usernames": len(set(c["username"] for c in credential_attempts)), "top_credentials": credential_attempts[:20], } def check_honeypot_status(): """Check if OpenCanary daemon is running.""" cmd = ["opencanaryd", "--status"] result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) is_running = "running" in result.stdout.lower() or result.returncode == 0 return {"running": is_running, "status_output": result.stdout.strip()[:200]} def generate_report(analysis, status, config): """Generate honeypot deployment and interaction report.""" enabled_services = [k.replace(".enabled", "") for k, v in config.items() if k.endswith(".enabled") and v] report = { "timestamp": datetime.utcnow().isoformat(), "honeypot_type": "OpenCanary", "node_id": config.get("device.node_id", ""), "enabled_services": enabled_services, "daemon_status": status, "interaction_analysis": analysis, } return report def main(): parser = argparse.ArgumentParser(description="Honeypot Deployment and Analysis Agent") parser.add_argument("--action", choices=["deploy", "analyze", "status", "full"], default="analyze") parser.add_argument("--services", nargs="+", default=["ssh", "http", "smb", "ftp", "telnet"], help="Services to enable (default: ssh http smb ftp telnet)") parser.add_argument("--node-id", default="opencanary-001", help="Honeypot node identifier") parser.add_argument("--log-path", default="/var/tmp/opencanary.log", help="OpenCanary log file path") parser.add_argument("--config-path", default="/etc/opencanaryd/opencanary.conf") parser.add_argument("--output", default="honeypot_report.json") args = parser.parse_args() config = generate_config(args.services, args.node_id, args.log_path) if args.action in ("deploy", "full"): deploy_result = deploy_opencanary(config, args.config_path) logger.info("Deployment: %s", "success" if deploy_result["started"] else "failed") status = check_honeypot_status() events = parse_opencanary_log(args.log_path) analysis = analyze_interactions(events) report = generate_report(analysis, status, config) with open(args.output, "w") as f: json.dump(report, f, indent=2, default=str) logger.info("Honeypot: %d interactions from %d sources, %d credential attempts", analysis["total_interactions"], analysis["unique_sources"], analysis["credential_attempts"]) print(json.dumps(report, indent=2, default=str)) if __name__ == "__main__": main()