Using AttackMate in a Python Script
AttackMate can be embedded in Python scripts for automation and custom attack scenarios. Commands are created programmatically, dispatched one at a time, or run as a full playbook.
Note
This feature is under development and the API may change. Bug reports are welcome.
Installation
Install AttackMate with uv or pip before importing it:
uv add attackmate
# or
pip install attackmate
Quick Start
AttackMate.run_command is a coroutine, so all usage must be inside an async context:
import asyncio
from attackmate.attackmate import AttackMate
from attackmate.command import Command
async def main():
attackmate = AttackMate()
command = Command.create(type="shell", cmd="whoami")
result = await attackmate.run_command(command)
print(result)
asyncio.run(main())
API Reference
AttackMate
class attackmate.attackmate.AttackMate(
playbook=None,
config=None,
varstore=None,
is_api_instance=False
)
The central orchestration class. Instantiate it once per script; executors are created lazily on first use and reused across calls.
Constructor parameters
Parameter |
Type |
Description |
|---|---|---|
|
|
A parsed |
|
|
Tool configuration (Metasploit, Sliver, etc.). Defaults to safe defaults (see Config). |
|
|
Initial variables as a plain dictionary, e.g. |
|
|
Set to |
Methods
await attackmate.run_command(command) -> ResultExecute a single command and return its
Result.sftpcommands are internally routed to thesshexecutor. ReturnsResult(None, None)if no executor is registered for the type.Commands running in background mode return
Result('Command started in background', 0)immediately.await attackmate.main() -> intExecute all commands in the playbook, then clean up all open sessions and background processes. Handles
KeyboardInterruptgracefully. Returns0on completion.await attackmate.clean_session_stores()Tear down all open sessions (Metasploit, SSH, VNC, Sliver, Remote) without running the playbook. Call this for manual cleanup after using
run_command.
Command
class attackmate.command.Command
Factory interface for creating command instances. Do not instantiate directly; use the static factory method.
Command.create(type, cmd=None, **kwargs)Look up the registered command class for
type(and optionallycmd), then instantiate it with the remaining keyword arguments.- param type:
Command type string. See Available Command Types below.
- param cmd:
The command string passed to the executor (required for most commands). For
sliverandsliver-session,cmdalso selects the sub-command class.- param kwargs:
Additional fields defined on the command schema (e.g.
seconds,varstore,background).- raises ValueError:
If no class is registered for
type/cmd.
Available Command Types
Pass the string below as the type argument to Command.create().
Type string |
Description |
|---|---|
|
Execute a local shell command. |
|
Execute a command over SSH. |
|
Upload or download files over SFTP (routed to the SSH executor). |
|
Pause execution for a number of seconds ( |
|
Print a value or variable to the log without side effects. |
|
Set a variable in the variable store ( |
|
Match a regex against a previous result and capture groups. |
|
Parse a JSON string from a previous result and extract a value. |
|
Load and execute commands from another playbook file. |
|
Repeat a nested list of commands until a condition is met. |
|
Create a temporary file or directory. |
|
Execute commands as the parent/owning process. |
|
Start a local HTTP server to serve files. |
|
Send an HTTP request and capture the response. |
|
Automate a browser action via Playwright. |
|
Interact with a VNC session. |
|
Delegate command execution to a remote AttackMate instance. |
|
Run a Metasploit module. |
|
Run a command inside an active Metasploit session. |
|
Generate a Metasploit payload. |
|
Manage a Sliver C2 server ( |
|
Run a command inside a Sliver session ( |
All command types also accept the base fields inherited from BaseCommand:
Field |
Type |
Description |
|---|---|---|
|
|
Run the command in the background. Defaults to |
|
|
Kill a background process when the playbook ends. Defaults to |
|
|
Shell condition; command is skipped if this returns non-zero. |
|
|
Shell condition; execution aborts if this returns zero. |
|
|
Shell condition; execution aborts if this returns non-zero. |
|
|
Shell condition; re-run the command while this returns zero. |
|
|
Shell condition; re-run the command while this returns non-zero. |
|
|
Maximum loop iterations. Defaults to |
|
|
Abort the playbook if this command fails. Defaults to |
|
|
Variable name to store the command’s |
Config
class attackmate.schemas.config.Config
Top-level configuration object. All fields have safe defaults, so an empty
Config() is valid for scripts that do not use Metasploit or Sliver.
Field |
Type |
Description |
|---|---|---|
|
|
Global command execution settings. See below. |
|
|
Metasploit RPC connection settings. See below. |
|
|
Sliver C2 connection settings. See below. |
|
|
Named Bettercap instances. Keys are referenced by |
|
|
Named remote AttackMate instances. |
CommandConfig
Field |
Type |
Description |
|---|---|---|
|
|
Seconds to wait between loop iterations. Defaults to |
|
|
Seconds to wait before each command (excluding |
MsfConfig
Field |
Type |
Description |
|---|---|---|
|
|
Metasploit RPC password. |
|
|
Use SSL for the RPC connection. Defaults to |
|
|
Metasploit RPC port. Defaults to |
|
|
Metasploit server address. Defaults to |
|
|
Metasploit RPC URI. Defaults to |
SliverConfig
Field |
Type |
Description |
|---|---|---|
|
|
Path to the Sliver client configuration file. |
BettercapConfig / RemoteConfig
Field |
Type |
Description |
|---|---|---|
|
|
Base URL of the service. |
|
|
Authentication username. |
|
|
Authentication password. |
|
|
Path to a CA certificate file for TLS verification. |
Result
class attackmate.result.Result(stdout, returncode)
Returned by run_command.
Attribute |
Type |
Description |
|---|---|---|
|
|
The standard output of the command. |
|
|
|
Note
Commands running in background mode return
Result('Command started in background', 0) immediately.
VariableStore
class attackmate.variablestore.VariableStore
Stores and resolves $variable references. When you pass a plain dictionary
to AttackMate(varstore=...) it is loaded into a VariableStore automatically,
so direct use of this class is optional. Access it as attackmate.varstore to
read or update variables at runtime.
Methods
store.set_variable(variable, value)Store a scalar string or a list. The
$prefix invariableis stripped automatically. Integers are coerced tostr.store.get_variable(variable) -> str | list[str]Retrieve a variable by name (without
$prefix). RaisesVariableNotFoundif the variable does not exist.store.substitute_str(template_str, blank=False) -> strReplace all
$variableand$list[n]references intemplate_str. Ifblank=True, unresolved references are replaced with''.store.from_dict(variables)Bulk-load variables from a dictionary.
store.replace_with_prefixed_env_vars()Override stored variables with matching
ATTACKMATE_<name>environment variables. Called automatically duringAttackMate.__init__.
Playbook
class attackmate.schemas.playbook.Playbook(commands, vars=None)
A Pydantic model representing a full playbook. Use it when you want to execute
a sequence of pre-built commands via AttackMate.main(), or when loading
from a YAML file (see Running a Playbook from a YAML File).
Field |
Type |
Description |
|---|---|---|
|
|
Ordered list of commands to execute. |
|
|
Initial variables for the variable store. |
Usage Examples
Running a Single Command
import asyncio
from attackmate.attackmate import AttackMate
from attackmate.command import Command
from attackmate.schemas.config import Config
from attackmate.logging_setup import initialize_logger
async def main():
initialize_logger(debug=False, append_logs=False)
config = Config(
msf_config={"password": "your_password", "ssl": True, "port": 55553},
cmd_config={"loop_sleep": 10},
)
varstore = {"HOST": "10.0.0.1"}
attackmate = AttackMate(config=config, varstore=varstore, is_api_instance=True)
command = Command.create(type="shell", cmd="echo $HOST")
result = await attackmate.run_command(command)
print("Output:", result.stdout)
print("Return code:", result.returncode)
await attackmate.clean_session_stores()
asyncio.run(main())
Running Multiple Commands
import asyncio
from attackmate.attackmate import AttackMate
from attackmate.command import Command
async def main():
am = AttackMate(is_api_instance=True)
cmd1 = Command.create(type="sleep", cmd="sleep", seconds="1")
cmd2 = Command.create(type="debug", cmd="hello world")
cmd3 = Command.create(type="shell", cmd="id", save="RESULT")
cmd4 = Command.create(type="debug", cmd="$RESULT")
for cmd in [cmd1, cmd2, cmd3, cmd4]:
result = await am.run_command(cmd)
if result.returncode != 0:
print(f"Command failed: {result.stdout}")
break
await am.clean_session_stores()
asyncio.run(main())
Running a Playbook from a YAML File
Use parse_playbook and parse_config from attackmate.playbook_parser
to load a playbook file and optional config file, then pass them to
AttackMate.main:
import asyncio
import logging
from attackmate.attackmate import AttackMate
from attackmate.playbook_parser import parse_playbook, parse_config
from attackmate.logging_setup import initialize_logger
async def main():
logger = initialize_logger(debug=False, append_logs=False)
config = parse_config(None, logger) # reads ~/.config/attackmate.yml
playbook = parse_playbook("my_playbook.yml", logger)
am = AttackMate(playbook=playbook, config=config)
await am.main()
asyncio.run(main())
Updating Variables at Runtime
Access attackmate.varstore directly to read or write variables between
commands:
import asyncio
from attackmate.attackmate import AttackMate
from attackmate.command import Command
async def main():
am = AttackMate(varstore={"TARGET": "192.168.1.1"})
am.varstore.set_variable("PORT", "8080")
result = await am.run_command(
Command.create(type="shell", cmd="curl http://$TARGET:$PORT")
)
print(result.stdout)
host = am.varstore.get_variable("TARGET")
print("Target was:", host)
asyncio.run(main())
Checking Results
result = await am.run_command(command)
if result.returncode == 0:
print("Success:", result.stdout)
else:
print("Failed with code:", result.returncode)
Environment Variable Overrides
Any variable in the store can be overridden at runtime by setting an environment
variable with the ATTACKMATE_ prefix:
export ATTACKMATE_HOST=10.0.0.2
This overrides the variable HOST regardless of the value set via varstore
or the playbook vars section. Overrides are applied automatically during
AttackMate.__init__.