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:
- a Message has arrived, informing about the Message’s content and the Stream it received it -
covertutils.handlers.basehandler.BaseHandler.onMessage()
- a Chunk has arrived, informing about the Stream that it received it, and if it was the last part of a Message -
covertutils.handlers.basehandler.BaseHandler.onChunk()
- an unrecognized payload has arrived -
covertutils.handlers.basehandler.BaseHandler.onNotRecognised()
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.