Skip to content

Commit dbe7e71

Browse files
authored
Merge pull request #823 from BC-SECURITY/release/6.6.0
v6.6.0 into main
2 parents 6a683f2 + 892002d commit dbe7e71

334 files changed

Lines changed: 13314 additions & 3343 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/lint-and-test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ jobs:
7676
run: |
7777
set -o pipefail
7878
if [ "${{ matrix.python-version }}" = "3.14" ]; then
79-
DATABASE_USE=mysql poetry run pytest -v --runslow --cov=empire/server --junitxml=pytest.xml --cov-report=term-missing:skip-covered . | tee pytest-coverage.txt
79+
DATABASE_USE=mysql poetry run pytest -v --runslow --durations=10 --cov=empire/server --junitxml=pytest.xml --cov-report=term-missing:skip-covered . | tee pytest-coverage.txt
8080
else
81-
DATABASE_USE=mysql poetry run pytest -v --runslow .
81+
DATABASE_USE=mysql poetry run pytest -v --runslow --durations=10 .
8282
fi
8383
- name: Run test suite - sqlite
8484
if: ${{ startsWith(github.head_ref, 'release/') || contains(github.event.pull_request.labels.*.name,
8585
'test-sqlite') }}
8686
run: |
87-
DATABASE_USE=sqlite poetry run pytest . -v --runslow
87+
DATABASE_USE=sqlite poetry run pytest . -v --runslow --durations=10 -m "not mysql"
8888
- name: Pytest coverage comment
8989
if: ${{ matrix.python-version == '3.14' }}
9090
uses: MishaKav/pytest-coverage-comment@v1.2.0

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ empire/server/api/static/*
1919
empire/server/api/v2/starkiller-temp
2020
empire/server/api/v2/starkiller
2121
empire/server/Empire-Compiler
22+
loader.bin
2223

2324
# client
2425
empire/client/generated-stagers/*

CHANGELOG.md

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,70 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
## [Unreleased]
1616
- Fixed background jobs for the python agent.
1717

18-
## [6.5.0] - 2026-03-08
19-
- Updated Starkiller to v3.4.0
18+
## [6.6.0] - 2026-04-25
19+
- Updated Starkiller to v3.5.0
20+
21+
### Added
22+
23+
- Added 8 new modules (7 PowerShell, 1 Python) based on Atomic Red Team to fill partial ATT&CK coverage gaps: thread execution hijacking (T1055.003), cached domain credentials (T1003.005), Safe Mode boot defense evasion (T1562.009), default file association hijack (T1546.001), screensaver persistence (T1546.002), Office template macro injection (T1137.001), Wi-Fi credential extraction (T1555, T1016.002), and Linux proc filesystem credential dumping (T1003.007)
24+
- Added 16 new modules (13 PowerShell, 3 Python) based on Atomic Red Team for ATT&CK gap coverage: mshta execution (T1218.005), CHM execution (T1218.001), CMSTP UAC bypass (T1218.003), InstallUtil execution (T1218.004), regasm execution (T1218.009), msiexec execution (T1218.007), indirect command execution (T1202), browser cookie theft (T1539), base64 file encoding (T1027), compile-after-delivery (T1027.004), root certificate installation (T1553.004), hidden user creation (T1564.002), Python startup hooks (T1546.018), Windows Terminal profile persistence (T1547), exfiltration over alternative protocols (T1048.003), and Linux at job scheduling (T1053.002)
25+
- Added 25 new modules (19 PowerShell, 6 Python) based on Atomic Red Team for ATT&CK gap coverage: clear command history (T1070.003), impair history logging (T1562.003), disable firewall (T1562.004), hide artifacts (T1564.001), FSUtil indicator removal (T1070), network share removal (T1070.005), rename system utilities (T1036.003), masquerading (T1036, T1036.005), rundll32 proxy execution (T1218.011), regsvr32 proxy execution (T1218.010), signed script proxy (T1216), jsc.exe compilation (T1127), BITS jobs (T1197), logon script persistence (T1037.001), VM detection (T1497.001), system language discovery (T1614.001), web beaconing (T1071.001), and local data staging (T1074.001)
26+
- Added `./ps-empire test` command as a convenience wrapper for pytest with passthrough arguments
27+
- Added Alembic database migration framework for versioned schema management. Untracked databases are stamped at the baseline revision on first startup; already-tracked databases are left as-is so pending migrations can be applied. Includes `migrate_db()` and `backup_db()` functions for future update workflows.
28+
- Added configurable MySQL connection pool settings (`pool_size`, `max_overflow`, `pool_pre_ping`, `pool_recycle`) via server config YAML
29+
- Added pool health monitoring that warns at 80% capacity
30+
- Added `mysql` pytest marker for tests requiring MySQL and Docker
31+
- Added performance test suite (`empire/test/test_performance/`) for pool exhaustion and event loop blocking regression testing
32+
- Added performance tests for module obfuscation (event loop blocking detection, latency measurement, pre-obfuscation latency)
33+
- Added `POST /api/v2/obfuscation/modules/preobfuscate` endpoint for targeted pre-obfuscation of specific modules by ID (runs in background, returns 202)
34+
- Added `strict` and `suggested_values` to boolean switch options in modules for better validation and UI hints
35+
- Added dynamic `depends_on` options to stagers so dependent fields (e.g. `Bypasses`, `Obfuscate`, `ObfuscateCommand`) are shown/hidden based on the selected listener type
36+
- Added `nanodump` BOF module for creating minidumps of the LSASS process using various evasion techniques (handle duplication, process forking, snapshot, seclogon handle leaking)
37+
- Added 7 new BOF modules sourced from Sliver Armory for defense evasion and credential access:
38+
- `unhook` — refresh DLLs to remove EDR/AV API hooks (T1562.001)
39+
- `patchit` — all-in-one AMSI + ETW patch/check/revert (T1562.001)
40+
- `inject_amsi_bypass` — AMSI bypass in a remote process via syscalls (T1562.001)
41+
- `inject_etw_bypass` — ETW bypass in a remote process via syscalls (T1562.001)
42+
- `credman` — dump Windows Credential Manager via SeTrustedCredManAccess (T1555.004)
43+
- `handlekatz` — LSASS dump via handle duplication to evade handle-based detection (T1003.001)
44+
- `bofroast` — Kerberoasting as a BOF without .NET CLR dependency (T1558.003)
45+
- Added multi-language stager support (powershell, csharp, ironpython, go) to UAC bypass privesc modules: `bypassuac`, `bypassuac_env`, `bypassuac_eventvwr`, `bypassuac_sdctlbypass`, `bypassuac_wscript`
46+
- Added configurable `obfuscation.timeout` setting (default: 300s, set to 0 to disable) for the PowerShell obfuscation subprocess, settable via `config.yaml` or `EMPIRE_OBFUSCATION__TIMEOUT` env var
47+
48+
### Changed
49+
50+
- Agent check-in uses single INSERT with ON DUPLICATE KEY UPDATE / ON CONFLICT DO NOTHING instead of SELECT-then-INSERT (2 queries → 1)
51+
- All FastAPI route handlers converted from `async def` to `def`. FastAPI now dispatches every handler to a thread pool, preventing synchronous SQLAlchemy calls from blocking the uvicorn event loop. Handlers that previously offloaded work via `asyncio.to_thread()` no longer need to — the thread pool provides the same isolation automatically.
52+
- High-frequency hooks (`AFTER_AGENT_CALLBACK_HOOK`, `AFTER_TASKING_RESULT_HOOK`, `AFTER_AGENT_CHECKIN_HOOK`, `AFTER_TASKING_HOOK`) now fire with `None` as the session argument. `_run_async_hook` and `run_hooks` provide a fresh managed session to hook callbacks, eliminating the 2x connection amplification that occurred when hooks opened a second connection while the caller still held the first.
53+
- Cleaned up redundant "Switch." prefixes and duplicate description text from module option descriptions
54+
- Marked `Listener` and `Command` options as conditionally required in 7 lateral movement modules (`invoke_psexec`, `invoke_wmi`, `invoke_smbexec`, `invoke_dcom`, `invoke_psremoting`, `inveigh_relay`, `invoke_executemsbuild`) so they are validated when their `depends_on` condition is met
55+
56+
### Removed
57+
58+
- Removed legacy `archive` field from `empire_compiler` config; use `repo` and `ref` instead
59+
60+
### Fixed
61+
62+
- Fixed flaky `test_pool_exhaustion_at_concurrency_levels[250]` CI failures by marking the 250-concurrency case with `pytest.mark.flaky(reruns=2)` via the new `pytest-rerunfailures` dev dependency. The assertion is preserved exactly (250 stays 250), so a real throughput regression still fails all retries while transient CI resource contention clears on rerun.
63+
- Fixed DB pool exhaustion under concurrent load causing 503/504 cascading failures. The root cause was hook connection amplification: async hooks called inside DB session blocks opened a second pool connection via `_run_async_hook` while the caller still held the first, doubling connection usage per check-in.
64+
- Fixed event loop blocking across all API endpoints. Previously only stager, listener, and plugin endpoints were addressed; now all 216 handlers use `def` to prevent any synchronous DB call from blocking the event loop.
65+
- Fixed `donut-shellcode` failing with "Cannot open file" when a root-owned `loader.bin` exists in the working directory, breaking all shellcode generation tests and stager paths. Donut calls now run in an isolated temp directory via a shared `donut_create()` utility with a threading lock for concurrency safety.
66+
- Fixed unnecessary GitHub API call on every server startup when the compiler is already cached locally
67+
- Fixed unhandled `TagInvalidException` in `parse_routing_packet` that caused request crashes from stale agents or non-agent traffic
68+
- Fixed `TypeError` in BOF module parameter packing when integer values were passed to options that require space-checking
69+
- Fixed module option descriptions for `Obfuscate` and `ObfuscateCommand` that contained redundant text
70+
- Fixed `evaluate_dependencies` crashing when `DependsOn` key exists but is `None`
71+
- Fixed strict option validation crashing when `SuggestedValues` is `None`
72+
- Fixed options with unmet `depends_on` conditions being excluded from params, causing `KeyError` in module `generate()` functions — they now pass through with their default value
73+
- Fixed broken `revert_options` logic in `stager_service` that assigned entire option dicts as values, causing circular reference errors during JSON serialization
74+
- Fixed `invoke_ntsd` module setting stager options without the `["Value"]` key, causing `TypeError` during launcher generation
75+
- Fixed `invoke_executemsbuild` `Command` option `depends_on` pointing to `Payload=Empire` instead of `Payload=Manual`, and added missing `depends_on` for `Listener`
76+
- Fixed agent staging log messages displaying wrong language (e.g. "Python PUB key" for PowerShell agents, "PS" in C# block) by replacing hardcoded language names with the actual agent language
77+
- Fixed incorrect log levels in agent communication: `log.error` for normal conditions (agent not active, agent exiting) downgraded to `log.debug`/`log.info`, `log.info` for invalid data (bad language spec, malformed sysinfo) upgraded to `log.warning`
78+
- Fixed typo in SOCKS client error message ("failed to started" -> "failed to start")
79+
- Fixed double-obfuscation in PowerShell module script generation — when a module source was already obfuscated (via `get_module_source` or `auto_get_source`), `finalize_module` was re-obfuscating the entire combined script, spawning a redundant PowerShell subprocess per task. `finalize_module` now accepts `script_already_obfuscated` to skip the expensive re-obfuscation while still obfuscating the invoke command (`script_end`).
80+
- Fixed obfuscation subprocess (`Invoke-Obfuscation`) running indefinitely with no timeout. Added 300s timeout, process group isolation (`start_new_session`), return code checking, and empty output validation. On failure, gracefully falls back to keyword-obfuscated script with error logging.
81+
- Fixed background jobs for the python agent.
2082

2183
## [6.5.0] - 2026-03-08
2284
- Updated Starkiller to v3.4.0
@@ -29,6 +91,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2991
- Added `clipboard_window_inject_list` BOF module for enumerating processes with clipboard window class
3092
- Added PIC shellcode C template and linker script for MinGW-based shellcode compilation
3193
- Added unit tests for `shellcode_compiler` and rewrote `test_bof_packer` to cover the new `Packer` class API
94+
- Added `repo` and `ref` fields to `empire_compiler` config, replacing the hardcoded archive URL with GitHub Releases API asset discovery
95+
- Added unit tests for compiler platform resolution and download URL logic
3296
- Added a runtime `Background` option to C# modules, allowing operators to override background/foreground execution at task time
3397
- Added C# PatchETW module for in-process ETW patching via ntdll!EtwEventWrite
3498
- Added C# PatchlessAMSI module for patchless AMSI bypass using hardware breakpoints and vectored exception handling
@@ -37,6 +101,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
37101
- Added Python linux_keyring module for credential extraction from the Linux kernel keyring subsystem
38102
- Added Python aws_imds module for AWS IAM role credential theft via EC2 Instance Metadata Service
39103
- Added BOF `spawn` module for EarlyBird process hollowing with suspended process creation, shellcode injection, and APC thread hijacking
104+
- Agent "got results" log message now includes the task ID for easier post-mortem correlation
40105

41106
### Changed
42107

@@ -1337,7 +1402,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13371402
- Updated shellcoderdi to newest version (@Cx01N)
13381403
- Added a Nim launcher (@Hubbl3)
13391404

1340-
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.5.0...HEAD
1405+
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.6.0...HEAD
1406+
1407+
[6.6.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.5.0...v6.6.0
13411408

13421409
[6.5.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.4.1...v6.5.0
13431410

alembic.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[alembic]
2+
script_location = empire/server/core/db/alembic
3+
# Database URL is resolved programmatically in env.py
4+
# using the existing Empire configuration system.
5+
sqlalchemy.url =

conftest.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,23 @@ def pytest_addoption(parser):
1616
def pytest_configure(config):
1717
config.addinivalue_line("markers", "slow: mark test as slow to run")
1818
config.addinivalue_line("markers", "no_docker: mark test as failing in docker")
19+
config.addinivalue_line(
20+
"markers", "compiler: requires C# compiler (EmpireCompiler)"
21+
)
22+
config.addinivalue_line(
23+
"markers", "mysql: mark test as requiring MySQL (and Docker)"
24+
)
1925

2026

2127
def pytest_collection_modifyitems(config, items):
2228
if config.getoption("--runslow"):
2329
# --runslow given in cli: do not skip slow tests
24-
return
25-
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
26-
for item in items:
27-
if "slow" in item.keywords:
28-
item.add_marker(skip_slow)
30+
pass
31+
else:
32+
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
33+
for item in items:
34+
if "slow" in item.keywords:
35+
item.add_marker(skip_slow)
2936

3037
if config.getoption("--nodocker"):
3138
# --nodocker given in cli: skip tests that fail in docker

docs/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
* [Main Agent Class](agents/go/mainagentclass.md)
4646
* [Packet Handler Class](agents/go/packethandlerclass.md)
4747
* [Main.go Template](agents/go/template.md)
48+
* [C](agents/c/README.md)
4849
* [Staging](agents/staging.md)
4950
* [RESTful API](restful-api/README.md)
5051
* ```yaml

docs/agents/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ The Go agent (`Gopire`) is designed for use in environments where Go is advantag
2727

2828
Additional documentation on the agent can be found [here](./go/README.md).
2929

30+
## C Agent
31+
The C agent (`Cpire`) is an experimental native agent modeled after the Go agent. It compiles into a standalone binary and supports Windows and Linux targets. **Currently, the C agent supports the HTTP listener only.**
32+
33+
The C agent is only available in the [Sponsors](https://github.com/sponsors/BC-SECURITY) version of Empire.
34+
35+
### Features
36+
- Cross-platform: supports Windows and Linux targets.
37+
- Native compiled binary with no runtime dependencies.
38+
- Runs PowerShell, C#, BOF, and shell taskings.
39+
- Full DH key exchange staging with Ed25519 certificate verification.
40+
- File download/upload and directory listing.
41+
- Agent controls: delay/jitter, kill date, working hours, lost-limit enforcement.
42+
43+
Additional documentation on the agent can be found [here](./c/README.md).
44+
3045
## PowerShell Agent
3146
The PowerShell agent is the original agent for Empire.
3247

docs/agents/c/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# C Agent Overview
2+
3+
The C agent (`Cpire`) is an experimental native agent for Empire, modeled after the Go agent (Gopire). It compiles into a standalone binary and supports Windows and Linux targets via cross-compilation. **Currently, the C agent supports the HTTP listener only.**
4+
5+
The C agent is only available in the [Sponsors](https://github.com/sponsors/BC-SECURITY) version of Empire.
6+
7+
## Prerequisites
8+
9+
To compile the C agent, the following are required:
10+
11+
- A C compiler (GCC or MinGW for cross-compilation)
12+
- OpenSSL development libraries
13+
- For Windows targets: `x86_64-w64-mingw32-gcc` (MinGW-w64 toolchain)
14+
15+
## Compilation and Setup
16+
17+
The C agent is compiled server-side via the `CCompiler` class. When generating a stager through the `multi/c_exe` stager, the server handles compilation automatically using the configured compiler.
18+
19+
### Stager Options
20+
21+
| Option | Description | Default |
22+
|--------|-------------|---------|
23+
| `Listener` | Listener to use (required) | - |
24+
| `CC` | C compiler override | `x86_64-w64-mingw32-gcc` (Windows) or `gcc` (Linux) |
25+
| `CFLAGS` | Extra compiler flags | - |
26+
| `TargetOS` | Target OS: `windows` or `linux` | `windows` |
27+
28+
### Manual Compilation (Outside Empire)
29+
30+
```bash
31+
# Windows target (cross-compile from Linux)
32+
x86_64-w64-mingw32-gcc -o cpire.exe main.c agent/*.c comms/*.c crypto/*.c tasks/*.c common/*.c profile/*.c \
33+
-I. -Iagent -Icomms -Icrypto -Itasks -Icommon -Iprofile \
34+
-I/opt/openssl-mingw64/include -L/opt/openssl-mingw64/lib64 \
35+
-lssl -lcrypto -lws2_32 -lwinhttp -lcrypt32 -lole32 -loleaut32 -ladvapi32 -static
36+
37+
# Linux target
38+
gcc -o cpire main.c agent/*.c comms/*.c crypto/*.c tasks/*.c common/*.c profile/*.c \
39+
-I. -Iagent -Icomms -Icrypto -Itasks -Icommon -Iprofile \
40+
-lssl -lcrypto -lcurl
41+
```
42+
43+
## Features
44+
45+
- **Cross-platform**: Supports Windows and Linux targets.
46+
- **Native binary**: Compiles to a standalone executable with no runtime dependencies (statically linked on Windows).
47+
- **Full staging**: DH key exchange with Ed25519 certificate verification, AES-CBC encrypt-then-HMAC session keys, and ChaCha20-Poly1305 routing packets.
48+
- **Encrypted comms**: HTTP/HTTPS via WinHTTP (Windows) or libcurl (Linux).
49+
- **Task execution**: Shell commands, PowerShell, C#/.NET assembly loading, and BOF (Beacon Object File) execution.
50+
- **File operations**: File download (chunked), upload, and JSON directory listing.
51+
- **Agent controls**: Delay/jitter, kill date, working hours, and lost-limit enforcement.
52+
- **OPSEC**: No debug output in production builds. Debug logging available via `-DCPIRE_DEBUG` compile flag.
53+
- **HTTP listener support**: Only supports the HTTP listener for communication.
54+
55+
## Supported Tasks
56+
57+
| Task ID | Name | Description |
58+
|---------|------|-------------|
59+
| 1 | SYSINFO | Collect system information |
60+
| 2 | EXIT | Terminate the agent |
61+
| 10/12 | SET/GET_DELAY | Set or query delay and jitter |
62+
| 30/31 | SET/GET_KILLDATE | Set or query kill date |
63+
| 32/33 | SET/GET_WORKING_HOURS | Set or query working hours |
64+
| 40 | SHELL | Execute a shell command |
65+
| 41 | DOWNLOAD | Download a file from target (chunked) |
66+
| 42 | UPLOAD | Upload a file to target |
67+
| 43 | DIR_LIST | List directory contents (JSON) |
68+
| 100 | POWERSHELL | Execute PowerShell script (wait for output) |
69+
| 101 | POWERSHELL_CMD_WAIT | Execute PowerShell with save-file prefix |
70+
| 102 | POWERSHELL_CMD_JOB | Execute PowerShell (background) |
71+
| 120 | CSHARP_CMD_WAIT | Load and execute .NET assembly |
72+
| 121 | CSHARP_CMD_WAIT (save) | Load .NET assembly with save-file prefix |
73+
| 122 | CSHARP_CMD_JOB | Load .NET assembly (background) |
74+
| 123 | CSHARP_CMD_JOB (save) | Load .NET assembly background with save-file |
75+
| 130 | BOF_CMD_WAIT | Execute Beacon Object File |
76+
77+
## Security
78+
79+
The `CCompiler` class validates compiler flags and compiler binaries against an allowlist to prevent command injection during server-side compilation. The agent zeros all cryptographic key material using `OPENSSL_cleanse` before freeing memory to prevent forensic recovery.

0 commit comments

Comments
 (0)