Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e33a23a
remove endpoint to execute playbook from file path on server
thorinaboenke Nov 21, 2025
32cef18
remove logger from utils
thorinaboenke Nov 21, 2025
7e072a4
remove cli client
thorinaboenke Nov 21, 2025
9da4e69
remove filepath from remote executor and command
thorinaboenke Nov 21, 2025
d5c2e48
rename remote command type
thorinaboenke Nov 21, 2025
d419e16
remove sending file path from remote command
thorinaboenke Nov 27, 2025
0cac226
remove remote client
thorinaboenke Dec 2, 2025
20f37f9
registe vnc command
thorinaboenke Dec 2, 2025
c32fc52
remove api server
thorinaboenke Dec 2, 2025
a4aa923
import client from new package
thorinaboenke Dec 2, 2025
b74b4ca
update port in docs
thorinaboenke Dec 2, 2025
adeae7e
make Command an annotated union
thorinaboenke Dec 2, 2025
c4c1c4b
comments
thorinaboenke Dec 2, 2025
939d91b
Merge branch 'development' into _api_refactor
thorinaboenke Dec 2, 2025
54187e3
add attackmate-client to pyproject.toml
thorinaboenke Dec 3, 2025
53ed5e3
pre-commit fixes line length
thorinaboenke Dec 3, 2025
22d1f63
update gitignore
thorinaboenke Dec 3, 2025
226fe1c
update pyrpject toml
thorinaboenke Dec 4, 2025
a6db61c
merge development
thorinaboenke Dec 4, 2025
a123e43
bettercap command validator
thorinaboenke Dec 4, 2025
3ac55a8
remove api logging format
thorinaboenke Dec 17, 2025
960da4c
import remote executor in executor init.py
thorinaboenke Dec 17, 2025
1e2f2d8
merge development
thorinaboenke Jan 21, 2026
820ec62
typo
thorinaboenke Jan 21, 2026
e58b379
async refactor
thorinaboenke Jan 22, 2026
9580a9f
use asyncio sleep in Looper
thorinaboenke Jan 23, 2026
b10b85e
refactor base executor tests
thorinaboenke Jan 26, 2026
83f2082
refactor bettercap executor tests
thorinaboenke Jan 26, 2026
3d1368b
refactor browser executor tests
thorinaboenke Jan 26, 2026
508e0a8
refactor command delay tests
thorinaboenke Jan 26, 2026
c6c8f19
refactor json command tests
thorinaboenke Jan 26, 2026
5f6632c
async in Loop executor
thorinaboenke Jan 26, 2026
4c68c0d
refactor loop executor tests
thorinaboenke Jan 26, 2026
b69f106
refactor regex executor tests
thorinaboenke Jan 26, 2026
5daafb8
refactor shell executor tests
thorinaboenke Jan 26, 2026
155dee0
refactor vnc executor tests
thorinaboenke Jan 26, 2026
a339107
fix setvarexecutor tests!
thorinaboenke Jan 26, 2026
b062b74
pyproject
thorinaboenke Feb 11, 2026
462f5dd
fix model_validattor deprecation warning
thorinaboenke Feb 11, 2026
0f60875
config for several remote connections
thorinaboenke Feb 12, 2026
61adc53
add cleanup to remote executor
thorinaboenke Feb 12, 2026
748c6bf
add remote executor test
thorinaboenke Feb 12, 2026
7b95199
cleanup remote executor
thorinaboenke Feb 12, 2026
7082049
debug logs
thorinaboenke Feb 12, 2026
9a78b73
add cleanup to sliver executor, clean up jobs
thorinaboenke Feb 19, 2026
9e2db12
return 0 for background commands
thorinaboenke Feb 19, 2026
f1b50b2
return 0 for background commands
thorinaboenke Feb 19, 2026
2e6c3b2
update uv lock
thorinaboenke Feb 23, 2026
a185d2b
merge development
thorinaboenke Feb 23, 2026
14f95a5
delete jenkins file
thorinaboenke Feb 23, 2026
c4450b5
Merge branch 'development' into _api_refactor
thorinaboenke Feb 23, 2026
8cd2a5a
update pyproject.toml
thorinaboenke Feb 24, 2026
14eba67
pytest-asyncio for tests
thorinaboenke Feb 24, 2026
a7dd374
Merge branch 'development' into _api_refactor
thorinaboenke Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
pip install flake8 pytest pytest-asyncio
pip install -e .
if [ -f test/requirements.txt ]; then pip install -r test/requirements.txt; fi
- name: Install Playwright browser
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,6 @@ cython_debug/
playbooks/
.penpal.yml
.attackmate.yml
attackmate.json
attackmate.log
output.log
4 changes: 3 additions & 1 deletion docs/source/configuration/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ is not used, attackmate will search at the following locations for the config-fi
#. **$HOME/.config/attackmate.yml**
#. **/etc/attackmate.yml**

