Havoc is a modern and malleable post-exploitation command and control framework.
- Version History
- Known Issues
- Installation
- Teamserver
- Client
- Agents
- External C2
- Custom Agents
- Python API
- Modules
- FAQ
- TODO
Named after the Strand of Jotaro Kujo in JoJo's Bizzare Adventure, Star Platinum was among the very first Strands introduced.
- The first, public release of Havoc.
See the Issues tab for all open issues.
Kali has issues loading the proper font (Monaco) from the embedeed Qt resources file.
You will experience formatting issues in the Havoc client if you are not using a monospace/fixed-width font!
If you get an error that Python.h
isn't found when building, you need to make sure Python 3.10 is installed and you have the Python 3.10 development files. If you are using Ubuntu LTS you may need to leverage a PPA such as deadsnakes
to get a newer version of Python.
sudo apt install build-essential
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.10 python3.10-dev
You probably need a newer version of Qt. If you are using Ubuntu try adding a backports ppa and installing the latest qt6 dev packages.
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 libspdlog-dev python3-dev libboost-all-dev mingw-w64 nasm
You must enable Python 3.10 in your APT repositories before you can run the Client successfully.
sudo apt install build-essential
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.10 python3.10-dev
You must setup the
bookworm
repo for Python 3.10.
echo 'deb http://ftp.de.debian.org/debian bookworm main' >> /etc/apt/sources.list
sudo apt update
sudo apt install python3-dev python3.10-dev libpython3.10 libpython3.10-dev python3.10
If you are using a debian-based distro, you can use the bundled installation script at
/Havoc/Client/Install.sh
.
Clone the repository:
git clone https://github.com/HavocFramework/Havoc.git
Build and Run:
cd Havoc/Client
mkdir Build
cd Build
cmake ..
cd ..
./Havoc.sh
Running Havoc.sh
will automatically build the Client and start it.
If you are using a debian-based distro, you can use the bundled installation script at
/Havoc/Teamserver/Install.sh
Install additional Go dependencies:
cd Havoc/Teamserver
go mod download golang.org/x/sys
go mod download github.com/ugorji/go
Build and Run:
cd Havoc/Teamserver
make
./bin/teamserver -h
Build the Dockerfile with Jenkins:
sudo docker build -t havoc-client -f Client-Dockerfile .
Create data volume for persistence (optional):
sudo docker volume create havoc-c2-client
Run the container:
sudo docker run -p 443:443 -p 40056:40056-it -d -v havoc-c2-client:/data havoc-client
Enter the container and run the Client:
- NOT COMPLETE
Build the Dockerfile with Jenkins:
sudo docker build -f JC-Dockerfile .
Run the container:
sudo docker run -p8080:8080 -it -d -v havoc-c2-data:/data havoc-client
Visit Jenkins at localhost:8080
and create a pipeline to build the Havoc Teamserver.
- See
Havoc-Teamserver.groovy
in theAssets
folder.
The Havoc Teamserver is written in Golang. It handles the listeners, teamserver authentication and payload generation. It also supports ExternalC2 functionality through the configuration of Service endpoints.
A script is included to automatically start the Teamserver using some default options:
Havoc/Teamserver/teamserver
.
Running ./teamserver
will automatically build the Teamserver, set it as executable and start it with the following options:
./bin/teamserver server --profile profiles/havoc.yaotl -v
Usage: teamserver [command] [flags]
Here is a full list of arguments that can be passed to the teamserver:
Command | Flag | Description | Args |
---|---|---|---|
server |
--profile |
The configuration profile to load at start | Teamserver profile path (string ) |
-v / --verbose |
Enable verbose output | ||
-d / --debug |
Enable debug ouput | ||
-h / --help |
Output server help | ||
--debug-dev |
Enables DEBUG output (see below for caveats) |
DEBUG output can be enabled by passing the
--debug-dev
flag to the Teamserver.
When this flag is set, the Teamserver's builder
class adds the -D DEBUG
flag to the builder.compilerOptions.CFlags
array and removes the -nostdlib
flag to enable output to be printed to the console. Demon agent payloads genereated from the Havoc client will print visible DEBUG text in the console window after execution. The stdlib will be linked into the payload for this to occur, increasing the payload size.
Havoc's Teamserver uses profiles in the yaotl
format, which is a custom configuration syntax built on top of HCL.
Profiles are located at: Havoc/Teamserver/profiles
and can be passed to the teamserver
with the --profile <path-to-profile
flag.
The default example profile can be found at Havoc/Teamserver/profiles/havoc_default.yaotl
.
The teamserver can be configured to listen on a specific bind address and port with the following directive:
Teamserver {
Host = "0.0.0.0"
Port = 40056
}
Host
- The bind address used by the teamserver to accept Client connections.Port
- The port the teamserver listens on for Client connections.
Multiple users can be added to the Teamserver with the Operators directive:
Operators {
user "5pider" {
Password = "password1234"
}
user "Neo" {
Password = "password1234"
}
}
The primary Demon agent accepts a number of configuration options such as:
Demon {
Sleep = 2
Jitter = 20
Implant {
SleepMask = 1
SleepMaskTechnique = 0
}
Injection {
Spawn64 = "C:\\Windows\\System32\\notepad.exe"
Spawn32 = "C:\\Windows\\SysWOW64\\notepad.exe"
}
}
-
Sleep
- The default interval to sleep between check-ins for commands. -
Jitter
- The amount of jitter to be applied to sleep intervals (in milliseconds). -
Implant\SleepMask
- Enables the Sleep Mask obfuscation -
Implant\SleepMaskTechnique
- Chose from a variety of built-in sleep mask techniques:0
- WaitForSingleObjectEx (no obfuscation)1
- FOLIAGE2
- Ekko
-
Injection\Spawn64
- The full path to the process to spawn into for fork & run operations (64bit). -
Injection\Spawn32
- The full path to the process to spawn into for fork & run operations (32bit).
Currently, only HTTP/HTTPS listeners are supported.
Havoc supports multiple listener profiles and a variety of configuration options to help customize them.
Listeners {
Http {
Name = "HTTPS Listener"
Host = "10.0.0.10"
Port = 443
Method = "POST"
Secure = true
UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
Uris = [
"/funny_cat.gif",
"/index.php",
"/test.txt",
"/helloworld.js"
]
Headers = [
"X-Havoc: true",
"X-Havoc-Agent: Demon",
]
Response {
Headers = [
"Content-type: text/plain",
"X-IsHavocFramework: true",
]
}
}
}
The Havoc Client is written in C++ and Qt.
cd Havoc/Client
./Havoc.sh
The Havoc.sh
script will automatically build the Client and execute it afterwards.
When the client opens, you will be presented with a profile window similar to that in other C2 frameworks like Cobalt Strike.
Enter the profile name, teamserver bind address (Host
) and Port
, along with your defined username/password in the teamserver profile.
Demon is the primary Havoc agent, written in C/ASM. The source-code is located at Havoc/Teamserver/data/implants/Demon
.
Currently, only x64 EXE/DLL formats are supported.
From the Havoc UI, nagivate to Attack -> Payload
.
Directory | Description |
---|---|
Source/Asm |
Assembly code (return address stack spoofing) |
Source/Core |
Core functionality (transport, win32 apis, syscalls) |
Source/Crypt |
AES/XOR encryption functionality |
Source/Extra |
KaynLdr (reflective loader) |
Source/Inject |
Injection functionality |
Source/Loader |
COFF Loader, Beacon API |
Source/Main |
PE/DLL/RDLL Entry Points |
When compiled with OBF_SYSCALL
, Demon performs indirect syscalls for many Nt* APIs. By masquerading the RIP
to point to a location within ntdll.dll
, traps placed by EDR solutions (such as process instrumentation callbacks or other forms of sycall tracing)may be evaded.
The Syscall logic is primarily contained within /Teamserver/data/implants/Demon/Source/Core/Syscalls.c
Syscall stubs are dynamically crafted from ntdll.dll on disk and modified so the return address points to NtAddBootEntry (0x180024b6)
within the ntdll.dll module.
Demon has a variety of commands built-in. It also supports the dynamic modification of configuration at runtime, allowing operators to customize defaults pre-set in the profiles throughout an engagement, without modifying the profile and re-generating a payload.
Full documentation on commands can be accessed from the Havoc client by typing help
in the interact window. For more information on a particular command, simply tack it on the end of help like so: help [command]
Requests a checkin request from the Demon. This will output some basic system/configuration information to the Havoc client such as:
- Demon Metadata
- Magic values
- First/Last call in timestamps
- AES Key and IV
- Sleep Delay
- Host Information
- Hostname
- Username
- Domain Name
- Internal IP(s)
- Process Information
- Name
- Architecture
- PID
- Path
- Elevated
- Operating System
- Version
- Build
- Architecture
Demon supports sleeping at a specified delay (seconds) with a randomized jitter amount applied in the profile configuration settings.
sleep [delay]
When the Demon sleeps, it first checks if Sleep Masking is enabled in the profile configuration. If so, as long as there are no active job threads running, it will begin to apply the specified sleep obfuscation method and wait until the provided delay to "wake up" and check-in to the teamserver again.
During sleep, x64 demons may implement return address spoofing to hide the real return address.
Demon implements a multi-threaded job management system that allows the operator to manage long-running tasks.
OPSEC NOTE: Long-running jobs will PREVENT sleep obfuscation from occuring at the specified sleep interval due to the other threads running. Sleep obfuscation will only occur when there are no job threads in a running state.
job list
- Lists all running jobs.job suspend 1
- Suspends a job with the ID of 1job resume 1
- Resumes a job with the ID of 1job kill 1
- Kills a job with the ID of 1
Process management and enumeration system.
proc [command]
proc list
- Display a list of running processes on the target.proc kill [pid]
- Kills a process with the specified PIDproc blockdll [on|off]
- Blocks the loading of DLLs that aren't signed by Microsoft using Process Mitigation Policies
Demon implements a token management vault that allows for token theft, impersonation and privilege modification. All tokens are preserved within a token vault, allowing the operator to list and impersonate any stolen token when convenient.
Tokens are duplicated using
SecurityIdentification
andSecurityImpersonate
privileges, allowingOpenThreadToken
to work on impersonated UIDs with OpenAsSelf set to TRUE.
token getuid
- Prints the current user id from the tokentoken list
- List all stolen tokens in the token vaulttoken steal [pid]
- Steal the token from the specified PID and save it to the token vaulttoken impersonate [id]
- Impersonate a token from the token vaulttoken make [domain] [username] [password]
- Creates a token from the specified credentials and adds it to the vaulttoken privs-get
- Attempt to acquire all privileges from the current tokentoken privs-list
- List all privileges from the current tokentoken revert
- Reverts back to the default process tokentoken remove [id]
- Removes a token from the vaulttoken clear
- Removes all tokens from the vault.
Demon is capable of injecting shellcode (supplied in raw format as a path) into remote processes using process injection or fork & run. Depending on the technique, operators can chose to use higher-level Win32 APIs or NT versions using indirect syscalls.
shellcode inject x64 [pid] [path-to-raw-shellcode]
- Injects shellcode into the remote processshellcode spawn x64 [path-to-raw-shellcode]
- Launches the defined fork & run process and injects the shellcode
OPSEC NOTE: Depending on your injection technique and configuration settings, certain API calls may be performed outside of indirect syscalls.
Here is a high-level overview of each supported process injection technique:
*
means the API call is performed with indirect syscalls
INJECTION_TECHNIQUE_SYSCALL
CreateProcessA
- Allocate Memory
DX_MEM_WIN32 -> VirtualAllocEx
DX_MEM_SYSCALL -> NtAllocateVirtualMemory*
NtWriteVirtualMemory*
NtProtectVirtualMemory*
- Create Thread
DX_THREAD_WIN32 -> CreateRemoteThread
DX_THREAD_SYSCALL -> NtCreateThreadEx*
NtResumeThread*
dotnet list-versions
- Lists all of the installed dotnet versionsdotnet inline-execute [path-to-assembly] [args]
- Executes the dotnet assembly inside of the current process and returns output
OPSEC NOTE: Calling
inline-execute
creates an instance of the CLR (Common Language Runtime) within the demon's process to execute dotnet assemblies. This is an irreversible procedure and may provide more IoCs to defenders.
The inline-execute
works by first creating an instance of the CLR (Common Language Runtime) within the current Demon process. After the CLR is created, amsi.dll
is loaded and patched in-memory to bypass AMSI scanning. Demon then creates an AppDomain and loads the assembly into memory, finding the entry point and passing the commandline args supplied by the user before invoking the method. Output from the assembly is captured and returned to the teamserver.
(INCOMPLETE)
Havoc supports custom agents and ExternalC2 by using Teamserver service endpoints. These are configured using Service
directives (see the Teamserver Profiles documentation).
The Service module is for interacting with external services (custom agents, ExternalC2, etc).
By registering a Service directive, the Teamserver will automatically spawn a service listener that can route commands to/from the Teamserver.
Service {
Endpoint = "service-endpoint"
Password = "service-password"
}
This would create a service endpoint at <teamserver-host>:<teamserver-port>/service-endpoint
that is authenticated with service-password
.
Using Havoc's Service API, custom, third-party agents can be written to interact with the teamserver using the intermediate Python API.
An example of a third-party agent is provided here: https://github.com/HavocFramework/Talon
Talon.py
connects to the Teamserver over the Endpoint
defined in the Service
directive of the teamserver profile.
from havoc.service import HavocService
from havoc.agent import *
class MyCustomAgent(AgentType):
# ...
pass
agent = MyCustomAgent()
havoc_service = HavocService(
endpoint="ws://0.0.0.0:40056/service-endpoint",
password="service-password"
)
havoc_service.register_agent(agent)
Custom commands can be defined using the Python API and extending the Command class:
class CommandShell(Command):
CommandId = COMMAND_SHELL
Name = "shell"
Description = "executes commands using cmd.exe"
Help = ""
NeedAdmin = False
Params = [
CommandParam(
name="commands",
is_file_path=False,
is_optional=False
)
]
Mitr = []
def job_generate( self, arguments: dict ) -> bytes:
Task = Packer()
Task.add_int( self.CommandId )
Task.add_data( "c:\windows\system32\cmd.exe /c " + arguments[ 'commands' ] )
return Task.buffer
https://github.com/HavocFramework/havoc-py
Aside from Havoc's built-in commands, Modules can be loaded into the framework to add more functionality.
An example of some of Havoc's official modules can be found at this repository:
https://github.com/HavocFramework/Modules
Module Template: https://github.com/HavocFramework/Modules/tree/main/Template
Official Modules:
- Powerpick
- Executes unmanaged PowerShell commands by loading the CLR runtime (
4.0.30319
) into the designated fork & run process.
- Executes unmanaged PowerShell commands by loading the CLR runtime (
- InvokeAssembly
- Executes a dotnet assembly into a separate process by bootsrapping the CLR into the designated fork & run process and passing the arguments.
- The dotnet version can be specified in the arguments (
v4.0.30319
is default), as well as the AppDomain name (DefaultAppDomain
is default).
Jobs are ran in their own threads, and sleep obfuscation requires that all threads are suspended in order to encrypt the heap, otherwise the process would crash.