]> git.ipfire.org Git - people/ms/suricata.git/commitdiff
Look for Mismatched Encrypted HB request and response sizes, along with multiple...
authorWill Metcalf <william.metcalf@gmail.com>
Tue, 22 Apr 2014 16:11:32 +0000 (11:11 -0500)
committerVictor Julien <victor@inliniac.net>
Fri, 2 May 2014 09:55:12 +0000 (11:55 +0200)
src/app-layer-parser.c
src/app-layer-parser.h
src/app-layer-ssl.c
src/app-layer-ssl.h

index 9d7dae1cf83f3a35336a0c497f31e21b87aab7fc..d36de193c7677b2e2158cfb732e47b19d1dbcb5b 100644 (file)
@@ -849,6 +849,11 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp
         }
     }
 
+    /* In cases like HeartBleed for TLS we need to inspect AppLayer but not Payload */
+    if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) {
+        FlowSetNoPayloadInspectionFlag(f);
+    }
+
     /* next, see if we can get rid of transactions now */
     AppLayerParserTransactionsCleanup(f);
 
index 6496833898f5c552b572cb84fb5ba5c213a525fc..a000f0fbb082c2800530026b7e0ab8aa07400691 100644 (file)
 #include "app-layer-events.h"
 #include "util-file.h"
 
-#define APP_LAYER_PARSER_EOF            0x01
-#define APP_LAYER_PARSER_NO_INSPECTION  0x02
-#define APP_LAYER_PARSER_NO_REASSEMBLY  0x04
-
+#define APP_LAYER_PARSER_EOF                    0x01
+#define APP_LAYER_PARSER_NO_INSPECTION          0x02
+#define APP_LAYER_PARSER_NO_REASSEMBLY          0x04
+#define APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD  0x08
 
 
 /***** transaction handling *****/
index 6e0c001cfe2c794b59602c57ea803d12f9084136..30f9ce3eadcb5b543d6d4a4d2d071c6cfe880456 100644 (file)
@@ -63,6 +63,7 @@ SCEnumCharMap tls_decoder_event_table[ ] = {
     { "HEARTBEAT_MESSAGE",           TLS_DECODER_EVENT_HEARTBEAT },
     { "INVALID_HEARTBEAT_MESSAGE",   TLS_DECODER_EVENT_INVALID_HEARTBEAT },
     { "OVERFLOW_HEARTBEAT_MESSAGE",  TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT },
+    { "DATALEAK_HEARTBEAT_MISMATCH", TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH },
     /* Certificates decoding messages */
     { "INVALID_CERTIFICATE",         TLS_DECODER_EVENT_INVALID_CERTIFICATE },
     { "CERTIFICATE_MISSING_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT },
@@ -341,7 +342,7 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input,
  * \retval The number of bytes parsed on success, 0 if nothing parsed, -1 on failure.
  */
 static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input,
-                                       uint32_t input_len)
+                                       uint32_t input_len, uint8_t direction)
 {
     uint8_t hb_type;
     uint16_t payload_len;
@@ -351,34 +352,78 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input,
     if (input_len < 3) {
         return 0;
     }
-
     hb_type = *input++;
 
-    if (!(hb_type == TLS_HB_REQUEST || hb_type == TLS_HB_RESPONSE)) {
-        AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT);
-        return -1;
-    }
+    if((ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) == 0) {
+        ssl_state->flags |= SSL_AL_FLAG_HB_INFLIGHT;
+
+        if (direction) {
+            ssl_state->flags |= SSL_AL_FLAG_HB_SERVER_INIT;
+            SCLogDebug("HeartBeat Record type sent in the toclient "
+                       "direction!");
+        } else {
+            ssl_state->flags |= SSL_AL_FLAG_HB_CLIENT_INIT;
+            SCLogDebug("HeartBeat Record type sent in the toserver "
+                       "direction!");
+        }
+        // if we reach this poin then can we assume that the HB request is encrypted if so lets set the heartbeat record len
+        if (!(hb_type == TLS_HB_REQUEST || hb_type == TLS_HB_RESPONSE)) {
+            SCLogDebug("Encrypted HeartBeat Request In-flight");
+            ssl_state->hb_record_len = ssl_state->curr_connp->record_length;
+            return (ssl_state->curr_connp->record_length - 3);
+        }
 
-    payload_len = (*input++) << 8;
-    payload_len |= (*input++);
+        payload_len = (*input++) << 8;
+        payload_len |= (*input++);
 
-    // check that the requested payload length is really present in record (CVE-2014-0160)
-    if ((uint32_t)(payload_len+3) > ssl_state->curr_connp->record_length) {
-        AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT);
-        return -1;
-    }
+        // check that the requested payload length is really present in record (CVE-2014-0160)
+        if ((uint32_t)(payload_len+3) > ssl_state->curr_connp->record_length) {
+            SCLogDebug("We have a short record in HeartBeat Request");
+            AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT);
+            return -1;
+        }
+
+        // check the padding length
+        // it must be at least 16 bytes (RFC 6520, section 4)
+        padding_len = ssl_state->curr_connp->record_length - payload_len - 3;
+        if (padding_len < 16) {
+            SCLogDebug("We have a short record in HeartBeat Request");
+            AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT);
+            return -1;
+        }
 
