Ingredients for Cooking a Backdoor¶
Every program that uses the
covertutils way of implementing communication has the following ingredients. No matter if it is the backdoors Agent (the one running on the compromised host), or the Handler (the one that is used by the pentester/attacker/hoodie wearing guy).
All backdoors designed with
covertutils are made using the parts below:
This class manipulates data from and to the Communication Channel (see below).
When several data transformations are in place, the
Orchestrator objects are the ones that pass them from their minified / encrypted / chunked form to their original, lossless form.
This is done without any interaction from the developer in packet level as in
covertutils there are no packets.
All networking is abstracted, and what is finally traveling in network packets is no concern for
Packing and unpacking is done by the
covertutils.orchestration.orchestrator.Orchestrator.readyMessage() (packing) and
covertutils.orchestration.orchestrator.Orchestrator.depositChunk() (unpacking) methods.
Orchestrator instances are designed to create pairs of 2, in a way that data the first
Orchestrator instance packs to sendable forms are able to be unpacked and read only by the second
Orchestrator instance and vice-versa. This is done with the use of a passphrase to initialize all encryption keys and stream OTPs
Orchestrator object supports a list of streams defined as a python list at instance initialization. That means that Messages are packed against a stream (falling back to a default if not specified) every time the
readyMessage() is used.
It is possible to add and remove streams at runtime with
covertutils.orchestration.orchestrator.Orchestrator.deleteStream() methods. This is highly utilized by staging, as stages always operate in different streams (see Beyond the OS Shell).
To ensure compatibility between two
Orchestrator objects an Identity string is provided for each
Orchestrator object which is generated by computing hashes of its initial settings (including passphrase). Identity strings and compatibility checks for them are provided by the
*Handler classes are used to create both Agents and Handlers. Their name derives from their ability to handle Messages. Messages are received both ways! So a Reverse TCP Agent could consist of a
covertutils.handlers.impl.simpleshell.SimpleShellHandler object to let it communicate with the other side and shell_exec all incoming Messages.
*Handler objects like sockets with callbacks.
*Handler classes are used along with
Orchestrators to provide an interface to the developer for 2 things:
- How the received Messages are used (displayed? - executed? - stored in files?)
- How the Agent or Handler will respond on Messages, and the general Behavior of it.
The API described in Docs @
covertutils.handlers totally abstract the whole raw-data to Message, Stream transformations, setting callbacks that are meaningful to the receiver.
The callbacks run when:
- a Message has arrived, informing about the Message‘s content and the Stream it received it -
- a Chunk has arrived, informing about the Stream that it received it, and if it was the last part of a Message -
- an unrecognized payload has arrived -
At time of writing 2 behaviors have been identified in the wild and modeled. The interrogating one and the bind’ish one.
It is when one of the two sides is periodically querying the other side. This is the behavior of all reverse HTTP/S backdoor Agents.
Yet, it has not been hardcoded for use with Agents only! A handler could be interrogating too. Think of an ICMP backdoor Handler. If the Agent has to transfer a huge response back to the Handler, The Handler has to start an interrogating process for the Agent to respond with payload chunks, until the whole Message gets across. This is the only way to resemble a ping-pong behavior.
That behavior is modeled in the
covertutils.handlers.interrogating.InterrogatingHandler class, and it is used in the Advanced ICMP Bind Shell from the Handler exactly as described above.
This behavior is found when the one side MUST NOT TALK under any circumstance, unless asked by the other side. Most of the time it is just the complementary of the Interrogating behavior. This is the case for Reverse HTTP/S backdoors
We find this behavior typically in HTTP/S reverse Handlers. As HTTP/S reverse Handlers act as (or actually are ) HTTP/S Servers, usually also serving error pages just to be more persuading for their innocence.
The thing is that a presumable HTTP/S Server never sends things to an HTTP Client before getting an HTTP request. So the
covertutils.handlers.responseonly.ResponseOnlyHandler keeps a list of stuff that has to transmit and sends them over only if a request Message arrives.
Both Interrogating and Bind’ish behaviors can use the
covertutils.handlers.basehandler.BaseHandler.sendQueue() method to send Messages over.
Ad Hoc Behavior¶
That is all good but a good ol’ Reverse TCP needs none of them! For such cases the
covertutils.handlers.basehandler.BaseHandler.sendAdHoc() method saves the day. Just spits to the Communication Channel like there is no tomorrow (or IDS to trick).
Both class methods are available in all behaviors (defined in base class) but each one has the sending method that fits the behavior that is trying to simulate. The
covertutils.handlers.basehandler.BaseHandler.preferred_send() always holds the sending method best fit for the
Handler instance used.
A pinch of Communication Channel Creativity¶
Networking isn’t a standard thing when designing a backdoor. This is why it is left out of the way completely.
All Communication is wrapped by
recv functions where the
send() has to get 1 argument (raw data to send) and the
recv() has to be blocking.
to_handler =  to_agent =  #========================================= def handler_send(raw_data) : to_agent.append(raw_data) def handler_recv() : while not to_handler: pass # Has to block when no payloads arrive return to_handler.pop(0) #========================================= def agent_send(raw_data) : to_handler.append(raw_data) def agent_recv() : while not to_agent: pass # If you are brave enough use queues and threads return to_agent.pop(0)
This is perfectly working example of wrapping functions. It is actually really useful for testing stuff.
So those functions can use
requests to post to pastebin or do whatever. The
covertutils package doesn’t care about how you get your bytes to the other side. It just guarantees that the bytes will be fully unrecognizable (see: Totally IDS/IPS evading payloads) to anyone else than the other side.