]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
http_inspect: http_num_cookies rule option
authorAdrian Mamolea <admamole@cisco.com>
Wed, 3 Aug 2022 19:14:42 +0000 (15:14 -0400)
committerAdrian Mamolea <admamole@cisco.com>
Mon, 15 Aug 2022 12:09:02 +0000 (08:09 -0400)
src/service_inspectors/http_inspect/http_api.cc
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/http_inspect/http_inspect.h
src/service_inspectors/http_inspect/http_msg_head_shared.h
src/service_inspectors/http_inspect/http_msg_header.cc
src/service_inspectors/http_inspect/http_msg_header.h
src/service_inspectors/http_inspect/http_msg_section.cc
src/service_inspectors/http_inspect/http_msg_section.h
src/service_inspectors/http_inspect/ips_http_num_hdrs.cc
src/service_inspectors/http_inspect/ips_http_num_hdrs.h

index 604ed780ede0324e66f1589ab32d486fee14d155..5d1e59a3ff046458845b492e5e3733432b796884 100644 (file)
@@ -105,6 +105,7 @@ extern const BaseApi* ips_http_cookie;
 extern const BaseApi* ips_http_header;
 extern const BaseApi* ips_http_header_test;
 extern const BaseApi* ips_http_method;
+extern const BaseApi* ips_http_num_cookies;
 extern const BaseApi* ips_http_num_headers;
 extern const BaseApi* ips_http_num_trailers;
 extern const BaseApi* ips_http_param;
@@ -137,6 +138,7 @@ const BaseApi* sin_http[] =
     ips_http_header,
     ips_http_header_test,
     ips_http_method,
+    ips_http_num_cookies,
     ips_http_num_headers,
     ips_http_num_trailers,
     ips_http_param,
index 759d7ccf7cea42337e93e04d9a1445e7a6b4d710..0af7b2823d9304819ae0cf4492c8f1311341c510 100755 (executable)
@@ -58,7 +58,7 @@ enum HTTP_RULE_OPT { HTTP_BUFFER_CLIENT_BODY = 1, HTTP_BUFFER_COOKIE, HTTP_BUFFE
     HTTP_BUFFER_TRAILER, HTTP_BUFFER_TRUE_IP, HTTP_BUFFER_URI, HTTP_BUFFER_VERSION,
     BUFFER_JS_DATA, BUFFER_VBA_DATA , HTTP__BUFFER_MAX = BUFFER_VBA_DATA,
     HTTP_RANGE_NUM_HDRS, HTTP_RANGE_NUM_TRAILERS, HTTP_VERSION_MATCH,
-    HTTP_HEADER_TEST, HTTP_TRAILER_TEST, HTTP__MAX_RULE_OPTION };
+    HTTP_HEADER_TEST, HTTP_TRAILER_TEST, HTTP_RANGE_NUM_COOKIES, HTTP__MAX_RULE_OPTION };
 
 // Peg counts
 // This enum must remain synchronized with HttpModule::peg_names[] in http_tables.cc
index 467bfb9c2cc8efb904e4d3c2758e28d5185b2e4f..71f9cba4a66f4042fbeaaf82791b6c8af83c998e 100755 (executable)
@@ -314,11 +314,22 @@ int32_t HttpInspect::http_get_num_headers(Packet* p,
     const HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
 
     if (current_section == nullptr)
-        return STAT_NOT_COMPUTE;
+        return STAT_NOT_PRESENT;
 
     return current_section->get_num_headers(buffer_info);
 }
 
+int32_t HttpInspect::http_get_num_cookies(Packet* p,
+    const HttpBufferInfo& buffer_info) const
+{
+    const HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
+
+    if (current_section == nullptr)
+        return STAT_NOT_PRESENT;
+
+    return current_section->get_num_cookies(buffer_info);
+}
+
 VersionId HttpInspect::http_get_version_id(Packet* p,
     const HttpBufferInfo& buffer_info) const
 {
index f247a068236d0b2bbcc241c8385dfdf09c1e26ff..10f4772b4c665ce4257b472a1c63e9e3d1e68744 100644 (file)
@@ -52,6 +52,7 @@ public:
     const Field& http_get_param_buf(Cursor& c, snort::Packet* p,
         const HttpParam& param) const;
     int32_t http_get_num_headers(snort::Packet* p, const HttpBufferInfo& buffer_info) const;
+    int32_t http_get_num_cookies(snort::Packet* p, const HttpBufferInfo& buffer_info) const;
     HttpEnums::VersionId http_get_version_id(snort::Packet* p,
         const HttpBufferInfo& buffer_info) const;
     HttpCommon::SectionType get_type_expected(snort::Flow* flow, HttpCommon::SourceId source_id) const override;
index 3fbb64dcaf78f5a24e747b73cb9650ac8158bd5f..61db916b4d1570f0db4436269a82381cb5c07d76 100755 (executable)
@@ -73,6 +73,10 @@ protected:
     // Do a case insensitive search for "boundary=" in a Field
     static bool boundary_present(const Field& field);
 
+    Field* header_line = nullptr;
+    HttpEnums::HeaderId* header_name_id = nullptr;
+    int32_t num_headers = HttpCommon::STAT_NOT_COMPUTE;
+
 #ifdef REG_TEST
     void print_headers(FILE* output);
 #endif
@@ -93,15 +97,12 @@ private:
     Field classic_raw_header;    // raw headers with cookies spliced out
     Field classic_norm_header;   // URI normalization applied
     Field classic_norm_cookie;   // URI normalization applied to concatenated cookie values
-    Field* header_line = nullptr;
     Field* header_name = nullptr;
-    HttpEnums::HeaderId* header_name_id = nullptr;
     Field* header_value = nullptr;
 
     NormalizedHeader* get_header_node(HttpEnums::HeaderId k) const;
     NormalizedHeader* norm_heads = nullptr;
 
-    int32_t num_headers = HttpCommon::STAT_NOT_COMPUTE;
     std::bitset<MAX> headers_present = 0;
 
     void extract_filename_from_content_disposition();
index e6053a6f49d034944f642dd4ef9dc1f49a06b41d..eadaf2a2d7fc860858156e7479b3d4a6353ff79c 100755 (executable)
@@ -138,6 +138,29 @@ const Field& HttpMsgHeader::get_true_ip_addr()
     return true_ip_addr;
 }
 
