From: Maya Dagon (mdagon) Date: Fri, 20 Oct 2023 08:42:01 +0000 (+0000) Subject: Pull request #4060: http_inspect: handle reserved gzip flags X-Git-Tag: 3.1.73.0~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9691768505b3fa71ad96bc682ccd02fd040e939c;p=thirdparty%2Fsnort3.git Pull request #4060: http_inspect: handle reserved gzip flags Merge in SNORT/snort3 from ~MDAGON/snort3:gzip_flag to master Squashed commit of the following: commit d26f4726924c24ba7cafe6ba05468398ec0c4ab7 Author: maya dagon Date: Tue Oct 3 10:40:52 2023 -0400 http_inspect: handle reserved gzip flags --- diff --git a/doc/reference/builtin_stubs.txt b/doc/reference/builtin_stubs.txt index 0ddc211f5..23caefc0f 100644 --- a/doc/reference/builtin_stubs.txt +++ b/doc/reference/builtin_stubs.txt @@ -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 diff --git a/src/service_inspectors/http_inspect/http_enum.h b/src/service_inspectors/http_inspect/http_enum.h index 94838a627..9b1df5641 100755 --- a/src/service_inspectors/http_inspect/http_enum.h +++ b/src/service_inspectors/http_inspect/http_enum.h @@ -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 }; diff --git a/src/service_inspectors/http_inspect/http_stream_splitter.h b/src/service_inspectors/http_inspect/http_stream_splitter.h index 8a9b231ea..3a5c64450 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter.h +++ b/src/service_inspectors/http_inspect/http_stream_splitter.h @@ -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, diff --git a/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc b/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc index 2dc6ea47b..6b3cfd144 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc +++ b/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc @@ -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(data); + if (data_w_updated_hdr != nullptr) + compress_stream->next_in = const_cast(data_w_updated_hdr); + else + compress_stream->next_in = const_cast(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; diff --git a/src/service_inspectors/http_inspect/http_tables.cc b/src/service_inspectors/http_inspect/http_tables.cc index 54f4aac05..a8bcbb272 100755 --- a/src/service_inspectors/http_inspect/http_tables.cc +++ b/src/service_inspectors/http_inspect/http_tables.cc @@ -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 } };