]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3555: http_inspect: parameters for header alerts
authorTom Peters (thopeter) <thopeter@cisco.com>
Wed, 17 Aug 2022 23:52:41 +0000 (23:52 +0000)
committerTom Peters (thopeter) <thopeter@cisco.com>
Wed, 17 Aug 2022 23:52:41 +0000 (23:52 +0000)
Merge in SNORT/snort3 from ~ADMAMOLE/snort3:header_params to master

Squashed commit of the following:

commit beed48e8b60e9631ff9001b79db3dfd9df3e4285
Author: Adrian Mamolea <admamole@cisco.com>
Date:   Mon Aug 8 17:06:08 2022 -0400

    http_inspect: parameters for header alerts

doc/reference/builtin_stubs.txt
doc/user/http_inspect.txt
src/service_inspectors/http_inspect/http_module.cc
src/service_inspectors/http_inspect/http_module.h
src/service_inspectors/http_inspect/http_msg_head_shared.cc
src/service_inspectors/http_inspect/http_msg_head_shared.h
src/service_inspectors/http_inspect/http_tables.cc

index 52eec8bcff6b1948b72a2b1efd815d09d66425df..e3b97c2b8fb2020c1ea4f3f50921b7c156af7e71 100644 (file)
@@ -809,12 +809,12 @@ generated if the simplify_path option is configured.
 
 119:19
 
-HTTP header line exceeds 4096 bytes. This does not apply to the start line. Header line length
-includes both header field name and value.
+HTTP header line exceeds maximum_header_length option bytes. This does not apply to the start line.
+Header line length includes both header field name and value.
 
 119:20
 
-HTTP message has more than 200 header fields.
+HTTP message has more than maximum_headers option header fields.
 
 119:21
 
index b09c4821934eb934a7cbe1aef7c3cb361e9203e6..badafdd738df9fdeaa7c15c03a07bcf10c0cae9e 100755 (executable)
@@ -343,6 +343,16 @@ body to be less than four gigabytes.
 A lower limit may be configured by setting maximum_chunk_length. Any chunk
 longer than maximum chunk length will generate a 119:16 alert.
 
+===== maximum_header_length
+
+http_inspect generates 119:19 when the length of a header exceeds
+maximum_header_length = N {0 : 65535} (default 4096).
+
+===== maximum_headers
+
+http_inspect generates 119:20 when the number of headers exceeds
+maximum_headers = N {0 : 65535} (default 200).
+
 ===== URI processing
 
 Normalization and inspection of the URI in the HTTP request message is a
index c7451e90609c983b4d97d3012aaf8ec0f61c1b6f..a5ac07f135a69f11f23c570b453af9d1d3e0337c 100755 (executable)
@@ -74,6 +74,12 @@ const Parameter HttpModule::http_params[] =
     { "maximum_chunk_length", Parameter::PT_INT, "0:4294967295", "4294967295",
       "maximum allowed length for a message body chunk" },
 
+    { "maximum_header_length", Parameter::PT_INT, "0:65535", "4096",
+      "alert when the length of a header exceeds this value" },
+
+    { "maximum_headers", Parameter::PT_INT, "0:65535", "200",
+      "alert when the number of headers in a message exceeds this value" },
+
     { "normalize_utf", Parameter::PT_BOOL, nullptr, "true",
       "normalize charset utf encodings in response bodies" },
 
@@ -254,6 +260,14 @@ bool HttpModule::set(const char*, Value& val, SnortConfig*)
     {
         params->maximum_chunk_length = val.get_int64();
     }
