From 928ac012156fb8d393ce5ac4a496fde3c2e87b00 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 6 Aug 2026 20:57:34 +0000 Subject: [PATCH] ssl: fix SSLv2 CLIENT_HELLO underflow SSLv2Decode() consumed six fixed CLIENT_HELLO body bytes (version + cipher_spec_length + session_id_length) guarded only by input_len >= 6, which checks the buffer remainder but not the record itself. When an attacker sends a record whose declared record_length is < 7 (e.g. 1), bytes_processed advances past record_lengths_length + record_length, leading an integer underflow. Address by adding a record_length >= 7 check to the CLIENT_HELLO case. Also add another check: bail if bytes_processed > record_length + record_lengths_length. Ticket: #8853. --- src/app-layer-ssl.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 5dc0a407fd..a57fa52d76 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -2258,7 +2258,12 @@ static struct SSLDecoderResult SSLv2Decode(uint8_t direction, SSLState *ssl_stat break; case SSLV2_MT_CLIENT_HELLO: - if (input_len < 6) { + /* record_length does not count the msg_type byte. CLIENT_HELLO + * body starts with 3 fixed fields: client_version (2) + + * cipher_spec_length (2) + session_id_length (2). We need at + * least those 6 bytes after the msg_type, so record_length + * must be >= 7. */ + if (input_len < 6 || ssl_state->curr_connp->record_length < 7) { SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return SSL_DECODER_ERROR(-1); } @@ -2354,6 +2359,16 @@ static struct SSLDecoderResult SSLv2Decode(uint8_t direction, SSLState *ssl_stat ssl_state->flags |= ssl_state->current_flags; + if (ssl_state->curr_connp->bytes_processed > + ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length) { + SCLogDebug("SSLv2 bytes_processed (%u) exceeds record+hdr " + "len (record_length=%u, lengths_length=%u)", + ssl_state->curr_connp->bytes_processed, ssl_state->curr_connp->record_length, + ssl_state->curr_connp->record_lengths_length); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + return SSL_DECODER_ERROR(-1); + } + if (input_len + ssl_state->curr_connp->bytes_processed >= (ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length)) {