Pull the code from the official GitHub repository:
This is made to work with docker and docker compose plugin, so they both need to be installed. If docker is not installed on your ubuntu machine, you can use the ./install_docker_ubuntu.sh
script to install it for you.
If you're running on debian, use the ./install_docker_debian.sh
instead.
You need to have Docker server version 20.10.22
or above (latest version is 23.0.1
) for Mythic and the docker containers to work properly. If you do sudo apt upgrade
and sudo apt install docker-compose-plugin
on a new version of Ubuntu or Debian, then you should be good. You can check your version with sudo docker version
.
Mythic is normally installed on Linux. If you want to install on macOS, you need to use orbstack (not Docker Desktop). This because macOS's Docker Desktop doesn't support host networking, which the C2 containers need to dynamically open up ports.
It's recommended to run Mythic on a VM with at least 2CPU and 4GB Ram.
All configuration is done via the mythic-cli
binary. However, to help with GitHub sizes, the mythic-cli
binary is no longer distributed with the main Mythic repository. Instead, you will need to make the binary via sudo make
from the main Mythic folder. This will create the build container for the mythic-cli, build the binary, and copy it into your main Mythic folder automatically. From there on, you can use the mythic-cli
binary like normal. Make sure you use the mythic-cli
binary from the main Mythic folder.
Mythic configuration is all done via Mythic/.env
, which means for your configuration you can either add/edit values there or add them to your environment.
Mythic/.env doesn't exist by default. You can either let Mythic create it for you when you run sudo ./mythic-cli start
for the first time or you can create it ahead of time with just the variables you want to configure. mythic-cli status
is an easy way to pre-generate the .env
file so you can modify it without it being used by any containers yet.
If you need to run mythic-cli
as root for Docker and you set your environment variables as a user, be sure to run sudo -E ./mythic-cli
so that your environment variables are carried over into your sudo call. The following are the default values that Mythic will generate on first execution of sudo ./mythic-cli start
unless overridden:
A few important notes here:
MYTHIC_SERVER_PORT
will be the port opened on the server where you're running Mythic. The NGINX_PORT
is the one that's opened by Nginx and acts as a reverse proxy to all other services. The NGINX_PORT
is the one you'll connect to for your web user interface and should be the only port you need to expose externally (unless you prefer to SSH port forward your web UI port).
The allowed_ip_blocks
allow you to restrict access to everything within Mythic. This should be set as a series of netblocks with NO host bits set - i.e. 127.0.0.0/16,192.168.10.0/24,10.0.0.0/8
*_BIND_LOCALHOST_ONLY
- these settings determine if the associated container binds the port to 127.0.0.1:port
or 0.0.0.0:port
. These are all set to true (except for the nginx container) by default so that you're not exposing these services externally.
If you want to have a services (agent, c2 profile, etc) on a host other than where the Mythic server is running, then you need to make sure that RABBITMQ_BIND_LOCALHOST_ONLY and MYTHIC_SERVER_BIND_LOCALHOST_ONLY are both set to false
so that your remote services can access Mythic. If you change these, you will need to run sudo ./mythic-cli start
to make sure these changes are leveraged by Docker.
The above configuration does NOT affect the port or SSL information related to your agents or callback information. It's strictly for your operator web UI.
When the mythic_server
container starts for the first time, it goes through an initialization step where it uses the password and username from Mythic/.env
to create the mythic_admin_user
user. Once the database exists, the mythic_server
container no longer uses that value.
The mythic-cli
binary is used to start/stop/configure/install components of Mythic. You can see the help menu at any time with mythic-cli -h
, mythic-cli --help
or mythic-cli help
.
By default, Mythic does not come with any Payload Types (agents) or C2 Profiles. This is for a variety of reasons, but one of the big ones being time/space requirements - all Payload Types and C2 Profiles have their own Docker containers, and as such, collectively they could eat up a lot of space on disk. Additionally, having them split out into separate repositories makes it much easier to keep them updated.
Available Mythic Agents can be found on GitHub at https://github.com/MythicAgents
Available Mythic C2 Profiles can be found on GitHub at https://github.com/MythicC2Profiles
To install a Payload Type or C2 Profile, use the mythic-cli
binary with:
If you have an agent already installed, but want to update it, you can do the same command again. If you supply a -f
at the end, then Mythic will automatically overwrite the current version that's installed, otherwise you'll be prompted for each piece.
You won't be able to create any payloads within Mythic until you have at least one Agent and a matching C2 Profile installed
If you're wanting to enable SIEM-based logging, install the basic_logger
via the mythic cli sudo ./mythic-cli install github https://github.com/MythicC2Profiles/basic_logger
. This profile listens to the emit_log
RabbitMQ queue and allows you to configure how you want to save/modify the logs. By default they just go to stdout, but you can configure it to write out to files or even submit the events to your own SIEM.
If you came here right from the previous section, your Mythic instance should already be up and running. Check out the next section to confirm that's the case. If at any time you wish to stop Mythic, simply run sudo ./mythic-cli stop
and if you want to start it again run sudo ./mythic-cli start
. If Mythic is currently running and you need to make a change, you can run sudo ./mythic-cli restart
again without any issue, that command will automatically stop things and then restart them.
The default username is mythic_admin
, but that user's password is randomly generated when Mythic is started for the first time. You can find this random value in the Mythic/.env
file. Once Mythic has started at least once, this value is no longer needed, so you can edit or remove this entry from the Mythic/.env
file.
Mythic starts with NO C2 Profiles or Agents pre-installed. Due to size issues and the growing number of agents, this isn't feasible. Instead. use the ./mythic-cli install github <url> [branch] [-f]
command to install an agent from a GitHub (or GitLab) repository.
If something seems off, here's a few places to check:
Run sudo ./mythic-cli status
to give a status update on all of the docker containers. They should all be up and running. If one is exited or has only been up for less than 30 seconds, that container might be your issue. All of the Mythic services will also report back a health check which can be useful to determine if a certain container is having issues. The status command gives a lot of information about what services are running, on which ports, and if they're externally accessible or not.
To check the logs of any container, run sudo ./mythic-cli logs [container_name]
. For example, to see the output of mythic_server, run sudo ./mythic-cli logs mythic_server
. This will help track down if the last thing that happened was an error of some kind.
If all of that looks ok, but something still seems off, it's time to check the browser.
First open up the developer tools for your browser and see if there are any errors that might indicate what's wrong. If there's no error though, check the network tab to see if there are any 404 errors.
If that's not the case, make sure you've selected a current operation (more on this in the Quick Usage section). Mythic uses websockets that pull information about your current operation to provide data. If you're not currently in an active operation (indicated at the top of your screen in big letters), then Mythic cannot provide you any data.
If you run into an issue where mythic_nginx
is failing to start, you can look at its logs with sudo ./mythic-cli logs mythic_nginx
. If you see Address family not supported by protocol
, then it likely means that the nginx container is trying to use IPv4 and IPv6, but your host doesn't support one of them. To fix this, you can edit the .env file to adjust the following as necessary:
Then restart the container with sudo ./mythic-cli build mythic_nginx
and it should come up.
Starting with Mythic 3.2.16, Mythic pre-builds its main service containers and hosts them on GitHub. You'll see ghcr.io/itsafeature
in the FROM line in your Dockerfiles instead of the itsafeaturemythic/
line which is hosted on DockerHub. When Mythic gets a new tag
, these images are pre-built, mythic-cli is updated, and the associated push
on GitHub is updated with the new tag version.
When you use the new mythic-cli
to start Mythic, the .env
variable GLOBAL_DOCKER_LATEST
is used to determine which version of the Docker images to use. This variable is written out and saved as part of mythic-cli
itself, so make sure when you do a git pull
that you always run sudo make
to get the latest mythic-cli
as well.
As part of this, there are two new variables for each container:
*_USE_BUILD_CONTEXT
- This variable changes the docker-compose
file to either set a build-context
to read the local Dockerfile when building or to not use the local build context and just set the image to use to be the one hosted on GitHub. In most cases, you're fine to leave this as false
and just use the image hosted on GitHub. If you wanted to use another image version or if you wanted add stuff to the image that gets generated for a container, you can set this to true
and modify the Dockerfile associated with the service.
*_USE_VOLUME
- This variable identifies if the local file system is mounted into the image at run-time or if a custom volume is created and mounted instead. When this is set to true
, then a custom volume is created and mounted into the container at run time so that your local filesystem isn't used. When this is false
, then your local filesystem is mounted like normal. One reason to mount the local file system instead of using a volume is if you wanted to make changes to something on disk and have it reflected in the container. Similarly, you can set this to false
so that your database and downloaded files are all contained within the Mythic
folder. Setting this to true
will mean that volumes are used, so your saved files and database are in Docker's volume directory and not locally within the Mythic folder. It's just something to consider when it comes time to save things off or if you wanted to pull the files from disk.
Mythic is pre-building its containers so that it's faster and easier to get going while still keeping all of the flexibility of Dockerimages. This cuts down on the install/build time of the containers and reduces the general size of the images due to multi-stage Docker builds.
Agents on GitHub can also do this for free. It's pretty simple (all things considered) and provides a lot of flexibility to how you build your containers. You don't need to configure any special GitHub secrets - you just need to create the necessary yaml file as part of a certain directory of your repository so that things are kicked off on push and on tag. One of these changes is an automatic update to your config.json
so that Mythic can also track the version associated with your agent.
Specifically, you need to create the .github/workflows/[name].yml
file so that GitHub will be able to handle your actions. An example from the service_wrapper
payload is shown below:
99% of this example should work for all agents and c2 profiles. Things to change:
RELEASE_BRANCH
- This might need to change depending on if your branch name is master
or main
. (line 39)
Updating the remote_images.service_wrapper
(line 112) to remote_images.[your name]
so that your config.json
is updated appropriately. If you have multiple installs (ex: a payload in the payload_type folder and a c2 profile in the c2_profiles folder), then you should include this action multiple times to add each entry to your remote_images
dictionary.
Updating the files to update (line 121) - after building and pushing your container image, you'll need to update the corresponding files with the new version. Once they're updated, you need to make sure those changes actually get saved and pushed with your tag updated to that new pushed version. This line points to which files to add to the new commit.
There are a few places in this example that use a working_directory
that points to where the Dockerfiles are to use for building and saving changes. Make sure those paths reflect your agent/c2 profiles paths. You can find them in this example if you search for service_wrapper
.
In addition to this GitHub Actions file, you'll need two Dockerfiles - one that's used to pre-build your images, and one that's updated with a FROM ghcr.io/
to point to your newly created image. The common convention used here is to create a .docker
folder with your agent/c2 profile and the full Dockerfile in there (along with any necessary resources). Below is the example build Dockerfile in the .docker/Dockerfile
for the service_wrapper
payload type:
There's a few things to note here:
we're using one of the Mythic DockerHub images as a builder
and using a different, smaller stage (python3.11-slim-bullseye
in this case) that we copy things over to. The main thing that's going to make the images smaller is to build what's needed ahead of time and then move to a smaller image and copy things over. This is easier for C2 Profiles since you can really limit what gets moved to that second stage. This is harder for Agents though because you might still need a lot of toolchains and SDKs installed to build your agent on-demand. The best thing you can do here is to pre-pull any necessary requirements (like nuget packages or golang packages) so that at build-time for a payload you don't have to fetch them and can just build.
Because the service_wrapper
uses the Python mythic-container
PyPi library instead of the Golang library, we need to make sure we have Python 3.11+ and the right PyPi packages installed. On lines 3-4 we're copying in the requirements into our builder
container and generating wheels
from them so that in the second stage, lines 18-19, we copy over those wheels and install those.
Always make sure to test out your docker images to confirm you still have everything needed to build your agent. Some good reference points are any of the .docker/Dockerfile
references in the Mythic
repo, or the apfell
, service_wrapper
, websocket
, or http
versions.
By default, the server will bind to 0.0.0.0
on port 7443
with a self-signed certificate(unless otherwise configured). This IP is an alias meaning that it will be listening on all IPv4 addresses on the machine. Browse to either https://127.0.0.1:7443
if you’re on the same machine that’s running the server, or you can browse to any of the IPv4 addresses on the machine that’s running the server.
Browse to the server with any modern web browser. You will be automatically redirected to the /login
url. This url is protected by allowed_ip_blocks
.
The default username is mythic_admin
and the default password is randomized. The password is stored in Mythic/.env
after first launch, but you can also view it with sudo ./mythic-cli config get MYTHIC_ADMIN_PASSWORD
. You can opt to set this before you initially start if you want (or you can change this later through the UI) by setting that environment variable before staring Mythic for the first time.
Mythic uses JSON Web Tokens (JWT) for authentication. When you use the browser (vs the API on the command line), Mythic stores your access and refresh tokens in a cookie as well as in the local session storage. This should be seamless as long as you leave the server running; however, the history of the refresh tokens is saved in memory. So, if you authenticate in the browser, then restart the server, you’ll have to sign in again.
If you're using Chrome and a self-signed certificate that's default generated by Mythic, you will probably see a warning like this when you try to connect:
This is fine and expected since we're not using a LetsEncrypt or a proper domain certificate. To get around this, simply click somewhere within the window and type thisisunsafe
. Your browser will now Temporarily accept the cert and allow you through.
At some point in the future, your browser will decide to remind you that you're using a self-signed certificate. Mythic cannot actually read this error message due to Chrome's security policies. When this happens, simply refresh your page. You'll be brought back to the same big warning page as the image above and you can type thisisunsafe
again to continue your operations.
Mythic uses docker containers to logically separate different components and functions. There are two main categories:
Mythic's main core. This consists of docker containers stood up with docker-compose:
mythic_server - An GoLang gin webserver instance
mythic_postgres - An instance of a postgresql database
mythic_rabbitmq - An instance of a rabbitmq container for message passing between containers
mythic_nginx - A instance of a reverse Nginx proxy
mythic_graphql - An instance of a Hasura GraphQL server
mythic_jupyter - An instance of a Jupyter notebook
mythic_documentation - An instance of a Hugo webserver for localized documentation
Installed Services
Any folder in Mythic/InstalledServices
will be treated like a docker container (payload types, c2 profiles, webhooks, loggers, translation containers, etc)
To stop a specific container, run sudo ./mythic-cli stop {container name}
.
If you want to reset all of the data in the database, use sudo ./mythic-cli database reset
.
If you want to start/restart any specific payload type container, you can do sudo ./mythic-cli start {payload_type_name}
and just that container will start/restart. If you want to start multiple, just do spaces between them: sudo ./mythic-cli start {container 1} {container 2}
.
Mythic's C2 containers share the networking with the host it's on. This allows C2 Containers to not worry about exposing specific ports ahead of time for each container since they can be dynamically set by users. However, this does mean that Mythic needs to run as root
if any ports under 1024 need to be used.
All of Mythic's containers share a single docker-compose file. When you install an agent or C2 Profile this docker-compose file will automatically be updated. However, you can always add/remove from this file via mythic-cli
and list out what's registered in the docker-compose file vs what you have available on your system:
This makes it easy to track what's available to you and what you're currently using.
Operators connect via a browser to the main Mythic server, a GoLang gin
web server. This main Mythic server connects to a PostgreSQL database where information about the operations lives. Each of these are in their own docker containers. When Mythic needs to talk to any payload type container or c2 profile container, it does so via RabbitMQ, which is in its own docker container as well.
When an agent calls back, it connects through these c2 profile containers which have the job of transforming whatever the c2 profile specific language/style is back into the normal RESTful API calls that the Mythic server needs.
How to install Mythic and agents in an offline environment
This guide will assume you can install Mythic on a box that has Internet access and then migrate to your offline testing/development environment.
Install Mythic following the normal installation
With Mythic running, install any other agents or profiles you might need/want.
3. Export your docker containers. Make sure you also save the tags.
4. Download donut from pypi. (this is apollo specific, so there might be others depending on your agent)
Download Apollo dependencies (apollo specifically installs these dynamically within the Docker container at build-time, so pre-fetch these)
5. Tar Mythic directoy.
6. Push mythic_images.tar
, mythic_tags
, and mythic.tar.gz
to your offline box.
7. Import docker images and restore tags.
8. Extract Mythic directory.
9. Update Apollo's Dockerfile (at the time of use, it might not be 0.1.1 anymore, check #current-payloadtype-versions the latest). This is apollo specific, so you might need to copy in pieces for other agents/c2 profiles depending on what components they dynamically try to install.
10. Start Mythic
Normally, Mythic containers will try to re-build every time you bring them down and back up. This might not be great for an offline environment. The configuration variable, REBUILD_ON_START
, can be set to false
to tell Mythic that the containers should specifically NOT be rebuilt when restarted.
In the Mythic UI, you can click the hamburger icon (three horizontal lines) in the top left to see the current Server version and UI version.
There are three scenarios to updating Mythic: updates to the patch version (1.4.1 to 1.4.2), updates to the minor (1.4.1 to 1.5), or major version (1.4 to 2.0).
In all updates, after a git pull
you should run make
to get the latest mythic-cli
binary.
This is when you're on version 1.2 for example and want to pull in new updates (but not a new minor version like 1.3 or 1.4). In this case, the database schema should not have changed.
Pull in the latest code for your version (if you're still on the current version, this should be as easy as a git pull
)
Make a new mythic-cli binary with sudo make
Restart Mythic to pull in the latest code changes into the docker containers with sudo ./mythic-cli start
This is when you're on version 1.2 for example and want to upgrade to version 1.3 or 2.1 for example. In this case, the database schema has changed.
Starting with Mythic 3.1, we now have database migrations within PostgreSQL. You should be fine to git pull and rebuild everything. It's important that you rebuild so that server changes are pulled in for the various services that updated. This means that if you're on Mythic 3.0.0-rc* and want to upgrade to Mythic 3.1.0, you'll automatically get database migrations to help with this.
Note: I always highly recommend backing everything up if you plan to update a production system. Just in case something happens, you'll be able to revert.
You will have some down time while this happens (the containers need to rebuild and start back up), so make sure whatever you're doing can handle a few seconds to a few minutes of down time.
Pull in the latest code for your version (if you're still on the current version, this should be as easy as a git pull
)
Make a new mythic-cli binary with sudo make
Restart Mythic to pull in the latest code changes into the docker containers with sudo ./mythic-cli start
. If you have in your .env
to not rebuild on start, then you will need to change that first.
Since Mythic now has all of the C2 Profiles and Payload Types split out into different GitHub Organizations (https://github.com/MythicAgents and https://github.com/MythicC2Profiles), you might need to update those projects as well.
Agents and C2 Profiles are hosted in their own repositories, and as such, might have a different update schedule than the main Mythic repo itself. So, you might run into a scenario where you update Mythic, but now the current Agent/C2Profiles services are no longer supported.
You'll know if they're no longer supported because when the services check in, they'll report their current version number. Mythic has a range of supported version numbers for Agents, C2 Profiles, Translation services, and even scripting. If something checks in that isn't in the supported range, you'll get a warning notification in the UI about it.
To update these (assuming that the owner/maintainer of that Agent/C2 profile has already done the updates), simply stop the services (sudo ./mythic-cli stop agentname
or sudo ./mythic-cli stop profileName
) and run the install command again. The install command should automatically determine that a previous version exists, remove it, and copy in the new components. Then you just need to either start those individual services, or restart mythic overall.
Deleting Database
If you want to wipe the database and upgrade, the following steps will help:
Reset the database with sudo ./mythic-cli database reset
Make sure Mythic is stopped, sudo ./mythic-cli stop
Purge all of your containers, sudo docker system prune -a
Pull in the version you want to upgrade to (if you're wanting to upgrade to the latest, it's as easy as git pull
)
Make a new mythic-cli binary with sudo make
.
Delete your Mythic/.env
file - this file contains all of the per-install generated environment variables. There might be new environment variables leveraged by the updated Mythic, so be sure to delete this file and a new one will be automatically generated for you.
Restart Mythic to pull in the latest code changes into the docker containers with sudo ./mythic-cli start