Let’s Talk DNS: Designing a DNS Profile for Mythic C2
Some months ago I decided to play with Mythic and to be honest, I’ve had a great experience with it, not only related to the stability of the framework but also the way the code is structured. It’s fairly easy to implement custom profiles, custom agents, custom communication (encryption/decryption) since most of the work is pretty abstracted from all non-related implementation (UI stuff for example). Not only that, but also the possibility to create your agents in any language, while having your C2 designed in python, which has a decent amount of libraries.
These reasons played a big role in moving some of my toolkit to Mythic and also adding more things to it, including a DNS profile. This post will try to describe the whole process of creating a DNS profile for Mythic in a way that it will become a lot easier for anyone to implement this capability in a custom agent.
When designing a DNS profile there is a wide range of issues we need to address. Since DNS uses UDP for communication, it does not provide a way to ensure delivery, nor it provides a way to order the packets.
These things become a lot harder to address when we consider that the packets will arrive out of order most of the time, since multi-threading may be a thing to consider in the agent-side.
Many, many issues…
Considering the mentioned issues, the DNS profile should be able to:
Support for multiple connected implants.
Protection against packet tampering (HMAC check in each packet).
Support for multiple domain configuration.
Message Caching: cache previous message to avoid DNS spikes, since some of the messages are exactly the some in case there are no tasks for the agent.
Recover agent: Mythic has a way to recover agents by their UUID in case the Server goes down. However, the DNS profile does not transmit the UUID in the packet. It only obtains the UUID when assembling all the packets. Thus, it is necessary to create a mechanism to recover agents in case the server goes down.
Fallback state: Supposing a situation the server goes down in the middle of a large command (e.g. register_assembly/execute_assembly), the agent would repeatedly send DNS queries while still receiving a query failure response. This would result in a continuous DNS spike in the network. Therefore, the agent should be able to go in a state where the maximum amount of threads would be decreased, while each packet would be sent with the configured delay of the agent. The fallback state should be active until a successful DNS query is received by the agent.
In this article, we’ve tried to describe all the necessary procedures in order to implement the DNS communication to any custom agents in Mythic. With time, more DNS query types will be implemented with Host Rotation.