def sendSentinel(self): """ State 1: Send sentinel Cookie : SESSSIONID=HandshakeID; ID=Tunnel_Tag HandshakeID = Sentinel+Nonce_Client """ self.rc4_handshake_c2d = RC4.RC4(self.session_key) self.rc4_handshake_d2c = RC4.RC4(self.session_key) self.rc4_tunnel = RC4.RC4(self.session_key) # Filler text # plain_text = const.HTTPU_CLIENTHELLO auth_plain_text = '%s%s%s' % (self.encoder.digest(plain_text), const.HTTPU_HASHSEP, plain_text) cipher_text = self.rc4_handshake_c2d.update(auth_plain_text) # HTTP Request # req = http_util.create_http_req(self, cipher_text, self.handshake_ID, self.tunnel_tag.encode("hex"), self.host_name) self.transport.write(req) # New state # self.state = const.STATE_3_UNI
def send_cipher_req(self, plain_text): """ Create request containing encrypted, integrity checked data and send request on to decoy host """ plain_text = str(self.sent_count) + ":" + plain_text auth_plain_text = '%s%s%s' % (self.encoder.digest(plain_text), const.HTTPU_HASHSEP, plain_text) url_padding = cb_random.gen_rand_bytes(self, const.URL_PADDING_BYTE_LEN) cipher_text = self.rc4_tunnel.update(auth_plain_text) + url_padding req = http_util.create_http_req(self, cipher_text, self.handshake_ID, self.tunnel_tag.encode("hex"), self.host_name) if self.state != const.STATE_0_UNI: self.sent_count += 1 # Send request on to decoy host # self.transport.write(req)
def dataReceived(self, data): """ State 5.5: Ready A. URL : SeqNum_C2D + B. HMAC_Client( R2 ) + C. E_Client( R2 ) D. Cookie : SESSSIONID=Decoupled_ID R2 = Salt_3 + SeqNum_C2D + Decoupled_ID + CovertData Sending covert data from client in http request """ # A. SeqNum_C2D # self.dst_p.seqNum_C2D_Counter = self.dst_p.seqNum_C2D_Counter + 1 s = ( self.dst_p.seqNum_C2D_Rand + str( self.dst_p.seqNum_C2D_Counter ) ) seqNum_C2D = hmac.new( s, self.dst_p.client_hash, hashlib.sha256 ).digest() # B. HMAC_Client( R2 ) # salt_3 = cb_random.gen_rand_bytes(self, const.SALT_BYTE_LEN) text = ( salt_3 + seqNum_C2D + self.dst_p.decoupled_ID + data ) auth_text = hmac.new( text, self.dst_p.client_hash, hashlib.sha256 ).digest() # C. E_Client( R2 ) # enc_text = security_util.encrypt_text(self, text, self.dst_p.client_key, True, False, False) # D. SESSSIONID=Decoupled_ID # final_text = seqNum_C2D + auth_text + enc_text req = http_util.create_http_req(self, final_text, self.dst_p.decoupled_ID, self.dst_p.tunnel_tag.encode("hex"), self.host_name) # Send request on to decoy host # self.dst_p.transport.write(req)
def connectionMade(self): """ State 0: Request tunnel type Cookie : SESSSIONID=HandshakeID; ID=Tunnel_Tag HandshakeID = Sentinel+Nonce_Client """ # Sentinel # s = const.SENTINEL_DEADBEEF if use_crypto == True: s = self.sentinel_hex[0:const.SENTINEL_HEX_LEN] # Nonce_Client # self.nonce_client = cb_random.gen_rand_bytes( self, const.NONCE_CLIENT_BYTE_LEN) # Handshake_ID # self.handshake_ID = s + self.nonce_client.encode("hex") # Tunnel Tag # self.tunnel_tag = hmac.new( const.HTTP_UNI_TUNNEL + self.nonce_client.encode("hex"), self.sentinel_hex[const.SENTINEL_HEX_LEN:], hashlib.sha256).digest() # Filler text # plain_text = const.HTTPU_CLIENTHELLO auth_plain_text = '%s%s%s' % (self.encoder.digest(plain_text), const.HTTPU_HASHSEP, plain_text) cipher_text = auth_plain_text # HTTP Request # req = http_util.create_http_req(self, cipher_text, self.handshake_ID, self.tunnel_tag.encode("hex"), self.host_name) self.transport.write(req) # New state # self.state = const.STATE_1_UNI
def sendSentinel(self): """ State 1: Send sentinel Cookie : SESSSIONID=HandshakeID; ID=Tunnel_Tag HandshakeID = Sentinel+Nonce_Client """ # HTTP Request # req = http_util.create_http_req(self, '', self.handshake_ID, self.tunnel_tag.encode("hex"), self.host_name) self.transport.write(req) # New state # self.state = const.STATE_3
def connectionMade(self): """ State 0: Request tunnel type Cookie : SESSSIONID=HandshakeID; ID=Tunnel_Tag HandshakeID = Sentinel+Nonce_Client """ # Sentinel # s = const.SENTINEL_DEADBEEF if use_crypto == True: s = self.sentinel_hex[0:const.SENTINEL_HEX_LEN] # Nonce_Client # self.nonce_client = cb_random.gen_rand_bytes(self, const.NONCE_CLIENT_BYTE_LEN) # Handshake_ID # self.handshake_ID = ( s + self.nonce_client.encode("hex") ) # Tunnel_Tag # self.tunnel_tag = hmac.new( const.HTTP_BI_TUNNEL + self.nonce_client.encode("hex"), self.sentinel_hex[const.SENTINEL_HEX_LEN:], hashlib.sha256 ).digest() # HTTP Request # rand_url_len = random.randint(10, 40) rand_url = cb_random.gen_rand_bytes(self, rand_url_len) req = http_util.create_http_req(self, rand_url, self.handshake_ID, self.tunnel_tag.encode("hex"), self.host_name) self.transport.write(req) # New state # self.state = const.STATE_1
def sendPremaster(self, resp): """ State 3: Send premaster A. URL : E_KeyDPPub( Premaster ) + SeqNum_C2D_Rand ) + B. HMAC_KeyDPPub( Premaster + SeqNum_C2D_Rand + Decoupled_ID + Nonce_DP ) C. Cookie : SESSSIONID=Decoupled_ID Decoupled_ID = Randomstring """ try: # Check that DP sent back a decoupled_ID in a cookie # [new_cookie, self.decoupled_ID] = self.get_cookie_val( resp ) if self.decoupled_ID == -1: self.transport.loseConnection() # TODO: CHECK! return # Pull out the covert message and extract its components # pieces = resp.split('\r\n\r\n', 1) if len(pieces) != 2: print 'ERROR: bogus http response (%d pieces)' % len(pieces) self.transport.loseConnection() # TODO: CHECK! return # TODO: what does an ordinary client do when it gets BOTH # a "content-length" and "transfer-encoding chunked"? # We don't detect this, but just believe the first. # match_len = False match_chunk = False header = pieces[0] for line in header.split('\r\n'): match_len = re.search( '^[Cc]ontent-[Ll]ength:\s*([0-9]+)\s*$', line) if match_len: # print 'XXXXXX content-length' # TODO: rm break match_chunk = re.search( '^[Tt]ransfer-[Ee]ncoding:\s*chunked\s*$', line) if match_chunk: # print 'XXXXXX chunk-encoding' # TODO: rm break if match_len: covert_begin = str(resp).index(const.END_HEADER) + len(const.END_HEADER) covert_end = ( const.SIGNATURE_DP_PRIV_KEY_BYTE_LEN + const.ENCRYPT_SALT_NONCE_BYTE_LEN ) covert = resp[ covert_begin : covert_begin + covert_end ] elif match_chunk: chunk_len_begin = str(resp).index(const.END_HEADER) + len(const.END_HEADER) chunk_len_to_end = str(resp[chunk_len_begin:]) chunk_len_end = chunk_len_to_end.index(const.END_LINE) + len(const.END_LINE) chunk_len = chunk_len_to_end[ : chunk_len_end ] covert_begin = len(chunk_len) + str(resp).index(const.END_HEADER) + len(const.END_HEADER) covert_end = const.SIGNATURE_DP_PRIV_KEY_HEX_LEN + const.ENCRYPT_SALT_NONCE_HEX_LEN covert = str( resp[ covert_begin : covert_begin + covert_end ] ) if not all(c in string.hexdigits for c in covert): print "covert msg is not hex, not a hijack" self.transport.loseConnection() # TODO: CHECK! return else: covert = covert.decode("hex") else: print 'ERROR: no Content-Length or "Transfer-Encoding chunked"' self.transport.loseConnection() # TODO: CHECK! return i1 = const.SIGNATURE_DP_PRIV_KEY_BYTE_LEN signature = covert[ : i1 ] enc_nonce_dp = covert[ i1 : ] dec_nonce_dp = security_util.decrypt_text(self, enc_nonce_dp, self.extra_d2c_key, False, True, False) if dec_nonce_dp == -1: self.transport.loseConnection() # TODO: CHECK! return salt_1 = dec_nonce_dp[ : const.SALT_BYTE_LEN ] self.nonce_dp = dec_nonce_dp[ const.SALT_BYTE_LEN : ] # Verify that signature matches str_to_verify # str_to_verify = ( salt_1 + self.nonce_dp + new_cookie + self.handshake_ID ) verified = security_util.verify_signature( self, self.pubkey_dp, str_to_verify, signature ) if verified == True: # A. E_KeyDPPub( Premaster + SeqNum_C2D_Rand ) # premaster = cb_random.gen_rand_bytes( self, const.PREMASTER_BYTE_LEN ) k = RSA.load_pub_key_bio( BIO.MemoryBuffer(self.pubkey_dp) ) enc_text = k.public_encrypt( premaster + self.seqNum_C2D_Rand, RSA.pkcs1_oaep_padding ) # B. HMAC_KeyDPPub( Premaster + SeqNum_C2D_Rand + Decoupled_ID + Nonce_DP ) # # Note that decoupled_ID that is decoded here is client's # decouple_ID: it just happens to be stored in hex. # If something gets messed up, should fall through to # TypeError in except # text = ( premaster + self.seqNum_C2D_Rand + self.decoupled_ID.decode("hex") + self.nonce_dp ) auth_text = hmac.new( text, self.pubkey_dp, hashlib.sha256 ).digest() bin_text = binascii.hexlify( enc_text + auth_text ) zip_text = zlib.compress( bin_text ) # C. SESSSIONID=Decoupled_ID # req = http_util.create_http_req(self, zip_text, self.decoupled_ID, self.tunnel_tag.encode("hex"), self.host_name ) self.transport.write(req) [ self.client_key, self.dp_key, self.client_hash, self.dp_hash ] = security_util.compute_keys( self, premaster, self.nonce_client, self.nonce_dp ) # New state # self.state = const.STATE_5 else: self.transport.loseConnection() # TODO: CHECK! except ValueError, TypeError: print 'Error: message has no payload' self.transport.loseConnection()