1. Agent Message Format
This page describes how an agent message is formatted
All messages go to the /agent_message
endpoint via the associated C2 Profile docker container. These messages can be:
POST request
message content in body
GET request
message content in FIRST header value
message content in FIRST cookie value
message content in FIRST query parameter
For query parameters, the Base64 content must be URL Safe Encoded - this has different meaning in different languages, but means that for the "unsafe" characters of
+
and/
, they need to be swapped out with-
and_
instead of %encoded. Many languages have a special Base64 Encode/Decode function for this. If you're curious, this is an easy site to check your encoding: https://www.base64url.com/
message content in body
All agent messages have the same general structure, but it's the message inside the structure that varies.
Each message has the following general format shown below. The message is a JSON string, which is then typically encrypted (doesn't have to be though), with a UUID prepended, and then the entire thing base64 encoded:
There are a couple of components to note here in what's called an agentMessage
:
UUID
- This UUID varies based on the phase of the agent (initial checkin, staging, fully staged). This is a 36 character long of the formatb50a5fe8-099d-4611-a2ac-96d93e6ec77b
. Optionally, if your agent is dealing with more of a binary-level specification rather than strings, you can use a 16 byte big-endian value here for the binary representation of the UUID4 string.EncBlob
- This section is encrypted, typically by an AES256 key, but when agents are staging, this could be encrypted with RSA keys or as part of some other custom crypto/staging you're doing as part of your payload type container. .JSON
- This is the actual message that's being sent by the agent to Mythic or from Mythic to an agent. If you're doing your own custom message format and leveraging a translation container, this this format will obviously be different and will match up with your custom version; however, in your translation container you will need to convert back to this format so that Mythic can process the message.action
- This specifies what the rest of the message means. This can be one of the following:staging_rsa
checkin
get_tasking
post_response
translation_staging (you're doing your own staging)
...
- This section varies based on the action that's being performed. The different variations here can be found in Hooking Features , Initial Checkin, and Agent Responsesdelegates
- This section contains messages from other agents that are being passed along. This is how messages from nested peer-to-peer agents can be forwarded out through and egress callback. If your agent isn't forwarding messages on from others (such as in a p2p mesh or as an egress point), then you don't need this section. More info can be found here: Delegates (p2p)
+
- when you see something likeUUID + EncBlob
, that's referring to byte concatenation of the two values. You don't need to do any specific processing or whatnot, just right after the first elements bytes put the second elements bytes
Let's look at a few concrete examples without encryption and already base64 decoded:
Message Format for Custom Agent Messages
If you want to have a completely custom agent message format (different format for JSON, different field names/formatting, a binary or otherwise formatted protocol, etc), then there's only two things you have to do for it to work with Mythic.
Base64 encode the message
The first bytes of the message must be the associated UUID (payload, staging, callback).
Mythic uses these first few bytes to do a lookup in its database to find out everything about the message. Specifically for this case, it looks up if the associated payload type has a translation container, and if so, ships the message off to it first before trying to process it.