+int32_t HttpMsgHeader::get_num_cookies()
+{
+    if (num_cookies != STAT_NOT_COMPUTE)
+        return num_cookies;
+
+    num_cookies = 0;
+    for (int j=0; j < num_headers; j++)
+    {
+        if (header_name_id[j] == HEAD_SET_COOKIE)
+            num_cookies++;
+        else if (header_name_id[j] == HEAD_COOKIE)
+        {
+            const uint8_t* lim = header_line[j].start() + header_line[j].length();
+            for (const uint8_t* p = header_line[j].start();  p < lim; p++)
+                if (*p == ';')
+                    num_cookies++;
+            num_cookies++;
+        }
+    }
+
+    return num_cookies;
+}
+
 void HttpMsgHeader::gen_events()
 {
     if ((get_header_count(HEAD_CONTENT_LENGTH) > 0) &&
index 13d9249c57a4de0b8002f3431e62fac5a7fa117a..739f8129d6a5c8ddcca3a1846cecfad73d072bcd 100644 (file)
@@ -46,6 +46,7 @@ public:
     void publish() override;
     const Field& get_true_ip();
     const Field& get_true_ip_addr();
+    int32_t get_num_cookies();
 
     // The multi_file_processing_id is unique for each file transferred within a single connection
     // and is used by file processing to store partially processed file contexts in the flow data.
@@ -65,6 +66,7 @@ private:
 
     Field true_ip;
     Field true_ip_addr;
+    int32_t num_cookies = HttpCommon::STAT_NOT_COMPUTE;
 
     uint64_t multi_file_processing_id = 0;
 
index 73acad3cecaf18c3464fd1d3bf7f6b02ac346c30..71afc0a294eaff8a66780b4e7a9eb995961a8a08 100644 (file)
@@ -415,11 +415,23 @@ int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const
         (HttpMsgHeadShared*)trailer[buffer_side]:
         (HttpMsgHeadShared*)header[buffer_side] ;
     if (head == nullptr)
-        return HttpCommon::STAT_NOT_COMPUTE;
+        return HttpCommon::STAT_NO_SOURCE;
 
     return head->get_num_headers();
 }
 
+int32_t HttpMsgSection::get_num_cookies(const HttpBufferInfo& buf) const
+{
+    // buffer_side replaces source_id for rule options that support the request option
+    const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
+
+    HttpMsgHeader* head = header[buffer_side];
+    if (head == nullptr)
+        return HttpCommon::STAT_NO_SOURCE;
+
+    return head->get_num_cookies();
+}
+
 VersionId HttpMsgSection::get_version_id(const HttpBufferInfo& buf) const
 {
     // buffer_side replaces source_id for buffers that support the request option
index 8b1a6fcdd73d9831f60bd65e30726ca9388f3476..0c029062273298ad1aee0c84292322a543cfe108 100644 (file)
@@ -87,6 +87,7 @@ public:
 
     uint64_t get_transaction_id() { return trans_num; }
     int32_t get_num_headers(const HttpBufferInfo& buf) const;
+    int32_t get_num_cookies(const HttpBufferInfo& buf) const;
     HttpEnums::VersionId get_version_id(const HttpBufferInfo& buf) const;
 
     HttpMsgSection* next = nullptr;
index 7a11aba2e3f705c26a57b6dff785d91534cf6ccd..3b9d4f5ac339b41737d186d1a22f43ee042e9343 100644 (file)
@@ -43,7 +43,7 @@ using namespace HttpEnums;
 
 THREAD_LOCAL std::array<ProfileStats, NUM_HDRS_PSI_MAX> HttpNumHdrsRuleOptModule::http_num_hdrs_ps;
 
-const std::string hdrs_num_range = "0:" + std::to_string(HttpMsgHeadShared::MAX_HEADERS);
+static const char* num_range = "0:65535";
 
 bool HttpNumHdrsRuleOptModule::begin(const char*, int, SnortConfig*)
 {
@@ -51,6 +51,8 @@ bool HttpNumHdrsRuleOptModule::begin(const char*, int, SnortConfig*)
     range.init();
     if (rule_opt_index == HTTP_RANGE_NUM_HDRS)
         inspect_section = IS_FLEX_HEADER;
+    else if (rule_opt_index == HTTP_RANGE_NUM_COOKIES)
+        inspect_section = IS_HEADER;
     else
     {
         inspect_section = IS_TRAILER;
@@ -63,8 +65,8 @@ bool HttpNumHdrsRuleOptModule::begin(const char*, int, SnortConfig*)
 bool HttpNumHdrsRuleOptModule::set(const char*, Value& v, SnortConfig*)
 {
     if (v.is("~range"))
-        return range.validate(v.get_string(), hdrs_num_range.c_str());
-    
+        return range.validate(v.get_string(), num_range);
+
     return HttpRuleOptModule::set(nullptr, v, nullptr);
 }
 
@@ -94,8 +96,10 @@ IpsOption::EvalStatus HttpNumHdrsIpsOption::eval(Cursor&, Packet* p)
     if (hi == nullptr)
         return NO_MATCH;
 
-    const int32_t num_lines = hi->http_get_num_headers(p, buffer_info);
-    if (num_lines != HttpCommon::STAT_NOT_PRESENT && range.eval(num_lines))
+    const int32_t count = (idx == NUM_HDRS_PSI_COOKIES) ?
+        hi->http_get_num_cookies(p, buffer_info) :
+        hi->http_get_num_headers(p, buffer_info);
+    if (count != HttpCommon::STAT_NOT_PRESENT && range.eval(count))
         return MATCH;
 
     return NO_MATCH;
@@ -111,7 +115,7 @@ IpsOption::EvalStatus HttpNumHdrsIpsOption::eval(Cursor&, Packet* p)
 
 static const Parameter http_num_hdrs_params[] =
 {
-    { "~range", Parameter::PT_INTERVAL, hdrs_num_range.c_str(), nullptr,
+    { "~range", Parameter::PT_INTERVAL, num_range, nullptr,
         "check that number of headers of current buffer are in given range" },
     { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
         "match against the version from the request message even when examining the response" },
@@ -194,9 +198,57 @@ static const IpsApi num_trailers_api =
     nullptr
 };
 
+//-------------------------------------------------------------------------
+// num_cookies
+//-------------------------------------------------------------------------
+#undef IPS_OPT
+#define IPS_OPT "http_num_cookies"
+#undef IPS_HELP
+#define IPS_HELP "rule option to perform range check on number of cookies"
+
+static const Parameter http_num_cookies_params[] =
+{
+    { "~range", Parameter::PT_INTERVAL, num_range, nullptr,
+        "check that number of cookies of current header are in given range" },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the version from the request message even when examining the response" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static Module* num_cookies_mod_ctor()
+{
+    return new HttpNumHdrsRuleOptModule(IPS_OPT, IPS_HELP, HTTP_RANGE_NUM_COOKIES, CAT_NONE,
+        NUM_HDRS_PSI_COOKIES, http_num_cookies_params);
+}
+
+static const IpsApi num_cookies_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        num_cookies_mod_ctor,
+        HttpNumHdrsRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpNumHdrsIpsOption::opt_ctor,
+    HttpNumHdrsIpsOption::opt_dtor,
+    nullptr
+};
+
 //-------------------------------------------------------------------------
 // plugins
 //-------------------------------------------------------------------------
 const BaseApi* ips_http_num_headers = &num_headers_api.base;
 const BaseApi* ips_http_num_trailers = &num_trailers_api.base;
-
+const BaseApi* ips_http_num_cookies = &num_cookies_api.base;
index ccb3f83065facd5fc88b3b36a3f4afcbf9126f4c..8272f1ffa5249e32fc63d6e4dd5911c83d95cea5 100644 (file)
@@ -31,7 +31,7 @@
 #include "http_enum.h"
 #include "ips_http.h"
 
-enum NumHdrsPsIdx { NUM_HDRS_PSI_HDRS, NUM_HDRS_PSI_TRAILERS, NUM_HDRS_PSI_MAX };
+enum NumHdrsPsIdx { NUM_HDRS_PSI_HDRS, NUM_HDRS_PSI_TRAILERS, NUM_HDRS_PSI_COOKIES, NUM_HDRS_PSI_MAX };
 
 class HttpNumHdrsRuleOptModule : public HttpRuleOptModule
 {