+    else if (val.is("maximum_header_length"))
+    {
+        params->maximum_header_length = val.get_uint16();
+    }
+    else if (val.is("maximum_headers"))
+    {
+        params->maximum_headers = val.get_uint16();
+    }
     else if (val.is("decompress_pdf"))
     {
         params->decompress_pdf = val.get_bool();
index 35dce8d005aa0e76e4e62054303956f4ded28438..7b0070c818c65bf7a7133a8d42b1399d2dd6aaf9 100755 (executable)
@@ -54,6 +54,8 @@ public:
     bool normalize_utf = true;
     int64_t maximum_host_length = -1;
     int64_t maximum_chunk_length = 0xFFFFFFFF;
+    uint16_t maximum_header_length = 4096;
+    uint16_t maximum_headers = 200;
     bool decompress_pdf = false;
     bool decompress_swf = false;
     bool decompress_zip = false;
index 15ad80d13cbb773107fc2b07d1cc3c77ebb9fb3a..ee3ea1b2ebedf6a8dcedc464f761e11561f11b70 100755 (executable)
@@ -132,18 +132,15 @@ void HttpMsgHeadShared::parse_header_block()
         const int32_t header_length = find_next_header(msg_text.start() + bytes_used,
             msg_text.length() - bytes_used, num_seps);
         header_line[num_headers].set(header_length, msg_text.start() + bytes_used + num_seps);
-        if (header_line[num_headers].length() > MAX_HEADER_LENGTH)
+        if (header_line[num_headers].length() > params->maximum_header_length)
         {
             add_infraction(INF_TOO_LONG_HEADER);
             create_event(EVENT_LONG_HDR);
         }
         bytes_used += num_seps + header_line[num_headers].length();
-        if (++num_headers >= MAX_HEADERS)
-        {
-            break;
-        }
+        ++num_headers;
     }
-    if (bytes_used < msg_text.length())
+    if (num_headers > params->maximum_headers)
     {
         add_infraction(INF_TOO_MANY_HEADERS);
         create_event(EVENT_MAX_HEADERS);
index 61db916b4d1570f0db4436269a82381cb5c07d76..144aa97610e493e26d38d1502d2bc956a8284aac 100755 (executable)
@@ -62,7 +62,6 @@ public:
     int32_t get_num_headers() const { return num_headers; }
     int32_t get_content_type();
 
-    static const int MAX_HEADERS = 200;  // I'm an arbitrary number. FIXIT-RC
 protected:
     HttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size,
         HttpFlowData* session_data_, HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
@@ -73,6 +72,8 @@ protected:
     // Do a case insensitive search for "boundary=" in a Field
     static bool boundary_present(const Field& field);
 
+    // All of these are indexed by the relative position of the header field in the message
+
     Field* header_line = nullptr;
     HttpEnums::HeaderId* header_name_id = nullptr;
     int32_t num_headers = HttpCommon::STAT_NOT_COMPUTE;
@@ -84,9 +85,6 @@ protected:
 private:
     static const int MAX = HttpEnums::HEAD__MAX_VALUE + HttpEnums::MAX_CUSTOM_HEADERS;
 
-    // All of these are indexed by the relative position of the header field in the message
-    static const int MAX_HEADER_LENGTH = 4096; // Based on max cookie size of some browsers
-
     void parse_header_block();
     int32_t find_next_header(const uint8_t* buffer, int32_t length, int32_t& num_seps);
     void parse_header_lines();
index 35881af7381622a7e8539ec48a601c5921ae10ae..ff7dc6f1e5a6a8fa512c14a67b657603e04010a4 100755 (executable)
@@ -241,8 +241,8 @@ const RuleMap HttpModule::http_events[] =
                                         "oversize_dir_length parameter" },
     { EVENT_LARGE_CHUNK,                "chunk length exceeds configured maximum_chunk_length" },
     { EVENT_WEBROOT_DIR,                "URI path includes /../ that goes above the root directory" },
-    { EVENT_LONG_HDR,                   "HTTP header line exceeds 4096 bytes" },
-    { EVENT_MAX_HEADERS,                "HTTP message has more than 200 header fields" },
+    { EVENT_LONG_HDR,                   "HTTP header line exceeds maximum_header_length option bytes" },
+    { EVENT_MAX_HEADERS,                "HTTP message has more than maximum_headers option header fields" },
     { EVENT_MULTIPLE_CONTLEN,           "HTTP message has more than one Content-Length header value" },
     { EVENT_MULTIPLE_HOST_HDRS,         "Host header field appears more than once or has multiple values" },
     { EVENT_LONG_HOSTNAME,              "length of HTTP Host header field value exceeds maximum_host_length option" },