-    // check the padding length
-    // it must be at least 16 bytes (RFC 6520, section 4)
-    padding_len = ssl_state->curr_connp->record_length - payload_len - 3;
-    if (padding_len < 16) {
+        if (input_len < payload_len+padding_len) { // we don't have the payload
+            return 0;
+        }
+
+    //OpenSSL still seems to discard multiple in-flight heartbeats although some tools send multiple at once
+    } else if (direction == 1 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_SERVER_INIT)) {
+        SCLogDebug("Multiple In-Flight Server Intiated HeartBeats");
+        AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT);
+        return -1;
+    } else if (direction == 0 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_CLIENT_INIT)) {
+        SCLogDebug("Multiple In-Flight Client Intiated HeartBeats");
         AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT);
         return -1;
+    } else {
+        //we have a HB record in the opposite direction of the request lets reset our flags
+        ssl_state->flags &= ~SSL_AL_FLAG_HB_INFLIGHT;
+        ssl_state->flags &= ~SSL_AL_FLAG_HB_SERVER_INIT;
+        ssl_state->flags &= ~SSL_AL_FLAG_HB_CLIENT_INIT;
+
+        // if we reach this poin then can we assume that the HB request is encrypted if so lets set the heartbeat record len
+        if (!(hb_type == TLS_HB_REQUEST || hb_type == TLS_HB_RESPONSE)) {
+            //check to see if the encrypted response is longer than the encrypted request
+            if (ssl_state->hb_record_len > 0 && ssl_state->hb_record_len < ssl_state->curr_connp->record_length) {
+                SCLogDebug("My Heart It's Bleeding.. OpenSSL HeartBleed Response");
+                AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH);
+                ssl_state->hb_record_len = 0;
+                return -1;
+            }
+        }
+        // reset the hb record len in-case we have legit hb's followed by a bad one
+        ssl_state->hb_record_len = 0;
     }
-
-    if (input_len < payload_len+padding_len) // we don't have the payload
-        return 0;
-
     // skip the heartbeat, 3 bytes were already parsed, e.g |18 03 02| for TLS 1.2
     return (ssl_state->curr_connp->record_length - 3);
 }
@@ -766,6 +811,7 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state,
     }
 
     switch (ssl_state->curr_connp->content_type) {
+
         /* we don't need any data from these types */
         case SSLV3_CHANGE_CIPHER_SPEC:
             ssl_state->flags |= SSL_AL_FLAG_CHANGE_CIPHER_SPEC;
@@ -782,10 +828,12 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state,
         case SSLV3_APPLICATION_PROTOCOL:
             if ((ssl_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) &&
                 (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) {
-                /* set flags */
+                /*
                 AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION);
                 if (ssl_config.no_reassemble == 1)
                     AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY);
+                */
+                AppLayerParserStateSetFlag(pstate,APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD);
             }
 
             break;
@@ -822,14 +870,8 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state,
             }
 
             break;
-
         case SSLV3_HEARTBEAT_PROTOCOL:
-            if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) {
-                // stream is encrypted, so we cannot check the handshake :(
-                //AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_HEARTBEAT);
-                break;
-            }
-            retval = SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, input_len);
+            retval = SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, input_len, direction);
             if (retval < 0)
                 return -1;
             break;
index 5047eb10f2baf2f7222a86cfa2eb8a8a9be80c75..fca4f4ed7766ad179a74f35865e16c99003b127c 100644 (file)
@@ -38,6 +38,7 @@ enum {
     TLS_DECODER_EVENT_HEARTBEAT,
     TLS_DECODER_EVENT_INVALID_HEARTBEAT,
     TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT,
+    TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH,
     /* Certificates decoding messages */
     TLS_DECODER_EVENT_INVALID_CERTIFICATE,
     TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT,
@@ -71,6 +72,11 @@ enum {
 
 #define SSL_AL_FLAG_STATE_LOGGED                0x4000
 
+/* flags specific to HeartBeat state */
+#define SSL_AL_FLAG_HB_INFLIGHT                 0x8000
+#define SSL_AL_FLAG_HB_CLIENT_INIT              0x10000
+#define SSL_AL_FLAG_HB_SERVER_INIT             0x20000
+
 /* config flags */
 #define SSL_TLS_LOG_PEM                         (1 << 0)
 
@@ -151,6 +157,9 @@ typedef struct SSLState_ {
 
     SSLStateConnp client_connp;
     SSLStateConnp server_connp;
+
+    /* there might be a better place to store this*/
+    uint16_t hb_record_len;
 } SSLState;
 
 void RegisterSSLParsers(void);