mythic-cli
binary. To reduce the size of the GitHub clones, this binary is now included as part of the main base docker image, so run sudo make
and the binary will be downloaded and copied into the normal spot.20.10.22
or above (current is 23.0.1
. This is required for the latest docker containers to work properly. A simple sudo apt upgrade
and install should suffice. Also install docker-compose via sudo apt install docker-compose-plugin
vs the docker-compose
script as the script will soon be deprecated according to Docker.ExternalAgent
format is still the same. These next pieces are how you can test updates of your agent locally before copying your agent’s folder back into your normal ExternalAgent format.
Mythic/InstalledServices
folder is on the Mythic server. When you installed a PayloadType via ./mythic-cli install github <url>
, the folder within your github’s Payload_Type
folder is copied to the Mythic/InstalledServices
folder.Mythic/InstalledServices
folder the same as your GitHub’s Payload_Type
folder (or any other folder really - it’s simply serving as a staging ground while you create the new folder structure).agent name
, in Mythic/InstalledServices
agent name
directory into InstalledServices
(yes, the path will look like Mythic/InstalledServices/agentName/agentName
)
Mythic/InstalledServices/agentName
create a main.py
and a Dockerfile
Dockerfile
, copy the contents of your old Dockerfile
and change the FROM
line to FROM itsafeaturemythic/mythic_python_base:latest
main.py
add:
agent name
directory a PyPi package that can be imported, create a __init__.py
file in Mythic/InstalledServices/agentName/agentName
. In the Mythic/InstalledServices/agentName/agentName/Mythic
folder make a __init__.py
file with the following contents (this will loop through all of your command files and import them automatically):
Mythic/InstalledServices/agentName/agentName/mythic/agent_functions
files, we need to replace all mythic_payloadtype_container
with mythic_container
. If you have an import like from agent_functions.execute_pe import PRINTSPOOFER_FILE_ID
which references another command file, update it to from .execute_pe import PRINTSPOOFER_FILE_ID
. If you include a local library at the same level as agent_functions
, you can import it like from [agent name].mythic.[package] import [thing]
rabbitmq_config.json
file at the same level as your main.py
to tell your service where Mythic is located and the rabbitmq password. The configuration options you can supply can be found in the Local Development section.
rabbitmq_config.json
file keys:container_files_path
is no longer used and can be deleted.
username
is no longer used and can be deleted.
password
is now rabbitmq_password.
host
is now rabbitmq_host.
name
is no longer used and can be deleted.
virtual_host
is no longer used and can be deleted.
rabbitmq_config.json
are:rabbitmq_host
- points to the IP where Mythic lives
rabbitmq_password
- the password used to authenticate to rabbitmq
mythic_server_host
- points to the IP where Mythic lives
mythic_server_port
- if you’re using something other than the default (this is NOT the 7443 that you use for the UI)
builder.py
file where you define your Payload Type, you need to add the following:
agent_path
is the path to your general agent structure (typically with the agent_functions
as a sub-folder. The agent_code_path
points to your agent’s actual code.
Something that’s a little different is the agent icons - the agents will sync that over automatically with the rest of their definition (no more having to copy it over manually or get it from an install). What that means though is you either need to supply agent_icon_path
and provide the path to your agent’s svg icon or specify agent_icon_bytes
and provide the raw bytes for your icon.
SendMythicRPCPayloadUpdateBuildStep
RPC call (based on your defined build steps). This will update the UI step-by-step for the operator so they know what’s going on.
You can also set UpdatedFilename
(or updated_filename
for Python) in your build response and adjust the final filename of the payload. This can be helpful if your payload type allows you to build to various outputs (exe, dll, dylib, binary, etc). This allows you to adjust the filename based on that so that when the user clicks “download” in the UI, they get the right file and don’t have to change the filename.
agent_path / browser_scripts / filename.js
OR at the path specified by the name
parameter for the script. So, that means your can either specify the name as test.js
and have it located in your agent_path / browser_scripts / test.js
file or specify a full path as your name.
The browser_script attribute is a single BrowserScript value, not an array. This is because the entire Python back-end is gone, so there’s no more need to supply a script for the old UI and the new UI.
http
profile, both the AESPSK
and the headers
parameters will be passed in as dictionaries.
create_tasking
functions still work just like normal; however, the newer create_go_tasking
function gives you more contextual data and mirrors the data structures from the new Golang container version.
taskData
variable is defined here: https://github.com/MythicMeta/MythicContainerPyPi/blob/main/mythic_container/MythicCommandBase.py#L1068 and provides a lot more context in a well-defined class.
functionName
function as part of your tasking, in your create_tasking
function you need to set the name:
create_go_tasking
function, then you need to do somthing very similar:
process_response
key within your responses
allows you to hook into the associated command’s process_response
function within your Payload Type’s container. The format of this function has changed slightly:
old:
control_socks
. Instead, you’ll use the SendMythicRPCProxyStart
and SendMythicRPCProxyStop
commands as detailed here.
c2 name
, in Mythic/InstalledServices
c2 name
directory into InstalledServices
(yes, the path will look like Mythic/InstalledServices/c2Name/c2Name
)
c2_service.sh
, mythic_service.py
, and rabbitmq_config.json
from your mythic
folder
C2_RPC_Functions.py
Mythic/InstalledServices/c2Name
create a main.py
and a Dockerfile
Dockerfile
, copy the contents of your old Dockerfile
and change the FROM
line to FROM itsafeaturemythic/mythic_python_base:latest
mythic/c2_functions/
folder, your definition file should import mythic_container
instead of mythic_c2_container
(similar to what we did for agent updates).
main.py
add:
server_folder_path
(path to the folder where your server binary and config.json files exist), and server_binary_path
(path to the binary to execute if you’re doing an egress c2 profile and not a p2p profile).
websocket
example here: https://github.com/MythicMeta/ExampleContainers/tree/main/Payload_Type/python_services. You’ll notice that the websocket
is just one of multiple services that the single docker contianer is offering. If you want your container to only offer that one, then you can remove the other folders and adjust your main.py
accordingly.
Dictionary
will be sorted alphabetically - they will NOT maintain the order they were specified in the UI. This is currently a limitation of the Golang Google JSON library.MYTHIC_ADDRESS
environment variable that points to http://mythic_server:17443/agent_message
for C2 Profiles to use for forwarding their messages. With Mythic 3.0+, there are going to be more options for connections outside of a static HTTP endpoint. Therefore, the MYTHIC_ADDRESS
field exists, but there’s additional values for MYTHIC_SERVER_HOST
and MYTHIC_SERVER_PORT
so that we can dynamically use these later on.
translator
in the ExampleContainers (https://github.com/MythicMeta/ExampleContainers/tree/main/Payload_Type/python_services) repository for an example of how to format your new structure. Translation containers boil down to one class definition with a few functions.
One big change from Mythic 2.3 -> 3.0 for Translation Containers is that they now operate over gRPC instead of RabbitMQ. This means that they need to access the gRPC port on the Mythic Server if you intend on running a translation container on a separate host from Mythic itself. This port is configurable in the Mythic/.env
file, but by default it’s 17443. This change to gRPC instead of RabbitMQ for the translation container messages speeds things up and reduces the burden on RabbitMQ for transmitting potentially large messages.
Some additional notes about Translation container message updates: