Skip to content

Commit 4b82a26

Browse files
authored
Merge pull request #818 from BC-SECURITY/release/6.5.0
2 parents b8fb1c9 + 62f2cd9 commit 4b82a26

File tree

429 files changed

+7913
-3866
lines changed

Some content is hidden

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

429 files changed

+7913
-3866
lines changed

.github/cst-config-docker.yaml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ commandTests:
77
- name: "python3 version"
88
command: "python3"
99
args: ["--version"]
10-
expectedOutput: ["Python 3.13.*"]
10+
expectedOutput: ["Python 3.14.*"]
1111
- name: "poetry"
1212
command: "which"
1313
args: ["poetry"]
@@ -19,7 +19,7 @@ commandTests:
1919
- name: "poetry python version"
2020
command: "poetry"
2121
args: ["run", "python3", "--version"]
22-
expectedOutput: ["Python 3.13.*"]
22+
expectedOutput: ["Python 3.14.*"]
2323
- name: "powershell which"
2424
command: "which"
2525
args: ["pwsh"]
@@ -44,6 +44,14 @@ commandTests:
4444
command: "go"
4545
args: ["version"]
4646
expectedOutput: ["go version go1.23.* linux/*"]
47+
- name: "mingw64 gcc exists"
48+
command: "which"
49+
args: ["x86_64-w64-mingw32-gcc"]
50+
expectedOutput: ["/usr/bin/x86_64-w64-mingw32-gcc"]
51+
- name: "perl exists"
52+
command: "which"
53+
args: ["perl"]
54+
expectedOutput: ["/usr/bin/perl"]
4755
fileExistenceTests:
4856
- name: 'profiles'
4957
path: '/empire/empire/server/data/profiles/'
@@ -57,3 +65,9 @@ fileExistenceTests:
5765
- name: 'plugin-registries'
5866
path: '/root/.local/share/empire/plugin-registries/BC-SECURITY/main/registry.yaml'
5967
shouldExist: true
68+
- name: 'openssl mingw prefix'
69+
path: '/opt/openssl-mingw64/'
70+
shouldExist: true
71+
- name: 'openssl mingw headers'
72+
path: '/opt/openssl-mingw64/include/openssl/ssl.h'
73+
shouldExist: true

.github/install_tests/cst-config-install-base.yaml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ commandTests:
2525
- name: "poetry python version"
2626
command: "poetry"
2727
args: ["run", "python3", "--version"]
28-
expectedOutput: ["Python 3.13.*"]
28+
expectedOutput: ["Python 3.14.*"]
2929
# powershell
3030
- name: "powershell which"
3131
command: "which"
@@ -54,6 +54,15 @@ commandTests:
5454
command: "which"
5555
args: ["mono"]
5656
expectedOutput: ["/usr/bin/mono"]
57+
# mingw / cross-compile deps
58+
- name: "mingw64 gcc exists"
59+
command: "which"
60+
args: ["x86_64-w64-mingw32-gcc"]
61+
expectedOutput: ["/usr/bin/x86_64-w64-mingw32-gcc"]
62+
- name: "perl exists"
63+
command: "which"
64+
args: ["perl"]
65+
expectedOutput: ["/usr/bin/perl"]
5766
# run
5867
- name: "ps-empire help"
5968
command: "./ps-empire"
@@ -76,3 +85,9 @@ fileExistenceTests:
7685
- name: 'plugin-registries'
7786
path: '/home/empire/.local/share/empire/plugin-registries/BC-SECURITY/main/registry.yaml'
7887
shouldExist: true
88+
- name: 'openssl mingw prefix'
89+
path: '/opt/openssl-mingw64/'
90+
shouldExist: true
91+
- name: 'openssl mingw headers'
92+
path: '/opt/openssl-mingw64/include/openssl/ssl.h'
93+
shouldExist: true

