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
212 lines
8.3 KiB
Python
212 lines
8.3 KiB
Python
#!/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()
|