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:

500gr - Orchestrator

Docs @ covertutils.orchestration.orchestrator.Orchestrator

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 covertutils classes.

Message Packing

Packing and unpacking is done by the covertutils.orchestration.orchestrator.Orchestrator.readyMessage() (packing) and covertutils.orchestration.orchestrator.Orchestrator.depositChunk() (unpacking) methods.

The 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

Streams

Every 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.addStream() and covertutils.orchestration.orchestrator.Orchestrator.deleteStream() methods. This is highly utilized by staging, as stages always operate in different streams (see Beyond the OS Shell).

Identities

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 covertutils.orchestration.orchestrator.Orchestrator.checkIdentity() and covertutils.orchestration.orchestrator.Orchestrator.getIdentity() methods.

750gr - Handler

Docs @ covertutils.handlers (enlightening)

Warning

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.

Note

Think of *Handler objects like sockets with callbacks.

The *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.

Messages

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:

Behaviors

At time of writing 2 behaviors have been identified in the wild and modeled. The interrogating one and the bind’ish one.

Interrogating

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.

Bind’ish

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 send() and 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.