Skip to content

Commit

Permalink
Merge pull request #715 from BC-SECURITY/release/5.9.1
Browse files Browse the repository at this point in the history
v5.9.1 into main
  • Loading branch information
vinnybod authored Jan 25, 2024
2 parents 59af878 + 0b6b2d8 commit a75ee49
Show file tree
Hide file tree
Showing 338 changed files with 4,493 additions and 1,647 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: psf/black@23.10.1
- uses: psf/black@23.12.0
- name: Run ruff
run: |
pip install ruff==0.1.4
pip install ruff==0.1.9
ruff .
matrix-prep-config:
runs-on: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ repos:
- id: end-of-file-fixer

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.4
rev: v0.1.9
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.10.1
rev: 23.12.0
hooks:
- id: black
language_version: python3.10
64 changes: 63 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [5.9.1] - 2024-01-25

### Changed

- Convert agent task output to string before the BEFORE_TASKING_RESULT_HOOK (@Vinnybod)
- Updated tasklist for powershell code to not throw error when GetOwner fails (@Cx01N)

### Fixed

- Updated Uvicorn to fix issue where an open browser would cause the shutdown to hang (<https://github.com/encode/uvicorn/pull/2145>) (@Vinnybod)
- Fixed the fastapi app lifecycle not being properly called on shutdown (@Vinnybod)
- Converted listener threads to daemons so they don't hang the shutdown in Python 3.12 and report `RuntimeError: can't create new thread at interpreter shutdown` (@Vinnybod)
- Log warning about ps/ls hooks and filters not being able to parse the JSON output (@Vinnybod)

## [5.9.0] - 2024-01-20

### Added

- Added validation and execution exceptions for modules to raise (@Vinnybod)
- Added decorators for module generate functions to automatically get the module_source and call finalize_module (@Vinnybod)
- Added execution exception to plugins (@Vinnybod)
- Added RUF rules to ruff config (@Vinnybod)
- Added SIM rules to ruff config (@Vinnybod)
- Added BOF modules to Empire as yamls (@Cx01N)
- Added ClipBoardWindow-Inject module
- Added nanodump module
- Added secinject module
- Added tgtdelegation module
- Added TrustedSec's SA modules
- Added custom certificate path to server config.yaml (@AaronVigal)

### Deprecated

- Returning tuples from module generate functions is deprecated
- To return a 400, raise a `ModuleValidationException`
- To return a 500, raise a `ModuleExecutionException`
- Stop using `handle_error_message`
- Returning tuples from plugin execution functions is deprecated
- To return a 400, raise a `PluginValidationException`
- To return a 500, raise a `PluginExecutionException`
- Loading plugins from a `.plugin` file is deprecated
- Use a `.py` file with a `plugin.yaml` instead
- Extending the `Plugin` class is deprecated
- Use the `BasePlugin` class instead

### Changed

- Migrated some Pydantic and FastAPI usage away from deprecated features (@Vinnybod)
- Updated the install script and Docker file from Python 3.12.0 to 3.12.1 (@Vinnybod)
- Upgraded all dependencies with `poetry up` (@Vinnybod)
- Plugin updates (@Vinnybod)
- Plugins have a `plugin.yaml`
- Base plugin class is now `BasePlugin`
- Updated plugin documentation
- Upgraded Black to 23.12.0 (@Vinnybod)
- Upgraded Ruff to 0.1.9 (@Vinnybod)
- Upgraded Seatbelt to 1.2.1 (@Cx01N)

## [5.8.4] - 2023-12-22

### Fixed
Expand Down Expand Up @@ -710,7 +768,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated shellcoderdi to newest version (@Cx01N)
- Added a Nim launcher (@Hubbl3)

[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.8.4...HEAD
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.9.1...HEAD

[5.9.1]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.9.0...v5.9.1

[5.9.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.8.4...v5.9.0

[5.8.4]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.8.3...v5.8.4

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# 2) create volume storage: `docker create -v /empire --name data bcsecurity/empire`
# 3) run out container: `docker run -it --volumes-from data bcsecurity/empire /bin/bash`

FROM python:3.12.0-bullseye
FROM python:3.12.1-bullseye

LABEL maintainer="bc-security"
LABEL description="Dockerfile for Empire server and client. https://bc-security.gitbook.io/empire-wiki/quickstart/installation#docker"
Expand Down
2 changes: 2 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* [Starkiller](interfaces/starkiller/README.md)
* [Introduction](interfaces/starkiller/introduction.md)
* [Plugins](plugins/README.md)
* [Getting Started](plugins/getting-started.md)
* [Plugin Development](plugins/plugin-development.md)
* [Hooks and Filters](plugins/hooks-and-filters.md)
* [Bypasses](bypasses.md)
Expand All @@ -39,6 +40,7 @@
* [PowerShell Modules](module-development/powershell-modules.md)
* [Python Modules](module-development/python-modules.md)
* [C# Modules](module-development/c-modules.md)
* [BOF Modules](module-development/bof-modules.md)
* [Agents](agents/README.md)
* [Python](agents/python/README.md)
* [Main Agent Class](agents/python/mainagentclass.md)
Expand Down
40 changes: 40 additions & 0 deletions docs/module-development/bof-modules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# BOF Modules

BOF modules are mostly configured the same as powershell modules.

Where it varies:
* The `script`, `script_path`, and `script_end` fields are not used
* `bof.x86` and `box.x64` refer to the path to the beacon object file for each architecture
* `bof.entry_point` is an optional field for defining the object file entry point
* An `Architecture` field is required


In addition, options add the `format` which breaks them into the following categeories:
```
-i:123 A 32 bit integer (e.g. 123 passed to object file)
-s:12 A 16 bit integer (e.g. 12 passed to object file)
-z:hello An ASCII string (e.g. hello passed to object file)
-Z:hello A string that's converted to wchar (e.g. (wchar_t)hello passed to object file)
-b:aGVsbG8= A base64 encoded binary blob (decoded binary passed to object file)
```

The yaml would use the following format:
```yaml
options:
- name: Architecture
description: Architecture of the beacon_funcs.o to generate with (x64 or x86).
required: true
value: x64
strict: true
suggested_values:
- x64
- x86
- name: Filepath
description: Filepath to search for permissions.
required: true
value: 'C:\\windows\\system32\\cmd.exe'
format: Z
value: 'alex'
```
BOF modules also support the `advanced.custom_generate` method of generating the script.
118 changes: 115 additions & 3 deletions docs/module-development/powershell-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,13 @@ The generate function **should** treat these parameters as read only, to not cau
```python
class Module(object):
@staticmethod
def generate(main_menu, module: PydanticModule, params: Dict, obfuscate: bool = False, obfuscation_command: str = "") -> Tuple[Optiona[str], Optional[str]]:
pass
def generate(
main_menu: MainMenu,
module: EmpireModule,
params: dict,
obfuscate: bool = False,
obfuscation_command: str = "",
):
```

Examples of modules that use this custom generate function:
Expand All @@ -73,12 +78,119 @@ Examples of modules that use this custom generate function:
* [invoke\_assembly](https://github.com/BC-SECURITY/Empire/blob/master/empire/server/modules/powershell/code\_execution/invoke\_assembly.py)
* [seatbelt](https://github.com/BC-SECURITY/Empire/blob/master/empire/server/modules/powershell/situational\_awareness/host/seatbelt.py)

If an error occurs during the execution of the generate function, return the error message using `handle_error_message`, which will ensure that the client receives the error message in the REST response.
#### Error Handling

If an error occurs during the execution of the generate function and it goes unchecked,
the client will receive a 500 error.

There are two Exceptions that can be raised by the generate function:
**ModuleValidationException**: This exception should be raised if the module fails validation. This will return a 400 error to the client with the error message.
**ModuleExecutionException**: This exception should be raised if the module fails execution. This will return a 500 error to the client with the error message.

```python
raise ModuleValidationException("Error Message")
raise ModuleExecutionException("Error Message")
```

##### Deprecated

Previously, it was recommended that the generate function return a tuple of the script and the error.
`handle_error_message` was provided as a helper function to handle this tuple.

This is no longer recommended, but is still supported. Please migrate away from the tuple return type
to raising exceptions. The tuple return type will be removed in a future major release.

#### Functions

`get_module_source` is used pull the script from the yaml file defined in **script\_path**. Once the script has been loaded, it will determine if obfuscation is enabled and obfuscate it.

`finialize_module` will combine the `script` and `script_end` into a single script and then will apply obfuscation, if it is enabled.


#### Decorators

`@auto_get_source` is a decorator that will automatically call `get_module_source` and pass the script to the decorated function.
To use this decorator, the function must have a `script` kwarg and the `script_path` must be set in the yaml config.

```python
@staticmethod
@auto_get_source
def generate(
main_menu: MainMenu,
module: EmpireModule,
params: dict,
obfuscate: bool = False,
obfuscation_command: str = "",
script: str = "",
):
# do stuff
...
# The above is the equivalent of:
@staticmethod
def generate(
main_menu: MainMenu,
module: EmpireModule,
params: dict,
obfuscate: bool = False,
obfuscation_command: str = "",
):
# read in the common module source code
script, err = main_menu.modulesv2.get_module_source(
module_name=module.script_path,
obfuscate=obfuscate,
obfuscate_command=obfuscation_command,
)
if err:
return handle_error_message(err)
# do stuff
...
```

`@auto_finalize` is a decorator that will automatically call `finalize_module` on the returned script from the decorated function.

To use this decorator, the function must not utilize the deprecated tuple return type or the
`handle_error_message` function. First migrate the function to raise exceptions before using this decorator.

```python
@staticmethod
@auto_finalize
def generate(
main_menu: MainMenu,
module: EmpireModule,
params: dict,
obfuscate: bool = False,
obfuscation_command: str = "",
):
# Do stuff
return script, script_end
# The above is the equivalent of:
@staticmethod
def generate(
main_menu: MainMenu,
module: EmpireModule,
params: dict,
obfuscate: bool = False,
obfuscation_command: str = "",
):
# Do stuff
script, script_end = main_menu.modulesv2.finalize_module(
script=script,
script_end=script_end,
obfuscate=obfuscate,
obfuscate_command=obfuscation_command,
)
return script
```



### String Formatting

**option\_format\_string:** This tells Empire how to format all of the options before injecting them into the `script_end`. In most cases, the default option format string will be fine: `-{{ KEY }} "{{ VALUE }}"`.
Expand Down
6 changes: 4 additions & 2 deletions docs/plugins/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Plugins

Plugins are an extension of Empire that allow for custom scripts to be loaded. This allows anyone to easily build or add community projects to extend Empire functionality. Plugins can be accessed from the Empire client or the API as long as the plugin follows the [template example](https://github.com/BC-SECURITY/Empire/blob/master/empire/server/plugins/example.py). A list of Empire Plugins is located here.
Plugins are an extension of Empire that allow for custom scripts to be loaded.
This allows anyone to build or add community projects to extend Empire functionality.
Plugins can be accessed from the Empire client or the API as long as the plugin follows
the [template example](https://github.com/BC-SECURITY/Empire/blob/master/empire/server/plugins/example.py). A list of Empire Plugins is located here.

## Empire Plugins

Expand All @@ -15,4 +18,3 @@ Plugins are an extension of Empire that allow for custom scripts to be loaded. T
| [Nmap-Plugin](https://github.com/BC-SECURITY/Nmap-Plugin) | Nmap-Plugin gives a way to interface directly from Empire to [Nmap](https://nmap.org/) and send commands through [Python3-Nmap](https://github.com/nmmapper/python3-nmap). | [![nmap](https://user-images.githubusercontent.com/20302208/120945236-1feb5f80-c6ed-11eb-9ca3-160c66d4c447.gif)](https://user-images.githubusercontent.com/20302208/120945236-1feb5f80-c6ed-11eb-9ca3-160c66d4c447.gif) | @Cx01N | X |
| [Twilio-Plugin](https://github.com/BC-SECURITY/Twilio-Plugin) | The Twilio Plugin is meant to show the possibilities of the Hooks feature implemented in Empire 4.1. It sends a text message every time an agent connects. | | @Vinnybod | |
| [denylist-plugin](https://github.com/BC-SECURITY/denylist-plugin) | The purpose of this plugin is to block certain IP addresses from connecting to the server. It is to showcase the event-driven nature of the hook system. | | @Vinnybod | |

30 changes: 30 additions & 0 deletions docs/plugins/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Plugins Getting Started

This page will walk you through the process of creating a plugin for Empire using
the hello world plugin as an example. The hello world plugin is an example plugin
that can be found in the `empire/server/plugins/example` directory.

```
empire/server/plugins/example
├── __init__.py
├── example.py
└── plugin.yaml
```

The `plugin.yaml` configuration will likely be expanded on in the future, but for now
it only contains one property: `main`. This is the name of the python file within the
plugin's directory that contains the plugin class.

```yaml
main: example.py
```
The `example.py` file contains the plugin class. The class must be named `Plugin`
and must inherit from `empire.server.common.plugins.BasePlugin`.

```python
class Plugin(BasePlugin):
...
```

To get into the details of the plugin, move onto the [plugin development](./plugin-development.md) page.
Loading

0 comments on commit a75ee49

Please sign in to comment.