.github/workflows/dockerimage.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ jobs:
4242
platforms: linux/amd64,linux/arm64
4343
push: true
4444
tags: bcsecurity/empire:${{ steps.tag-step.outputs.RELEASE_TAG }}
45+
build-args: COMMIT_SHA=${{ github.sha }}

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ jobs:
1717
if: ${{ startsWith(github.head_ref, 'release/') || contains( github.event.pull_request.labels.*.name,
1818
'run-all-versions') }}
1919
run: |
20-
echo "config={\"python-version\": [\"3.13\"]}" >> $GITHUB_OUTPUT
20+
echo "config={\"python-version\": [\"3.13\", \"3.14\"]}" >> $GITHUB_OUTPUT
2121
- id: not-release
2222
if: ${{ !startsWith(github.head_ref, 'release/') }}
2323
run: |
24-
echo "config={\"python-version\": [\"3.13\"]}" >> $GITHUB_OUTPUT
24+
echo "config={\"python-version\": [\"3.14\"]}" >> $GITHUB_OUTPUT
2525
outputs:
2626
config: ${{ steps.release.outputs.config || steps.not-release.outputs.config
2727
}}
@@ -70,11 +70,12 @@ jobs:
7070
run: |
7171
poetry env use ${{ matrix.python-version }}
7272
poetry install
73-
sudo apt install -y mono-runtime
73+
sudo apt-get update
74+
sudo apt-get install -y mono-runtime mingw-w64 perl
7475
- name: Run test suite - mysql
7576
run: |
7677
set -o pipefail
77-
if [ "${{ matrix.python-version }}" = "3.13" ]; then
78+
if [ "${{ matrix.python-version }}" = "3.14" ]; then
7879
DATABASE_USE=mysql poetry run pytest -v --runslow --cov=empire/server --junitxml=pytest.xml --cov-report=term-missing:skip-covered . | tee pytest-coverage.txt
7980
else
8081
DATABASE_USE=mysql poetry run pytest -v --runslow .
@@ -85,7 +86,7 @@ jobs:
8586
run: |
8687
DATABASE_USE=sqlite poetry run pytest . -v --runslow
8788
- name: Pytest coverage comment
88-
if: ${{ matrix.python-version == '3.13' }}
89+
if: ${{ matrix.python-version == '3.14' }}
8990
uses: MishaKav/pytest-coverage-comment@v1.2.0
9091
with:
9192
pytest-coverage-path: ./pytest-coverage.txt
@@ -125,15 +126,20 @@ jobs:
125126
config: .github/cst-config-docker.yaml
126127
test_install_script:
127128
needs: test
128-
timeout-minutes: 30
129+
timeout-minutes: 45
129130
runs-on: ubuntu-latest
130131
name: Test Install Script
131132
strategy:
132133
matrix:
133-
# Because the box runs out of disk space, we can't run all tests on a single docker compose build.
134+
# Each image builds individually to avoid running out of disk space.
135+
# The OpenSSL cross-compilation for MinGW makes each image too large
136+
# to build multiple in parallel on a single runner.
134137
images:
135-
- ['debian11', 'debian12', 'debian13']
136-
- ['ubuntu2204', 'ubuntu2404']
138+
- ['debian11']
139+
- ['debian12']
140+
- ['debian13']
141+
- ['ubuntu2204']
142+
- ['ubuntu2404']
137143
- ['kalirolling'] # 'parrotrolling'
138144
# Parrot disabled for now because the apt repo is having some slowness issues.
139145
# Install is running up way too many minutes.

.github/workflows/release-private-start.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
- name: Setup Python
3838
uses: actions/setup-python@v6
3939
with:
40-
python-version: '3.12'
40+
python-version: '3.14'
4141
- name: Setup poetry
4242
run: |
4343
curl -sL https://install.python-poetry.org | python - -y

.github/workflows/release-private-tag.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- name: Setup Python
2525
uses: actions/setup-python@v6
2626
with:
27-
python-version: '3.12'
27+
python-version: '3.14'
2828
- name: Setup poetry
2929
run: |
3030
curl -sL https://install.python-poetry.org | python - -y

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.13
1+
3.14

CHANGELOG.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,87 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414

1515
## [Unreleased]
1616

17+
## [6.5.0] - 2026-03-08
18+
- Updated Starkiller to v3.4.0
19+
1720
### Added
1821