The optional configuration-file is in yaml-format and is divided into three sections:
The optional configuration-file is in yaml-format and is divided into five sections:

* **cmd_config**: defines settings for all commands
* **msf_config**: connection settings for the msfrpcd
* **bettercap_config**: connection settings for the bettercap rest-api
* **sliver_config**: connection settings for the sliver-api
* **remote_config**: connection settings for the remote attackmate server

The following configuration file is an example for a basic configuration with
sliver and metasploit:
Expand Down Expand Up @@ -51,3 +52,4 @@ For detailed information about the config sections see:
bettercap_config
msf_config
sliver_config
remote_config
63 changes: 63 additions & 0 deletions docs/source/configuration/remote_config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
.. _remote_config:

=============
remote_config
=============

The remote_config section defines connections to remote AttackMate instances. This allows one AttackMate instance to act as a controller, dispatching playbooks or commands to remote nodes.

Like other executors, the configuration uses unique identifiers (names) for each connection. If a command in a playbook does not explicitly specify a connection, the first entry defined in this configuration is used as the default.

.. code-block:: yaml

remote_config:
remote_server:
url: "https://10.0.0.5:5000"
username: admin
password: securepassword
cafile: "/path/to/cert.pem"
another_server:
url: "https://10.0.0.6:5000"
username: user
password: anotherpassword
cafile: "/path/to/another_cert.pem"

.. code-block:: yaml

commands:
# Executed on 'another_server'
- type: remote
connection: another_server
cmd: execute_command
remote_command:
type: shell
cmd: "whoami"

# Executed on 'remote_server' (defaults to first remote_config entry))
- type: remote
cmd: execute_playbook
playbook_yaml_path: path/to/playbook.yml

.. confval:: url

The base URL of the remote AttackMate REST API.

:type: str :required: True

.. confval:: username

The username for authentication with the remote AttackMate instance.

:type: str :required: False

.. confval:: password

The password for authentication with the remote AttackMate instance.

:type: str :required: False

.. confval:: cafile

The path to a CA certificate file used to verify the remote server's SSL certificate. This is highly recommended when using HTTPS.

:type: str :required: False
4 changes: 2 additions & 2 deletions docs/source/developing/baseexecutor.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Example:
from attackmate.result import Result

class CustomExecutor(BaseExecutor):
def _exec_cmd(self, command) -> Result:
async def _exec_cmd(self, command) -> Result:
self.logger.info(f"Executing custom command: {command.cmd}")
return Result(stdout="Execution complete", returncode=0)

Expand Down Expand Up @@ -68,7 +68,7 @@ The following methods can be overridden in custom executors to modify behavior:

.. code-block:: python

def _exec_cmd(self, command: BaseCommand) -> Result:
async def _exec_cmd(self, command: BaseCommand) -> Result:
return Result(None, None)

