diff options
author | Peter Wu <peter@lekensteyn.nl> | 2017-06-21 22:41:02 -0400 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2017-06-22 14:20:46 +0000 |
commit | 0510954a8b2388dab356f161133ac3b8a573aa82 (patch) | |
tree | 523a167b32a0932225fe62c46536430cb694ea42 | |
parent | d2ed7fcf9e0dca17f1a0181364910b9533dc7091 (diff) |
ssl: detect SSL 2.0 compatible Client Hello
During the esPcape challenge at SharkFest 2017 US, we had a SSL
decryption challenge. Normally you have to use Decode As to recognize
the custom port number, but the latest development branch has a feature
that automatically recognizes TLS (heuristics dissector).
SSL 2.0 Client Hello messages were however not recognized by this
heuristics which totally broke TLS decryption. Add some very strong
heuristics to detect these. "Mosterd na de maaltijd" :p
Change-Id: I0ac6aa666393335bb191e395faa1d32d3588ded7
Reviewed-on: https://code.wireshark.org/review/22337
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
-rw-r--r-- | epan/dissectors/packet-ssl.c | 79 |
1 files changed, 73 insertions, 6 deletions
diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c index 5140608cd5..869355b076 100644 --- a/epan/dissectors/packet-ssl.c +++ b/epan/dissectors/packet-ssl.c @@ -858,19 +858,18 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) return tvb_captured_length(tvb); } -static int -dissect_ssl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +static gboolean +is_sslv3_or_tls(tvbuff_t *tvb) { guint8 content_type; guint16 protocol_version, record_length; - conversation_t *conversation; /* * Heuristics should match a non-empty TLS record: * ContentType (1), ProtocolVersion (2), Length (2), fragment (...) */ if (tvb_captured_length(tvb) < 6) { - return 0; + return FALSE; } content_type = tvb_get_guint8(tvb, 0); @@ -879,7 +878,7 @@ dissect_ssl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data /* These are the common types. */ if (content_type != SSL_ID_HANDSHAKE && content_type != SSL_ID_APP_DATA) { - return 0; + return FALSE; } /* @@ -892,11 +891,79 @@ dissect_ssl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data protocol_version != TLSV1_VERSION && protocol_version != TLSV1DOT1_VERSION && protocol_version != TLSV1DOT2_VERSION) { - return 0; + return FALSE; } /* Check for sane length, see also ssl_check_record_length in packet-ssl-utils.c */ if (record_length == 0 || record_length >= TLS_MAX_RECORD_LENGTH + 2048) { + return FALSE; + } + + return TRUE; +} + +static gboolean +is_sslv2_clienthello(tvbuff_t *tvb) +{ + /* + * Detect SSL 2.0 compatible Client Hello as used in SSLv3 and TLS. + * + * https://tools.ietf.org/html/rfc5246#appendix-E.2 + * uint8 V2CipherSpec[3]; + * struct { + * uint16 msg_length; // 0: highest bit must be 1 + * uint8 msg_type; // 2: 1 for Client Hello + * Version version; // 3: equal to ClientHello.client_version + * uint16 cipher_spec_length; // 5: cannot be 0, must be multiple of 3 + * uint16 session_id_length; // 7: zero or 16 (in TLS 1.0) + * uint16 challenge_length; // 9: must be 32 + * // length so far: 2 + 1 + 2 + 2 + 2 + 2 = 11 + * V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length]; // len: min 3 + * opaque session_id[V2ClientHello.session_id_length]; // len: zero or 16 + * opaque challenge[V2ClientHello.challenge_length; // len: 32 + * // min. length: 11 + 3 + (0 or 16) + 32 = 46 or 62 + * } V2ClientHello; + */ + if (tvb_captured_length(tvb) < 46) { + return FALSE; + } + + /* Assume that message length is less than 256 (at most 64 cipherspecs). */ + if (tvb_get_guint8(tvb, 0) != 0x80) { + return FALSE; + } + + /* msg_type must be 1 for Client Hello */ + if (tvb_get_guint8(tvb, 2) != 1) { + return FALSE; + } + + /* cipher spec length must be a non-zero multiple of 3 */ + guint16 cipher_spec_length = tvb_get_ntohs(tvb, 5); + if (cipher_spec_length == 0 || cipher_spec_length % 3 != 0) { + return FALSE; + } + + /* session ID length must be 0 or 16 in TLS 1.0 */ + guint16 session_id_length = tvb_get_ntohs(tvb, 7); + if (session_id_length != 0 && session_id_length != 16) { + return FALSE; + } + + /* Challenge Length must be 32 */ + if (tvb_get_ntohs(tvb, 9) != 32) { + return FALSE; + } + + return TRUE; +} + +static int +dissect_ssl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + conversation_t *conversation; + + if (!is_sslv3_or_tls(tvb) && !is_sslv2_clienthello(tvb)) { return 0; } |