This section describes new Payload Types
docker-compose
file that stands up a bunch of microservices. These services expose various pieces of functionality like a database (PostgreSQL
), the web UI (React Web UI
), internal documentation (Hugo Documentation
), and a way for the various services to communicate with each other (RabbitMQ
). Don’t worry though, you don’t worry about 99% of this.
Mythic by itself doesn’t have any agents or command-and-control profiles - these all are their own Docker containers that connect up via RabbitMQ
and gRPC
. This is what you’re going to create - a separate container that connects in (the far right hand side set of containers in the above diagram).
make
to generate the mythic-cli
binary, and then run sudo ./mythic-cli start
, you are creating a docker-compose
file automatically that references a bunch of Dockerfile
in the various folders within the Mythic
folder. These folders within Mythic
are generally self-explanatory for their purpose, such as postgres-docker
, rabbitmq-docker
, mythic-docker
, and MythicReactUI
.
When you use the mythic-cli
to install an agent or c2 profile, these all go in the Mythic/InstalledServices
folder. This makes it super easy to see what you have installed.
Throughout development you’ll have a choice - do development remotely from the Mythic server and hook in manually, or do development locally on the Mythic server. After all, everything boils down to code that connects to RabbitMQ
and gRPC
- Mythic doesn’t really know if the connection is locally from Docker or remotely from somewhere else.
Payload_Type
folder, there are two folders - one for GoLang and one for Python depending on which language you prefer to code your agent definitions in (this has nothing to do with the language of your agent itself, it’s simply the language to define commands and parameters). We’re going to go step-by-step and see what happens when you install something via mythic-cli
, but doing it manually.
Mythic/InstalledServices
folder. When you normally install via mythic-cli
, it clones down your repository and does the same thing - it copies what’s in that repository’s Payload_Type
and C2_Profiles
folders into the Mythic/InstalledServices
folder.
Mythic/InstalledServices
folder, we need to let the docker-compose
file know that it’s there. Assuming you copied over python_services
, you then need to run sudo ./mythic-cli add python_services
. This adds that python_services
folder to the docker-compose
. This is automatically done normally as part of the install process.
As part of updating docker-compose
, this process adds a bunch of environment variables to what will be the new container.
docker-compose
knows about the new service, we need to build the image that will be used to make the agent’s container. We can use sudo ./mythic-cli build python_services
. This tells docker
to look in the Mythic/InstalledServices/python_services
folder for a Dockerfile
and use it to build a new image called python_services
. As part of this, Mythic will automatically then use that new image to create a container and run it. If it doesn’t, then you can create and start the container with sudo ./mythic-cli start python_services
.
Again, all of this happens automatically as part the normal installation process when you use sudo ./mythic-cli install
. We’re doing this step-by-step though so you can see what happens.
sudo ./mythic-cli logs python_services
(this is a wrapper around sudo docker logs python_services
and truncates to the latest 500 lines).
mythic-cli
. If you don’t want to install via mythic-cli
then you can do these steps manually like we did here.
python_services
folder.
Dockerfile
so that docker-compose
can build your image and start the container. You can use anything as your base image, but Mythic provides a few to help you get started with some various environments:
itsafeaturemythic/mythic_go_base
has GoLang 1.21 installeditsafeaturemythic/mythic_go_dotnet
has GoLang 1.21 and .NETitsafeaturemythic/mythic_go_macos
has GoLang 1.21 and the macOS SDKitsafeaturemythic/mythic_python_base
has Python 3.11 and the mythic_container
pypi packageitsafeaturemythic/mythic_python_go
has Python 3.11, the mythic_container
pypi package, and GoLang v1.21itsafeaturemythic/mythic_python_macos
has Python 3.11, the mythic_container
pypi package, and the macOS SDKDockerfile
off with one of the above images:
mythic_container
PyPi versions can be found here: #current-payloadtype-versions. The mythic_python_*
containers will always have the latest PyPi
version installed if you’re using the :latest
version.
If you’re curious what else goes into these containers, look in the docker-templates
folder within the Mythic repository.
Mythic/InstalledServices/[agent name]
folder is mapped to /Mythic
in the docker container. Editing the files on disk results in the edits appearing in the docker container and visa versa.Dockerfile
you will then need to do whatever is needed to kick off your main program that imports either the MythicContainer PyPi package or the MythicContainer GoLang package. As some examples, here’s what you can do for Python and GoLang:
Mythic/InstalledServices/[agent name]/main.py
< if you plan on using Python as your definition language, this main.py
file is what will get executed by Python 3.11 assuming you use the Dockerfile shown below. If you want a different structure, just change the CMD
line to execute whatever it is you want.main.py
file should import any other folders/files needed to define your agent/commands and import the mythic_container
PyPi package.Any changes you make to your Python code is automatically reflected within the container. Simply do sudo ./mythic-cli start [agent name]
to restart the container and have python reprocess your files.If you want to do local testing without docker
, then you can add a rabbitmq_config.json
in the root of your directory (i.e. [agent name]/rabbitmq_config.json
) that defines the environment parameters that help the container connect to Mythic:rabbitmq_password
is shared over to your agent as well. By default, this is a randomized value stored in the Mythic/.env
file and shared across containers, but you will need to manually share this over with your agent either via an environment variable (MYTHIC_RABBITMQ_PASSWORD
) or by editing the rabbitmq_password
field in your rabbitmq_config.json file. You also need to make sure that the MYTHIC_RABBITMQ_LISTEN_LOCALHOST_ONLY
is set to false
and restart Mythic to make sure the RabbitMQ
port isn’t bound exclusively to 127.0.0.1.Mythic/InstalledServices
is what’s used to create the docker
image and container names. It doesn’t necessarily have to be the same as the name of your agent / c2 profile (although that helps).
mythic-cli
to control and install your agent, then your agent’s name can’t have any capital letters in it. Only lowercase, numbers, and _. It’s a silly limitation by Docker, but it’s what we’re working with.python_services
folder this would mean deleting the mywebhook
, translator
, and websocket
folders. For the go_services
folder, this would mean deleting the http
, my_logger
, my_webhooks
, no_actual_translation
folders. For both cases, this will result in removing some imports at the top of the remaining main.py
and main.go
files.
python_services
folder, we’ll update the basic_python_agent/agent_functions/builder.py
file. This file can technically be anywhere that main.py
can reach and import, but for convenience it’s in a folder, agent_functions
along with all of the command definitions for the agent. Below is an example from that builder that defines the agent:mythic-cli
, the repo/folder needs to be in a common format. This format just makes it easier for mythic-cli
to add things to the right places. This is based on the External Agent format here (https://github.com/MythicMeta/Mythic_External_Agent). If you’re creating a new payload type, then add your entire folder into the Payload_Type
folder. Similarly, when you get around to making documentation for your agent, you can add it to the documentation folder. If there’s things you don’t want to include, then in the config.json
file you can mark specific sections to exclude.
@its_a_feature_
on twitter or @its_a_feature_
in the Bloodhound slack to get your agent added to the agents list here (https://github.com/MythicMeta/overview/blob/main/agent_repos.txt). You could also make a PR to that file if you wanted too.
Having your agent hosted on the https://github.com/MythicAgents
organization means that it’s easier for people to find your agent and we can collect stats on its popularity. For an example of what this means, check out the overview page and see the biweekly clone stats as well as the green chart icon for a historic list of view/clones of the repo.
If you don’t want to have your agent hosted on the MythicAgents organization, but still want to make it available on that site, that’s fine too. Just let me know or update the PR for that file appropriately.
agent_capabilities.json
file in the root of your repository. This is just a json
file that gets ingested at midnight every day and used to update that matrix. The format is as follows:
The os
key provides all the operating systems your agent supports. These are the things that would be available after installing your agent for the user to select when building a payload. The languages
key identifies what languages your agent supports (typically only one, but could be multiple). The features
section identifies which features your agent supports. For the mythic
sub-key, the options are at the bottom of the matrix page, along with their descriptions and links to documentation for if you want to implement that feature in your agent. The custom
sub-key is just additional features that your agent supports that you want to call out. The payload_output
key identifies which output formats your agent supports as well as the architectures
key identifying which architectures your agent can be built for. The c2
key identifies which C2 Profiles your agent supports and the supported_wrappers
key identifies which wrapper
payloads your agent supports. As you might expect, the mythic_version
is which Mythic version your agent supports and the agent_version
is the current agent version in use.