This is the core execution function and must be implemented in subclasses.
Expand Down
2 changes: 1 addition & 1 deletion docs/source/developing/command.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The new command should be handled by an executor in `src/attackmate/executors``

@executor_factory.register_executor('debug')
class DebugExecutor(BaseExecutor):
def _exec_cmd(self, command: DebugCommand) -> Result:
async def _exec_cmd(self, command: DebugCommand) -> Result:
self.logger.info(f"Executing debug command: {command.cmd}")
return Result(stdout="Debug executed", returncode=0)

Expand Down
50 changes: 50 additions & 0 deletions docs/source/remote.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

Remote Execution
=================
AttackMate can be used for remote command execution.
This section explains hoe the server handles authentication, logging, and AttackMate instances.

Authentication
--------------

The AttackMate API server secures its endpoints using **token-based authentication**.

* **Login Endpoint**: Clients must first authenticate by sending a username and password to the `/login` endpoint (e.g., `https://localhost:8445/login`). This endpoint is defined in `main.py` and uses FastAPI's `OAuth2PasswordRequestForm` for standard form encoding.
* **Token Generation**: Upon successful authentication, the server generates an access token and returns it to the client.
* **Token Storage and Usage**:
* The provided token is received and then stored globally (`CURRENT_TOKEN`) and optionally in an environment variable (`ATTACKMATE_API_TOKEN`).
* For subsequent requests to protected endpoints (like `/command` or `/playbooks`), the client include this token in the `X-Auth-Token` header.
* The `update_token_from_response` function in `client.py` also suggests a mechanism for token renewal, where the server might return a new token in a response.
* **SSL/TLS**: The `main.py` server is configured to run with HTTPS on port `8443`, requiring `key.pem` and `cert.pem` files for SSL/TLS encryption. Clients should specify the path to the server's public certificate.

Logging
-------

The AttackMate API server provides the following logging features:

* **Centralized Logging**: `main.py` initializes several loggers (`attackmate_api`, `playbook`, `output`, `json`) at startup.
* **Instance-Specific Logging**: For remote command and playbook executions, AttackMate implements instance-specific logging.
* The `instance_logging` context manager (from `log_utils.py`) creates dedicated log files for each AttackMate instance based on its `instance_id`.
* These logs are stored in a `attackmate_server_logs` directory (relative to the project root, or a configurable absolute path like `/var/log/attackmate_instances`).
* Each remote command or playbook execution within an instance generates new timestamped log files (e.g., `20240715_123456_my_instance_output.log`).
* This ensures that logs from different concurrent AttackMate instances remain separate.
* **Log Levels**: Log levels can be adjusted for debugging, providing more verbose output when needed.

AttackMate Instances
--------------------

The AttackMate API server manages AttackMate instances to handle multiple execution contexts.

* **Default Instance**: On startup, `main.py` initializes a single default AttackMate instance named `default_context`. This instance handles request to process entire playbooks.
* **Instance Management**:
* The server can create and manage multiple AttackMate instances, each identified by a unique `instance_id`.
* **Instance Lifecycle**:
* Instances are stored in a global dictionary (`state.INSTANCES`).
* When the API server starts (`lifespan` function in `main.py`), it loads a global AttackMate configuration and creates the `default_context` instance.
* When the API server shuts down, it iterates through all active instances, performing cleanup operations like `clean_session_stores()` and `kill_or_wait_processes()` to ensure resources are properly released.
* **Command and Playbook Execution**:
* The API routes (`commands`, `playbooks` routers included in `main.py`) receive client requests.
* These requests specify an `instance_id` (or implicitly use `default_context`).
* The API then dispatches the command or playbook to the designated AttackMate instance for execution. This allows for isolated execution environments, where variables and session data for one instance do not interfere with another.
* **State Management**:
* Each AttackMate instance maintains its own internal state, including a `VariableStore`.
13 changes: 10 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = [
]
description = "AttackMate is an attack orchestration tool that executes full attack-chains based on playbooks."
readme = "README.md"
requires-python = ">=3.7"
requires-python = ">=3.10"
keywords = ["Pentest", "Attack", "Orchestration", "Hacking", "Simulating", "Attackchain"]
license = {text = "GPL-3.0"}
dependencies = [
Expand All @@ -27,15 +27,16 @@ dependencies = [
"uvicorn",
"dotenv",
"passlib",
"python-multipart"
"python-multipart",
"attackmate-client @ git+https://github.com/ait-testbed/attackmate-client.git",
]
dynamic = ["version"]

[project.scripts]
attackmate = "attackmate.__main__:main"

[build-system]
requires = ["setuptools"]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

# [tool.setuptools]
Expand All @@ -55,3 +56,9 @@ version = {attr = "attackmate.metadata.__version__"}

[tool.mypy]
explicit_package_bases = true

[dependency-groups]
dev = [
"pytest-asyncio>=1.3.0",
"vcrpy>=8.1.1",
]
76 changes: 0 additions & 76 deletions remote_rest/README.md

This file was deleted.

Empty file removed remote_rest/__init__.py
Empty file.
103 changes: 0 additions & 103 deletions remote_rest/auth_utils.py

This file was deleted.

Loading