]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4060: http_inspect: handle reserved gzip flags
authorMaya Dagon (mdagon) <mdagon@cisco.com>
Fri, 20 Oct 2023 08:42:01 +0000 (08:42 +0000)
committerOleksii Shumeiko -X (oshumeik - SOFTSERVE INC at Cisco) <oshumeik@cisco.com>
Fri, 20 Oct 2023 08:42:01 +0000 (08:42 +0000)
Merge in SNORT/snort3 from ~MDAGON/snort3:gzip_flag to master

Squashed commit of the following:

commit d26f4726924c24ba7cafe6ba05468398ec0c4ab7
Author: maya dagon <mdagon@cisco.com>
Date:   Tue Oct 3 10:40:52 2023 -0400

    http_inspect: handle reserved gzip flags

doc/reference/builtin_stubs.txt
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_stream_splitter.h
src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc
src/service_inspectors/http_inspect/http_tables.cc

index 0ddc211f5a9f8a880a52337843e4bd8ec131151d..23caefc0fab10bda492a266fd78473f6ef2881e6 100644 (file)
@@ -1287,6 +1287,10 @@ HTTP/2 preface received instead of an HTTP/1 method
 
 HTTP request method is not on allowed methods list or is on disallowed methods list.
 
+119:288
+
+HTTP reserved GZIP flags are set
+
 121:1
 
 Invalid flag set on HTTP/2 frame header
index 94838a627864569dab8b3c90cc4ba92827097d72..9b1df5641f301162b8556a36851c06dec17ebe54 100755 (executable)
@@ -33,6 +33,7 @@ static const uint32_t HTTP_GID = 119;
 static const int GZIP_WINDOW_BITS = 31;
 static const uint8_t GZIP_HEADER_FLAG_OFFSET = 3;
 static const uint8_t GZIP_FLAG_FEXTRA = 0x4;
+static const uint8_t GZIP_RESERVED_FLAGS = 0xE0; // bits 5-7
 static const int DEFLATE_WINDOW_BITS = 15;
 static const int MAX_FIELD_NAME_LENGTH = 100;
 // Plan to support max 8 xff headers
@@ -287,6 +288,7 @@ enum Infraction
     INF_METHOD_NOT_ON_ALLOWED_LIST = 136,
     INF_METHOD_ON_DISALLOWED_LIST = 137,
     INF_PIPELINE_MAX = 138,
+    INF_GZIP_RESERVED_FLAGS = 139,
     INF__MAX_VALUE
 };
 
@@ -434,6 +436,7 @@ enum EventSid
     EVENT_REQ_TOO_LONG = 285,
     EVENT_UNEXPECTED_H2_PREFACE = 286,
     EVENT_DISALLOWED_METHOD = 287,
+    EVENT_GZIP_RESERVED_FLAGS = 288,
     EVENT__MAX_VALUE
 };
 
index 8a9b231ea95b0fe3f80ffc2c71a7bdf46717aa48..3a5c64450d2bca6bc760955c64a7c6fc670e8669 100644 (file)
@@ -63,7 +63,7 @@ private:
         uint32_t length, HttpEnums::CompressId& compression, z_stream*& compress_stream,
         bool at_start, HttpInfractions* infractions, HttpEventGen* events,
         HttpFlowData* session_data) const;
-    void process_gzip_header(const uint8_t* data,
+    uint8_t* process_gzip_header(const uint8_t* data,
         uint32_t length, HttpFlowData* session_data) const;
     bool gzip_header_check_done(HttpFlowData* session_data) const;
     StreamSplitter::Status handle_zero_nine(snort::Flow*, HttpFlowData*, const uint8_t* data,
index 2dc6ea47b9b08e64240ba2e428ba19ffe12916f9..6b3cfd144f273c5b53ef19276209269996c8fff9 100644 (file)
@@ -141,11 +141,12 @@ void HttpStreamSplitter::chunk_spray(HttpFlowData* session_data, uint8_t* buffer
     }
 }
 
-void HttpStreamSplitter::process_gzip_header(const uint8_t* data,
+uint8_t* HttpStreamSplitter::process_gzip_header(const uint8_t* data,
     uint32_t length, HttpFlowData* session_data) const
 {
     uint32_t& header_bytes_processed = session_data->gzip_header_bytes_processed[source_id];
     uint32_t input_bytes_processed = 0;
+    uint8_t* modified_data = nullptr;
     if (session_data->gzip_state[source_id] == GZIP_TBD)
     {
         static const uint8_t gzip_magic[] = {0x1f, 0x8b, 0x08};
@@ -168,9 +169,18 @@ void HttpStreamSplitter::process_gzip_header(const uint8_t* data,
             *session_data->get_infractions(source_id) += INF_GZIP_FEXTRA;
             session_data->events[source_id]->create_event(EVENT_GZIP_FEXTRA);
         }
+        if (gzip_flags & GZIP_RESERVED_FLAGS)
+        {
+            *session_data->get_infractions(source_id) += INF_GZIP_RESERVED_FLAGS;
+            session_data->events[source_id]->create_event(EVENT_GZIP_RESERVED_FLAGS);
+            modified_data = new uint8_t[length];
+            memcpy(modified_data, data, length);
+            modified_data[input_bytes_processed] &= ~GZIP_RESERVED_FLAGS;
+        }
         header_bytes_processed++;
         session_data->gzip_state[source_id] = GZIP_FLAGS_PROCESSED;
     }
+    return modified_data;
 }
 
 bool HttpStreamSplitter::gzip_header_check_done(HttpFlowData* session_data) const
@@ -185,15 +195,21 @@ void HttpStreamSplitter::decompress_copy(uint8_t* buffer, uint32_t& offset, cons
 {
     if ((compression == CMP_GZIP) || (compression == CMP_DEFLATE))
     {
+        uint8_t* data_w_updated_hdr = nullptr;
         if (compression == CMP_GZIP and !gzip_header_check_done(session_data))
-            process_gzip_header(data, length, session_data);
+            data_w_updated_hdr = process_gzip_header(data, length, session_data);
 
-        compress_stream->next_in = const_cast<Bytef*>(data);
+        if (data_w_updated_hdr != nullptr)
+            compress_stream->next_in = const_cast<Bytef*>(data_w_updated_hdr);
+        else 
+            compress_stream->next_in = const_cast<Bytef*>(data);
         compress_stream->avail_in = length;
         compress_stream->next_out = buffer + offset;
         compress_stream->avail_out = MAX_OCTETS - offset;
         int ret_val = inflate(compress_stream, Z_SYNC_FLUSH);
 
+        delete[] data_w_updated_hdr;
+        
         if ((ret_val == Z_OK) || (ret_val == Z_STREAM_END))
         {
             offset = MAX_OCTETS - compress_stream->avail_out;
index 54f4aac05415461f048ccabd8f8436ec1bb2e071..a8bcbb272df2ac8dfd28f4016d02ce27f7e67fa3 100755 (executable)
@@ -347,6 +347,7 @@ const RuleMap HttpModule::http_events[] =
     { EVENT_UNEXPECTED_H2_PREFACE,      "HTTP/2 preface received instead of an HTTP/1 method" },
     { EVENT_DISALLOWED_METHOD,          "HTTP request method is not on allowed methods list or is on "
                                         "disallowed methods list" },
+    { EVENT_GZIP_RESERVED_FLAGS,        "HTTP gzip body with reserved flag set" },
     { 0, nullptr }
 };