#!/usr/bin/env python3 """Decoy file (canary) deployment agent for ransomware detection. Deploys canary files across file systems and monitors them for modifications that indicate ransomware encryption activity. Provides real-time alerting when decoy files are modified, renamed, or deleted. """ import hashlib import json import logging import os import sys import time from datetime import datetime logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", ) logger = logging.getLogger("canary_agent") CANARY_EXTENSIONS = [".docx", ".xlsx", ".pdf", ".csv", ".sql", ".txt", ".pptx"] CANARY_NAMES_FIRST = [ "_AAAA_budget_2024", "_AAAA_financial_report", "_AAAA_payroll_data", "_AAA_employee_records", "_AAA_client_contracts", ] CANARY_NAMES_LAST = [ "~zzzz_annual_review", "~zzzz_backup_config", "~zzzz_tax_returns", "~zzz_insurance_claims", "~zzz_merger_docs", ] RANSOMWARE_EXTENSIONS = { ".locked", ".encrypted", ".crypt", ".locky", ".cerber", ".wncry", ".dharma", ".basta", ".blackcat", ".hive", ".royal", ".akira", ".lockbit", ".conti", ".ryuk", ".maze", ".revil", ".phobos", ".makop", ".stop", ".djvu", ".rhysida", } RANSOM_NOTE_NAMES = { "readme.txt", "readme.html", "decrypt.txt", "decrypt.html", "how_to_decrypt.txt", "restore_files.txt", "read_me.txt", "how_to_recover.txt", "ransom_note.txt", } def compute_file_hash(filepath): """Compute SHA-256 hash of a file.""" sha256 = hashlib.sha256() with open(filepath, "rb") as f: for chunk in iter(lambda: f.read(65536), b""): sha256.update(chunk) return sha256.hexdigest() def generate_canary_content(canary_type, name): """Generate realistic content for canary files.""" timestamp = datetime.now().isoformat() content = f"CANARY_TOKEN:{name}\n" content += f"Generated: {timestamp}\n" content += f"Classification: CONFIDENTIAL\n\n" if "budget" in name or "financial" in name: content += "Q4 Financial Summary\n" content += "Total Revenue: $12,450,000\n" content += "Operating Expenses: $8,230,000\n" content += "Net Income: $4,220,000\n" elif "payroll" in name or "employee" in name: content += "Employee Records - Human Resources\n" content += "Total Headcount: 342\n" content += "Departments: Engineering, Sales, Marketing, Operations\n" elif "client" in name or "contract" in name: content += "Client Contract Summary\n" content += "Active Contracts: 156\n" content += "Pending Renewal: 23\n" else: content += "Internal Document - Do Not Distribute\n" content += "This document contains sensitive business information.\n" return content def deploy_canaries(target_dirs, canaries_per_dir=4): """Deploy canary files to target directories.""" deployed = [] names = CANARY_NAMES_FIRST[:canaries_per_dir // 2] + CANARY_NAMES_LAST[:canaries_per_dir // 2] for target_dir in target_dirs: if not os.path.isdir(target_dir): logger.warning("Directory does not exist: %s", target_dir) continue for i, name in enumerate(names): ext = CANARY_EXTENSIONS[i % len(CANARY_EXTENSIONS)] filename = f"{name}{ext}" filepath = os.path.join(target_dir, filename) content = generate_canary_content(ext, name) with open(filepath, "w") as f: f.write(content) file_hash = compute_file_hash(filepath) record = { "path": filepath, "hash": file_hash, "size": os.path.getsize(filepath), "deployed_at": datetime.now().isoformat(), "name": filename, } deployed.append(record) logger.info("Deployed canary: %s (hash: %s)", filepath, file_hash[:16]) return deployed def check_canary_integrity(canary_records): """Check all canary files for modifications, deletions, or renames.""" alerts = [] for record in canary_records: filepath = record["path"] if not os.path.exists(filepath): # Check if file was renamed with ransomware extension parent_dir = os.path.dirname(filepath) basename = os.path.basename(filepath) renamed = False if os.path.isdir(parent_dir): for f in os.listdir(parent_dir): if f.startswith(basename) and any(f.endswith(ext) for ext in RANSOMWARE_EXTENSIONS): alerts.append({ "type": "RANSOMWARE_RENAME", "severity": "CRITICAL", "original": filepath, "renamed_to": os.path.join(parent_dir, f), "timestamp": datetime.now().isoformat(), }) renamed = True break if not renamed: alerts.append({ "type": "CANARY_DELETED", "severity": "HIGH", "path": filepath, "timestamp": datetime.now().isoformat(), }) continue current_hash = compute_file_hash(filepath) if current_hash != record["hash"]: alerts.append({ "type": "CANARY_MODIFIED", "severity": "CRITICAL", "path": filepath, "original_hash": record["hash"], "current_hash": current_hash, "timestamp": datetime.now().isoformat(), }) current_size = os.path.getsize(filepath) if abs(current_size - record["size"]) > record["size"] * 0.5: alerts.append({ "type": "SIGNIFICANT_SIZE_CHANGE", "severity": "HIGH", "path": filepath, "original_size": record["size"], "current_size": current_size, "timestamp": datetime.now().isoformat(), }) # Check for ransom notes in canary directories checked_dirs = set() for record in canary_records: parent_dir = os.path.dirname(record["path"]) if parent_dir in checked_dirs or not os.path.isdir(parent_dir): continue checked_dirs.add(parent_dir) for f in os.listdir(parent_dir): if f.lower() in RANSOM_NOTE_NAMES: alerts.append({ "type": "RANSOM_NOTE_DETECTED", "severity": "CRITICAL", "path": os.path.join(parent_dir, f), "timestamp": datetime.now().isoformat(), }) return alerts def monitor_loop(canary_records, interval=10): """Continuously monitor canary files at specified interval.""" logger.info("Starting canary monitoring loop (interval: %ds)", interval) logger.info("Monitoring %d canary files", len(canary_records)) while True: alerts = check_canary_integrity(canary_records) if alerts: for alert in alerts: logger.critical( "ALERT [%s] %s: %s", alert["severity"], alert["type"], alert.get("path", alert.get("original", "unknown")), ) print(json.dumps({"alerts": alerts}, indent=2)) time.sleep(interval) if __name__ == "__main__": print("=" * 60) print("Ransomware Canary File Deployment Agent") print("Deploy and monitor decoy files for encryption detection") print("=" * 60) if len(sys.argv) < 2: print("\nUsage:") print(" python agent.py deploy [dir2] ... Deploy canaries") print(" python agent.py check Check canary integrity") print(" python agent.py monitor Continuous monitoring") sys.exit(0) command = sys.argv[1] if command == "deploy": dirs = sys.argv[2:] if len(sys.argv) > 2 else [os.getcwd()] records = deploy_canaries(dirs) registry_file = "canary_registry.json" with open(registry_file, "w") as f: json.dump(records, f, indent=2) print(f"\n[+] Deployed {len(records)} canary files across {len(dirs)} directories") print(f"[+] Registry saved to: {registry_file}") elif command == "check": if len(sys.argv) < 3: print("[!] Provide canary registry JSON file") sys.exit(1) with open(sys.argv[2]) as f: records = json.load(f) alerts = check_canary_integrity(records) if alerts: print(f"\n[!] {len(alerts)} ALERTS DETECTED:") for a in alerts: print(f" [{a['severity']}] {a['type']}: {a.get('path', a.get('original'))}") else: print(f"\n[+] All {len(records)} canary files intact. No alerts.") elif command == "monitor": if len(sys.argv) < 3: print("[!] Provide canary registry JSON file") sys.exit(1) with open(sys.argv[2]) as f: records = json.load(f) interval = int(sys.argv[3]) if len(sys.argv) > 3 else 10 monitor_loop(records, interval) else: print(f"[!] Unknown command: {command}")