def do_handshake_with_robot(self): # type: ignore """Modified do_handshake() to send a ROBOT payload and return the result. """ try: # Start the handshake using nassl - will throw WantReadError right away self._ssl.do_handshake() except WantReadError: # Send the Client Hello len_to_read = self._network_bio.pending() while len_to_read: # Get the data from the SSL engine handshake_data_out = self._network_bio.read(len_to_read) # Send it to the peer self._sock.send(handshake_data_out) len_to_read = self._network_bio.pending() # Retrieve the server's response - directly read the underlying network socket # Retrieve data until we get to the ServerHelloDone # The server may send back a ServerHello, an Alert or a CertificateRequest first did_receive_hello_done = False remaining_bytes = b"" while not did_receive_hello_done: try: tls_record, len_consumed = TlsRecordParser.parse_bytes(remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? break remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsHandshakeRecord): # Does the record contain a ServerDone message? for handshake_message in tls_record.subprotocol_messages: if handshake_message.handshake_type == TlsHandshakeTypeByte.SERVER_DONE: did_receive_hello_done = True break # If not, it could be a ServerHello, Certificate or a CertificateRequest if the server requires client auth elif isinstance(tls_record, TlsAlertRecord): # Server returned a TLS alert break else: raise ValueError("Unknown record? Type {}".format(tls_record.header.type)) if did_receive_hello_done: # Send a special Client Key Exchange Record as the payload self._sock.send(self._robot_cke_record.to_bytes()) if self._robot_should_finish_handshake: # Then send a CCS record ccs_record = TlsChangeCipherSpecRecord.from_parameters( tls_version=tls_parser.tls_version.TlsVersionEnum[self._ssl_version.name] ) self._sock.send(ccs_record.to_bytes()) # Lastly send a Finished record finished_record_bytes = _RobotTlsRecordPayloads.get_finished_record_bytes(self._ssl_version) self._sock.send(finished_record_bytes) # Return whatever the server sent back by raising an exception # The goal is to detect similar/different responses while True: try: tls_record, len_consumed = TlsRecordParser.parse_bytes(remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data try: raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? raise ServerResponseToRobot("No data") except socket.error as e: # Server closed the connection after receiving the CCS payload raise ServerResponseToRobot("socket.error {}".format(str(e))) remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsAlertRecord): raise ServerResponseToRobot( "TLS Alert {} {}".format(tls_record.alert_description, tls_record.alert_severity) ) else: break raise ServerResponseToRobot("Ok")
def _do_handshake_with_ccs_injection(self): # type: ignore """Modified do_handshake() to send a CCS injection payload and return the result. """ try: # Start the handshake using nassl - will throw WantReadError right away self._ssl.do_handshake() except WantReadError: # Send the Client Hello len_to_read = self._network_bio.pending() while len_to_read: # Get the data from the SSL engine handshake_data_out = self._network_bio.read(len_to_read) # Send it to the peer self._sock.send(handshake_data_out) len_to_read = self._network_bio.pending() # Retrieve the server's response - directly read the underlying network socket # Retrieve data until we get to the ServerHelloDone # The server may send back a ServerHello, an Alert or a CertificateRequest first did_receive_hello_done = False remaining_bytes = b"" while not did_receive_hello_done: try: tls_record, len_consumed = TlsRecordParser.parse_bytes( remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? break remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsHandshakeRecord): # Does the record contain a ServerDone message? for handshake_message in tls_record.subprotocol_messages: if handshake_message.handshake_type == TlsHandshakeTypeByte.SERVER_DONE: did_receive_hello_done = True break # If not, it could be a ServerHello, Certificate or a CertificateRequest if the server requires client auth elif isinstance(tls_record, TlsAlertRecord): # Server returned a TLS alert break else: raise ValueError("Unknown record? Type {}".format( tls_record.header.type)) if did_receive_hello_done: # Send an early CCS record - this should be rejected by the server payload = TlsChangeCipherSpecRecord.from_parameters( tls_version=tls_parser.tls_version.TlsVersionEnum[ self._ssl_version.name]).to_bytes() self._sock.send(payload) # Send an early application data record which should be ignored by the server app_data_record = TlsApplicationDataRecord.from_parameters( tls_version=tls_parser.tls_version.TlsVersionEnum[ self._ssl_version.name], application_data=b"\x00\x00") self._sock.send(app_data_record.to_bytes()) # Check if an alert was sent back while True: try: tls_record, len_consumed = TlsRecordParser.parse_bytes( remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data try: raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? raise _NotVulnerableToCcsInjection() except socket.error: # Server closed the connection after receiving the CCS payload raise _NotVulnerableToCcsInjection() remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsAlertRecord): # Server returned a TLS alert but which one? if tls_record.alert_description == 0x14: # BAD_RECORD_MAC: This means that the server actually tried to decrypt our early application data # record instead of ignoring it; server is vulnerable raise _VulnerableToCcsInjection() # Any other alert means that the server rejected the early CCS record raise _NotVulnerableToCcsInjection() else: break raise _NotVulnerableToCcsInjection()
def do_handshake_with_robot(self): """Modified do_handshake() to send a ROBOT payload and return the result. """ try: # Start the handshake using nassl - will throw WantReadError right away self._ssl.do_handshake() except WantReadError: # Send the Client Hello len_to_read = self._network_bio.pending() while len_to_read: # Get the data from the SSL engine handshake_data_out = self._network_bio.read(len_to_read) # Send it to the peer self._sock.send(handshake_data_out) len_to_read = self._network_bio.pending() # Retrieve the server's response - directly read the underlying network socket # Retrieve data until we get to the ServerHelloDone # The server may send back a ServerHello, an Alert or a CertificateRequest first did_receive_hello_done = False remaining_bytes = b'' while not did_receive_hello_done: try: tls_record, len_consumed = TlsRecordParser.parse_bytes(remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? break remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsHandshakeRecord): # Does the record contain a ServerDone message? for handshake_message in tls_record.subprotocol_messages: if handshake_message.handshake_type == TlsHandshakeTypeByte.SERVER_DONE: did_receive_hello_done = True break # If not, it could be a ServerHello, Certificate or a CertificateRequest if the server requires client auth elif isinstance(tls_record, TlsAlertRecord): # Server returned a TLS alert break else: raise ValueError('Unknown record? Type {}'.format(tls_record.header.type)) if did_receive_hello_done: # Send a special Client Key Exchange Record as the payload self._sock.send(self._robot_cke_record.to_bytes()) if self._robot_should_finish_handshake: # Then send a CCS record ccs_record = TlsChangeCipherSpecRecord.from_parameters( tls_version=TlsVersionEnum[self._ssl_version.name] ) self._sock.send(ccs_record.to_bytes()) # Lastly send a Finished record finished_record_bytes = RobotTlsRecordPayloads.get_finished_record_bytes(self._ssl_version) self._sock.send(finished_record_bytes) # Return whatever the server sent back by raising an exception # The goal is to detect similar/different responses while True: try: tls_record, len_consumed = TlsRecordParser.parse_bytes(remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data try: raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? raise ServerResponseToRobot('No data') except socket.error as e: # Server closed the connection after receiving the CCS payload raise ServerResponseToRobot('socket.error {}'.format(str(e))) remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsAlertRecord): raise ServerResponseToRobot('TLS Alert {} {}'.format(tls_record.alert_description, tls_record.alert_severity)) else: break raise ServerResponseToRobot('Ok')
def do_handshake_with_ccs_injection(self): # type: ignore """Modified do_handshake() to send a CCS injection payload and return the result. """ try: # Start the handshake using nassl - will throw WantReadError right away self._ssl.do_handshake() except WantReadError: # Send the Client Hello len_to_read = self._network_bio.pending() while len_to_read: # Get the data from the SSL engine handshake_data_out = self._network_bio.read(len_to_read) # Send it to the peer self._sock.send(handshake_data_out) len_to_read = self._network_bio.pending() # Retrieve the server's response - directly read the underlying network socket # Retrieve data until we get to the ServerHelloDone # The server may send back a ServerHello, an Alert or a CertificateRequest first did_receive_hello_done = False remaining_bytes = b'' while not did_receive_hello_done: try: tls_record, len_consumed = TlsRecordParser.parse_bytes(remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? break remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsHandshakeRecord): # Does the record contain a ServerDone message? for handshake_message in tls_record.subprotocol_messages: if handshake_message.handshake_type == TlsHandshakeTypeByte.SERVER_DONE: did_receive_hello_done = True break # If not, it could be a ServerHello, Certificate or a CertificateRequest if the server requires client auth elif isinstance(tls_record, TlsAlertRecord): # Server returned a TLS alert break else: raise ValueError('Unknown record? Type {}'.format(tls_record.header.type)) if did_receive_hello_done: # Send an early CCS record - this should be rejected by the server payload = TlsChangeCipherSpecRecord.from_parameters( tls_version=TlsVersionEnum[self._ssl_version.name]).to_bytes() self._sock.send(payload) # Send an early application data record which should be ignored by the server app_data_record = TlsApplicationDataRecord.from_parameters(tls_version=TlsVersionEnum[self._ssl_version.name], application_data=b'\x00\x00') self._sock.send(app_data_record.to_bytes()) # Check if an alert was sent back while True: try: tls_record, len_consumed = TlsRecordParser.parse_bytes(remaining_bytes) remaining_bytes = remaining_bytes[len_consumed::] except NotEnoughData: # Try to get more data try: raw_ssl_bytes = self._sock.recv(16381) if not raw_ssl_bytes: # No data? raise NotVulnerableToCcsInjection() except socket.error: # Server closed the connection after receiving the CCS payload raise NotVulnerableToCcsInjection() remaining_bytes = remaining_bytes + raw_ssl_bytes continue if isinstance(tls_record, TlsAlertRecord): # Server returned a TLS alert but which one? if tls_record.alert_description == 0x14: # BAD_RECORD_MAC: This means that the server actually tried to decrypt our early application data # record instead of ignoring it; server is vulnerable raise VulnerableToCcsInjection() # Any other alert means that the server rejected the early CCS record raise NotVulnerableToCcsInjection() else: break raise NotVulnerableToCcsInjection()
r.send(to_record(TlsHandshakeMessage(TlsHandshakeTypeByte.SERVER_DONE, b"")).to_bytes()) answer = r.recv() print(answer.hex()) clientkey, consumed1 = TlsRecordParser.parse_bytes(answer) if len(answer)-consumed1 == 0: print(clientkey.subprotocol_messages[0]) exit() changespec, consumed2 = TlsRecordParser.parse_bytes(answer[consumed1:]) encryptedfinish = answer[consumed1+consumed2+5:] serverchangespec = TlsChangeCipherSpecRecord.from_parameters(TlsVersionEnum.TLSV1_2) r.send(bytes.fromhex("16030300aa040000a600001c2000a03aa9174e129289d5f090d14da89b8f4aa4edd17a620729cdb8322bd983f312d6370766d7c52e840f76583726434c25fd5a802f9095e8dfd54d61baab6b6b97f3b48a01ab65f3b1a06705e9158a0def4ebb68be05e58dc43c0495aae057d9dab41a0196d72f5abb135e3c1b72c04c87c8b87b37e90f60d8dd8f07c8d7f33ae74c6f25e25cd9f353c6a66b1b6fba42f24068997283136fdd70690546f0907f3028") + serverchangespec.to_bytes()) handshake_messages = client_hello.subprotocol_messages[0].to_bytes() + TlsHandshakeMessage(TlsHandshakeTypeByte.SERVER_HELLO, server_hello).to_bytes() + TlsHandshakeMessage(TlsHandshakeTypeByte.CERTIFICATE, certs).to_bytes() + TlsHandshakeMessage(TlsHandshakeTypeByte.SERVER_KEY_EXCHANGE, serverkey).to_bytes() + TlsHandshakeMessage(TlsHandshakeTypeByte.SERVER_DONE, b"").to_bytes() + clientkey.subprotocol_messages[0].to_bytes() def prf(secret, label, seed, size): seed = label + seed a = seed r = b"" while len(r) < size: a = hmac.new(secret, a, sha384).digest() r += hmac.new(secret, a+seed, sha384).digest() return r[:size] from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicNumbers x = int(clientkey.subprotocol_messages[0].handshake_data[2:2+32].hex(), 16)