1""" 2Looks for SSL alert messages 3""" 4 5# handy reference: 6# http://blog.fourthbit.com/2014/12/23/traffic-analysis-of-an-ssl-slash-tls-session 7 8import dshell.core 9from dshell.output.alertout import AlertOutput 10 11import hashlib 12import io 13import struct 14from pprint import pprint 15 16# SSLv3/TLS version 17SSL3_VERSION = 0x0300 18TLS1_VERSION = 0x0301 19TLS1_1_VERSION = 0x0302 20TLS1_2_VERSION = 0x0303 21 22# Record type 23SSL3_RT_CHANGE_CIPHER_SPEC = 20 24SSL3_RT_ALERT = 21 25SSL3_RT_HANDSHAKE = 22 26SSL3_RT_APPLICATION_DATA = 23 27 28# Handshake message type 29SSL3_MT_HELLO_REQUEST = 0 30SSL3_MT_CLIENT_HELLO = 1 31SSL3_MT_SERVER_HELLO = 2 32SSL3_MT_CERTIFICATE = 11 33SSL3_MT_SERVER_KEY_EXCHANGE = 12 34SSL3_MT_CERTIFICATE_REQUEST = 13 35SSL3_MT_SERVER_DONE = 14 36SSL3_MT_CERTIFICATE_VERIFY = 15 37SSL3_MT_CLIENT_KEY_EXCHANGE = 16 38SSL3_MT_FINISHED = 20 39 40alert_types = { 41 0x00: "CLOSE_NOTIFY", 42 0x0a: "UNEXPECTED_MESSAGE", 43 0x14: "BAD_RECORD_MAC", 44 0x15: "DECRYPTION_FAILED", 45 0x16: "RECORD_OVERFLOW", 46 0x1e: "DECOMPRESSION_FAILURE", 47 0x28: "HANDSHAKE_FAILURE", 48 0x29: "NO_CERTIFICATE", 49 0x2a: "BAD_CERTIFICATE", 50 0x2b: "UNSUPPORTED_CERTIFICATE", 51 0x2c: "CERTIFICATE_REVOKED", 52 0x2d: "CERTIFICATE_EXPIRED", 53 0x2e: "CERTIFICATE_UNKNOWN", 54 0x2f: "ILLEGAL_PARAMETER", 55 0x30: "UNKNOWN_CA", 56 0x31: "ACCESS_DENIED", 57 0x32: "DECODE_ERROR", 58 0x33: "DECRYPT_ERROR", 59 0x3c: "EXPORT_RESTRICTION", 60 0x46: "PROTOCOL_VERSION", 61 0x47: "INSUFFICIENT_SECURITY", 62 0x50: "INTERNAL_ERROR", 63 0x5a: "USER_CANCELLED", 64 0x64: "NO_RENEGOTIATION", 65} 66 67alert_severities = { 68 0x01: "warning", 69 0x02: "fatal", 70} 71 72class DshellPlugin(dshell.core.ConnectionPlugin): 73 74 def __init__(self): 75 super().__init__( 76 name="sslalerts", 77 author="dev195", 78 bpf="tcp and (port 443 or port 993 or port 1443 or port 8531)", 79 description="Looks for SSL alert messages", 80 output=AlertOutput(label=__name__), 81 ) 82 83 def blob_handler(self, conn, blob): 84 data = io.BytesIO(blob.data) 85 alert_seen = False 86 # Iterate over each layer of the connection, paying special attention to the certificate 87 while True: 88 try: 89 content_type, proto_version, record_len = struct.unpack("!BHH", data.read(5)) 90 except struct.error: 91 break 92 if proto_version not in (SSL3_VERSION, TLS1_VERSION, TLS1_1_VERSION, TLS1_2_VERSION): 93 return None 94 if content_type == SSL3_RT_ALERT: 95 handshake_len = struct.unpack("!I", data.read(4))[0] 96# assert handshake_len == 2 # TODO remove when live 97 severity = struct.unpack("!B", data.read(1))[0] 98 if severity not in alert_severities: 99 continue 100 severity_msg = alert_severities.get(severity, severity) 101 alert_type = struct.unpack("!B", data.read(1))[0] 102 alert_msg = alert_types.get(alert_type, str(alert_type)) 103 self.write("SSL alert: ({}) {}".format(severity_msg, alert_msg), **conn.info()) 104 alert_seen = True 105 106 if alert_seen: 107 return conn, blob 108