From: Adrian Mamolea Date: Wed, 3 Aug 2022 19:14:42 +0000 (-0400) Subject: http_inspect: http_num_cookies rule option X-Git-Tag: 3.1.40.0~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=357d8293e09773f2c95dedfc142a40df8e7a769e;p=thirdparty%2Fsnort3.git http_inspect: http_num_cookies rule option --- diff --git a/src/service_inspectors/http_inspect/http_api.cc b/src/service_inspectors/http_inspect/http_api.cc index 604ed780e..5d1e59a3f 100644 --- a/src/service_inspectors/http_inspect/http_api.cc +++ b/src/service_inspectors/http_inspect/http_api.cc @@ -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, diff --git a/src/service_inspectors/http_inspect/http_enum.h b/src/service_inspectors/http_inspect/http_enum.h index 759d7ccf7..0af7b2823 100755 --- a/src/service_inspectors/http_inspect/http_enum.h +++ b/src/service_inspectors/http_inspect/http_enum.h @@ -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 diff --git a/src/service_inspectors/http_inspect/http_inspect.cc b/src/service_inspectors/http_inspect/http_inspect.cc index 467bfb9c2..71f9cba4a 100755 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -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 { diff --git a/src/service_inspectors/http_inspect/http_inspect.h b/src/service_inspectors/http_inspect/http_inspect.h index f247a0682..10f4772b4 100644 --- a/src/service_inspectors/http_inspect/http_inspect.h +++ b/src/service_inspectors/http_inspect/http_inspect.h @@ -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; diff --git a/src/service_inspectors/http_inspect/http_msg_head_shared.h b/src/service_inspectors/http_inspect/http_msg_head_shared.h index 3fbb64dca..61db916b4 100755 --- a/src/service_inspectors/http_inspect/http_msg_head_shared.h +++ b/src/service_inspectors/http_inspect/http_msg_head_shared.h @@ -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 headers_present = 0; void extract_filename_from_content_disposition(); diff --git a/src/service_inspectors/http_inspect/http_msg_header.cc b/src/service_inspectors/http_inspect/http_msg_header.cc index e6053a6f4..eadaf2a2d 100755 --- a/src/service_inspectors/http_inspect/http_msg_header.cc +++ b/src/service_inspectors/http_inspect/http_msg_header.cc @@ -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) && diff --git a/src/service_inspectors/http_inspect/http_msg_header.h b/src/service_inspectors/http_inspect/http_msg_header.h index 13d9249c5..739f8129d 100644 --- a/src/service_inspectors/http_inspect/http_msg_header.h +++ b/src/service_inspectors/http_inspect/http_msg_header.h @@ -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; diff --git a/src/service_inspectors/http_inspect/http_msg_section.cc b/src/service_inspectors/http_inspect/http_msg_section.cc index 73acad3ce..71afc0a29 100644 --- a/src/service_inspectors/http_inspect/http_msg_section.cc +++ b/src/service_inspectors/http_inspect/http_msg_section.cc @@ -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 diff --git a/src/service_inspectors/http_inspect/http_msg_section.h b/src/service_inspectors/http_inspect/http_msg_section.h index 8b1a6fcdd..0c0290622 100644 --- a/src/service_inspectors/http_inspect/http_msg_section.h +++ b/src/service_inspectors/http_inspect/http_msg_section.h @@ -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; diff --git a/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc b/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc index 7a11aba2e..3b9d4f5ac 100644 --- a/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc +++ b/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc @@ -43,7 +43,7 @@ using namespace HttpEnums; THREAD_LOCAL std::array 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; diff --git a/src/service_inspectors/http_inspect/ips_http_num_hdrs.h b/src/service_inspectors/http_inspect/ips_http_num_hdrs.h index ccb3f8306..8272f1ffa 100644 --- a/src/service_inspectors/http_inspect/ips_http_num_hdrs.h +++ b/src/service_inspectors/http_inspect/ips_http_num_hdrs.h @@ -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 {