22+
- Log Empire version and git commit SHA at startup for easier production diagnostics; commit SHA is baked into the Docker image at build time via `--build-arg`
23+
- Added C stager for lightweight stage0 shellcode injection via Fibers
24+
- Added `shellcode_compiler` utility for compiling position-independent C stagers into raw x64 shellcode for BOF process injection
25+
- Added `clipboard_window_inject_list` BOF module for enumerating processes with clipboard window class
26+
- Added PIC shellcode C template and linker script for MinGW-based shellcode compilation
27+
- Added unit tests for `shellcode_compiler` and rewrote `test_bof_packer` to cover the new `Packer` class API
1928
- Added a runtime `Background` option to C# modules, allowing operators to override background/foreground execution at task time
29+
- Added C# PatchETW module for in-process ETW patching via ntdll!EtwEventWrite
30+
- Added C# PatchlessAMSI module for patchless AMSI bypass using hardware breakpoints and vectored exception handling
31+
- Added PowerShell Invoke-VSSExtract module for NTDS.dit and SYSTEM hive extraction via Volume Shadow Copy
32+
- Added PowerShell Invoke-RDPHijack module for RDP session hijacking via tscon.exe
33+
- Added Python linux_keyring module for credential extraction from the Linux kernel keyring subsystem
34+
- Added Python aws_imds module for AWS IAM role credential theft via EC2 Instance Metadata Service
35+
- Added BOF `spawn` module for EarlyBird process hollowing with suspended process creation, shellcode injection, and APC thread hijacking
36+
37+
### Changed
38+
39+
- Added Python 3.14 support (supports 3.13 and 3.14); Dockerfile now uses `python:3.14.3-trixie`
40+
- Replace `os.path` with `pathlib` in core code and enforce `PTH` lint rule for all core files
41+
- Switch `stager_generation_service` from deprecated `installPath` (str) to `install_path` (Path)
42+
- Optimized test suite for faster CI and local runs
43+
- Modernize Python patterns in core code: use `setdefault()`, truthiness checks, `click.style()` for terminal colors, and remove redundant operations
44+
- Reduced test fixture boilerplate with a shared `make_agent()` factory and deduplicated `plugin_task` fixture across test files
45+
- Removed `autouse` from test fixtures that don't need it, making test dependencies explicit
46+
- Added unit tests for encryption, packet handling, helpers, malleable transformations, and listener utilities
47+
- Migrate remaining `installPath` usages to `install_path` (Path) in core services
48+
- Use `Path.read_text(encoding="utf-8")` instead of `read_bytes().decode()` in stager generation
49+
- Replace `os.system()` calls with `subprocess.run()` in stager JAR generation
50+
- Upgraded all Python dependencies to latest versions (Feb 2026)
51+
- Replace deprecated `handle_error_message` with raised `ModuleValidationException` in all modules (#716)
52+
- Convert 51 modules to use `@auto_get_source` and `@auto_finalize` decorators, eliminating boilerplate (#716)
53+
- Replace unmaintained `terminaltables` dependency with `prettytable` (#809)
54+
- Refactored `bof_packer` from standalone functions to a `Packer` class with granular packing methods (`addbytes`, `addstr`, `addWstr`, `addbool`, `adduint32`, `addint`, `addshort`)
55+
- Rewrote `clipboard_window_inject` BOF module to use PIC shellcode instead of PowerShell launcher-based shellcode generation
56+
- Simplified `clipboard_window_inject` module options by removing unnecessary launcher parameters and corrected BOF format string
57+
- Bumped Empire Compiler from v0.4.3 to v0.4.4
58+
59+
### Removed
60+
61+
- Removed `secinject` BOF module and its pre-compiled binary
2062

2163
### Fixed
2264

65+
- Fixed SQLAlchemy connection pool exhaustion caused by async hooks receiving the caller's committed session. `run_hooks` now wraps async hooks in `_run_async_hook`, which opens a fresh `SessionLocal` session for each hook and closes it cleanly after the hook returns. ORM objects are re-attached via `session.merge()` so lazy-loaded relationships resolve correctly.
66+
- Fixed SQLAlchemy connection pool exhaustion during agent check-ins by releasing the DB session before expensive file I/O, encryption, and packet building in `handle_agent_request()`
67+
- Fixed custom-generate BOF modules (`clipboard_window_inject`, `spawn`, `clipboard_window_inject_list`) returning .NET-only `file|,json` format for Go agents, causing BOF execution to fail on the Go agent's COFF loader
68+
- Added `format_bof_output()` to `ModuleService` to centralize BOF output formatting for Go and .NET agents
69+
- Pass `agent_language` to custom-generate modules so they can produce agent-appropriate output
70+
- Fixed malleable HTTP listener stagers failing after server restart due to random URI regeneration in `Stager._defaults()`
71+
- Fix null-safety bug in `_process_agent_packet` when `save_module_file` returns None on skywalker exploit detection
2372
- Fixed stop-job handlers in PowerShell and Python agents crashing when the target job doesn't exist
73+
- Fixed the `docs/quickstart/installation/README.md` file to specify a previously missing reference to Ubuntu
74+
- Fixed 9 malformed MITRE ATT&CK technique IDs across PowerShell, Python, and C# modules
75+
- Fixed 2 malformed tactic fields that used space-separated strings instead of YAML lists
76+
- Replaced 7 deprecated or revoked ATT&CK techniques with current equivalents
77+
- Added missing `software` field for known ATT&CK tools (Rubeus, BloodHound, Mimikatz)
78+
- Added missing `tactics` field to 82 Python modules that had none
79+
- Fixed 74 technique-to-tactic inconsistencies across all module languages
80+
- Replaced 27 additional deprecated technique IDs predating ATT&CK v10 with current equivalents across Python and template modules
81+
- Removed incorrect T1482 (Domain Trust Discovery) from 32 modules that perform user, group, or computer enumeration
82+
- Removed incorrect T1615 (Group Policy Discovery) from 24 modules unrelated to GPO enumeration
83+
- Replaced T1106 (Native API) with T1059.006 (Python) on 5 DCOS REST API modules
84+
- Added missing `techniques` field to 3 session enumeration modules
85+
- Corrected 3 macOS LaunchAgent persistence modules from T1055 (Process Injection) to T1543.001 (Launch Agent)
86+
- Corrected macOS screensaver credential prompt module from T1113 (Screen Capture) to T1056.002 (GUI Input Capture)
87+
- Corrected Invoke-DownloadFile from T1041 (Exfiltration Over C2) to T1105 (Ingress Tool Transfer)
88+
- Upgraded 3 keylogger modules from parent T1056 to specific T1056.001 (Keylogging) sub-technique
89+
- Upgraded macOS email search module from T1114 to T1114.001 (Local Email Collection) sub-technique
90+
- Upgraded macOS LoginHook persistence from T1037 to T1037.002 (Login Hook) sub-technique
91+
- Added T1105 (Ingress Tool Transfer) to 12 lateral movement modules that deploy stagers to remote hosts
92+
- Added 10 new ATT&CK technique IDs across 51 modules to improve coverage from 181 to 190 unique techniques
93+
- Added T1005 (Data from Local System) to 8 macOS and Linux credential and collection modules
94+
- Added T1550.002 (Pass the Hash) to PsExec, SMBExec, and WMI lateral movement modules
95+
- Added T1562.001 (Impair Defenses) to AMSI bypass, ETW patching, and Outlook security modules
96+
- Fixed duplicate technique entries in RevertToSelf and NetRipper modules
97+
- Fixed PSRansom module `name` field incorrectly set to `Invoke-Script` instead of `PSRansom`
2498

2599
## [6.4.1] - 2026-02-15
26100
- Fixed the `docs/quickstart/installation/README.md` file to specify a previously missing reference to Ubuntu
@@ -1256,7 +1330,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12561330
- Updated shellcoderdi to newest version (@Cx01N)
12571331
- Added a Nim launcher (@Hubbl3)
12581332

1259-
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.4.1...HEAD
1333+
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.5.0...HEAD
1334+
1335+
[6.5.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.4.1...v6.5.0
12601336

12611337
[6.4.1]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v6.4.0...v6.4.1
12621338

Dockerfile

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,36 @@
99
# 2) create volume storage: `docker create -v /empire --name data bcsecurity/empire`
1010
# 3) run out container: `docker run -it --volumes-from data bcsecurity/empire /bin/bash`
1111

12-
FROM python:3.13.6-bullseye
12+
FROM python:3.14.3-trixie
1313

1414
LABEL maintainer="bc-security"
1515
LABEL description="Dockerfile for Empire. https://bc-security.gitbook.io/empire-wiki/quickstart/installation#docker"
1616

1717
ENV DEBIAN_FRONTEND=noninteractive DOTNET_CLI_TELEMETRY_OPTOUT=1
1818

1919
ARG TARGETARCH
20+
ARG COMMIT_SHA=""
21+
ENV EMPIRE_COMMIT_SHA=$COMMIT_SHA
2022

2123
SHELL ["/bin/bash", "-c"]
2224

2325
RUN apt-get update && \
2426
apt-get install -qq \
2527
--no-install-recommends \
2628
apt-transport-https \
29+
ca-certificates \
2730
libicu-dev \
2831
sudo \
2932
zip \
3033
curl \
34+
wget \
3135
git \
3236
openssh-client \
3337
default-jdk \
3438
mono-runtime \
39+
build-essential \
40+
mingw-w64 \
41+
perl \
3542
&& rm -rf /var/lib/apt/lists/*
3643

3744
RUN if [ "$TARGETARCH" = "amd64" ]; then \
@@ -56,6 +63,24 @@ RUN curl -L -o /tmp/go.tar.gz https://go.dev/dl/go1.23.2.linux-${TARGETARCH}.tar
5663
ln -s /opt/go/bin/go /usr/bin/go && \
5764
rm /tmp/go.tar.gz
5865

66+
# Build OpenSSL for MinGW cross-compilation (for Windows C stagers)
67+
RUN set -eux; \
68+
if [ ! -d /opt/openssl-mingw64/include/openssl ]; then \
69+
OPENSSL_VERSION="3.5.4"; \
70+
mkdir -p /tmp/openssl-build; \
71+
cd /tmp/openssl-build; \
72+
wget -q "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz" -O "openssl-${OPENSSL_VERSION}.tar.gz"; \
73+
tar -xzf "openssl-${OPENSSL_VERSION}.tar.gz"; \
74+
cd "openssl-${OPENSSL_VERSION}"; \
75+
./Configure mingw64 no-apps no-async no-docs no-shared no-tests \
76+
--cross-compile-prefix=x86_64-w64-mingw32- \
77+
--prefix=/opt/openssl-mingw64; \
78+
make -j"$(nproc)"; \
79+
make install_dev; \
80+
cd /; \
81+
rm -rf /tmp/openssl-build; \
82+
fi
83+
5984
WORKDIR /empire
6085

6186
COPY pyproject.toml poetry.lock /empire/

docs/modules/module-development/README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ authors:
1414
- name: John Doe
1515
handle: '@johndoe'
1616
description: A sample module demonstrating Empire module structure.
17-
tactics: []
17+
software: ''
18+
tactics:
19+
- TA0002
1820
techniques:
19-
- T1234
21+
- T1059
2022
background: true
2123
output_extension: ps1
2224
needs_admin: false
@@ -32,6 +34,17 @@ options:
3234
strict: true
3335
```
3436
37+
## MITRE ATT&CK Fields
38+
39+
Every module should include proper MITRE ATT&CK metadata. The fields are:
40+
41+
- **`tactics`**: A list of ATT&CK tactic IDs (e.g., `TA0001` through `TA0043`). Every module should have at least one tactic — do not leave this as an empty list.
42+
- **`techniques`**: A list of ATT&CK technique or sub-technique IDs. Use the format `T####` for techniques (e.g., `T1059`) or `T####.###` for sub-techniques (e.g., `T1059.001`).
43+
- **`software`**: If the module wraps a known ATT&CK software entry, set this to its ID (e.g., `S0002` for Mimikatz, `S1071` for Rubeus). Leave as `''` if the tool is not cataloged in ATT&CK.
44+
45+
Refer to the [MITRE ATT&CK Enterprise Matrix](https://attack.mitre.org/matrices/enterprise/) for valid tactic, technique, and software IDs.
46+
47+
3548
## Special Options
3649

3750
Empire reserves certain option names that receive special handling during module execution. These are filtered out of the parameters passed to the module's script and instead control how the task is dispatched or processed.

0 commit comments

Comments
 (0)