From: Tom Peters (thopeter) Date: Wed, 14 Sep 2022 22:13:11 +0000 (+0000) Subject: Pull request #3582: Header length rule options X-Git-Tag: 3.1.42.0~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e6e37b925bf493267610de8618ef3dd17d50eed;p=thirdparty%2Fsnort3.git Pull request #3582: Header length rule options Merge in SNORT/snort3 from ~ADMAMOLE/snort3:header_length to master Squashed commit of the following: commit 95bfb786b9c1cc5912a90e0aeaf1ea57f1532b4b Author: Adrian Mamolea Date: Wed Aug 31 12:16:43 2022 -0400 http_inspect: http_max_header_line and http_max_trailer_line rule options --- diff --git a/doc/user/http_inspect.txt b/doc/user/http_inspect.txt index 298bedec0..b0f07f994 100755 --- a/doc/user/http_inspect.txt +++ b/doc/user/http_inspect.txt @@ -780,6 +780,11 @@ and decompress_vba options enabled. These are range-based rule options used to check the number of headers and trailers, respectively. +===== http_max_header_line and http_max_trailer_line + +These are range-based rule options used to check the longest line in +request and response headers and trailers, respectively. + ===== http_num_cookies This is a range-based rule option that checks the number of cookies. In a diff --git a/src/service_inspectors/http_inspect/http_api.cc b/src/service_inspectors/http_inspect/http_api.cc index 5d1e59a3f..93064df4c 100644 --- a/src/service_inspectors/http_inspect/http_api.cc +++ b/src/service_inspectors/http_inspect/http_api.cc @@ -104,6 +104,8 @@ extern const BaseApi* ips_http_client_body; extern const BaseApi* ips_http_cookie; extern const BaseApi* ips_http_header; extern const BaseApi* ips_http_header_test; +extern const BaseApi* ips_http_max_header_line; +extern const BaseApi* ips_http_max_trailer_line; extern const BaseApi* ips_http_method; extern const BaseApi* ips_http_num_cookies; extern const BaseApi* ips_http_num_headers; @@ -137,6 +139,8 @@ const BaseApi* sin_http[] = ips_http_cookie, ips_http_header, ips_http_header_test, + ips_http_max_header_line, + ips_http_max_trailer_line, ips_http_method, ips_http_num_cookies, ips_http_num_headers, diff --git a/src/service_inspectors/http_inspect/http_enum.h b/src/service_inspectors/http_inspect/http_enum.h index 0af7b2823..b4acfaec4 100755 --- a/src/service_inspectors/http_inspect/http_enum.h +++ b/src/service_inspectors/http_inspect/http_enum.h @@ -58,7 +58,8 @@ 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_RANGE_NUM_COOKIES, HTTP__MAX_RULE_OPTION }; + HTTP_HEADER_TEST, HTTP_TRAILER_TEST, HTTP_RANGE_NUM_COOKIES, HTTP_RANGE_MAX_HEADER_LINE, + HTTP_RANGE_MAX_TRAILER_LINE, 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 71f9cba4a..433525f11 100755 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -319,6 +319,17 @@ int32_t HttpInspect::http_get_num_headers(Packet* p, return current_section->get_num_headers(buffer_info); } +int32_t HttpInspect::http_get_max_header_line(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_max_header_line(buffer_info); +} + int32_t HttpInspect::http_get_num_cookies(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 10f4772b4..93790e178 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_max_header_line(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; diff --git a/src/service_inspectors/http_inspect/http_msg_head_shared.cc b/src/service_inspectors/http_inspect/http_msg_head_shared.cc index ee3ea1b2e..dcc689cd4 100755 --- a/src/service_inspectors/http_inspect/http_msg_head_shared.cc +++ b/src/service_inspectors/http_inspect/http_msg_head_shared.cc @@ -117,6 +117,7 @@ void HttpMsgHeadShared::parse_header_block() { int32_t bytes_used = 0; num_headers = 0; + max_header_line = 0; int32_t num_seps; // The number of header lines in a message may be zero @@ -131,6 +132,10 @@ void HttpMsgHeadShared::parse_header_block() assert(num_headers < session_data->num_head_lines[source_id]); const int32_t header_length = find_next_header(msg_text.start() + bytes_used, msg_text.length() - bytes_used, num_seps); + if (header_length > max_header_line) + { + max_header_line = header_length; + } header_line[num_headers].set(header_length, msg_text.start() + bytes_used + num_seps); if (header_line[num_headers].length() > params->maximum_header_length) { 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 144aa9761..d7ea2da2c 100755 --- a/src/service_inspectors/http_inspect/http_msg_head_shared.h +++ b/src/service_inspectors/http_inspect/http_msg_head_shared.h @@ -60,6 +60,7 @@ public: uint64_t get_file_cache_index(); const Field& get_content_disposition_filename(); int32_t get_num_headers() const { return num_headers; } + int32_t get_max_header_line() const { return max_header_line; } int32_t get_content_type(); protected: @@ -77,6 +78,7 @@ protected: Field* header_line = nullptr; HttpEnums::HeaderId* header_name_id = nullptr; int32_t num_headers = HttpCommon::STAT_NOT_COMPUTE; + int32_t max_header_line = HttpCommon::STAT_NOT_COMPUTE; #ifdef REG_TEST void print_headers(FILE* output); diff --git a/src/service_inspectors/http_inspect/http_msg_section.cc b/src/service_inspectors/http_inspect/http_msg_section.cc index 71afc0a29..842c87eb7 100644 --- a/src/service_inspectors/http_inspect/http_msg_section.cc +++ b/src/service_inspectors/http_inspect/http_msg_section.cc @@ -163,7 +163,7 @@ const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, ui const Field& HttpMsgSection::get_classic_buffer(const HttpBufferInfo& buf) { - // buffer_side replaces source_id for buffers that support the request option + // 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; switch (buf.type) @@ -408,7 +408,7 @@ const Field& HttpMsgSection::get_param_buffer(Cursor& c, const HttpParam& param) int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const { - // buffer_side replaces source_id for buffers that support the request option + // 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; const HttpMsgHeadShared* const head = (buf.type == HTTP_RANGE_NUM_TRAILERS) ? @@ -420,6 +420,20 @@ int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const return head->get_num_headers(); } +int32_t HttpMsgSection::get_max_header_line(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; + + const HttpMsgHeadShared* const head = (buf.type == HTTP_RANGE_MAX_TRAILER_LINE) ? + (HttpMsgHeadShared*)trailer[buffer_side]: + (HttpMsgHeadShared*)header[buffer_side] ; + if (head == nullptr) + return HttpCommon::STAT_NO_SOURCE; + + return head->get_max_header_line(); +} + int32_t HttpMsgSection::get_num_cookies(const HttpBufferInfo& buf) const { // buffer_side replaces source_id for rule options that support the request option @@ -434,7 +448,7 @@ int32_t HttpMsgSection::get_num_cookies(const HttpBufferInfo& buf) const VersionId HttpMsgSection::get_version_id(const HttpBufferInfo& buf) const { - // buffer_side replaces source_id for buffers that support the request option + // 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; HttpMsgStart* start = (buffer_side == SRC_CLIENT) ? (HttpMsgStart*)request : (HttpMsgStart*)status; diff --git a/src/service_inspectors/http_inspect/http_msg_section.h b/src/service_inspectors/http_inspect/http_msg_section.h index 0c0290622..bd34c9db7 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_max_header_line(const HttpBufferInfo& buf) const; int32_t get_num_cookies(const HttpBufferInfo& buf) const; HttpEnums::VersionId get_version_id(const HttpBufferInfo& buf) const; 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 5d2632a46..90d0e07f5 100644 --- a/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc +++ b/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc @@ -101,35 +101,29 @@ IpsOption::EvalStatus HttpRangeIpsOption::eval(Cursor&, Packet* p) } //------------------------------------------------------------------------- -// num_header_lines +// max_header_line //------------------------------------------------------------------------- #undef IPS_OPT -#define IPS_OPT "http_num_headers" +#define IPS_OPT "http_max_header_line" #undef IPS_HELP -#define IPS_HELP "rule option to perform range check on number of headers" +#define IPS_HELP "rule option to perform range check on longest header line" -static const Parameter http_num_hdrs_params[] = +static const Parameter http_max_header_line_params[] = { { "~range", Parameter::PT_INTERVAL, "0:65535", nullptr, - "check that number of headers of current buffer are in given range" }, + "check that longest line of current header is in given range" }, { "request", Parameter::PT_IMPLIED, nullptr, nullptr, "match against the version from the request message even when examining the response" }, - { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, - "this rule is limited to examining HTTP message headers" }, - { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, - "parts of this rule examine HTTP message body" }, - { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, - "parts of this rule examine HTTP message trailers" }, { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; -static Module* num_hdrs_mod_ctor() +static Module* max_header_line_mod_ctor() { - return new HttpNumRuleOptModule(IPS_OPT, IPS_HELP, - http_num_hdrs_params); + return new HttpNumRuleOptModule(IPS_OPT, IPS_HELP, + http_max_header_line_params); } -static const IpsApi num_headers_api = +static const IpsApi max_header_line_api = { { PT_IPS_OPTION, @@ -140,7 +134,7 @@ static const IpsApi num_headers_api = API_OPTIONS, IPS_OPT, IPS_HELP, - num_hdrs_mod_ctor, + max_header_line_mod_ctor, HttpRangeRuleOptModule::mod_dtor }, OPT_TYPE_DETECTION, @@ -149,26 +143,35 @@ static const IpsApi num_headers_api = nullptr, nullptr, nullptr, - HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor, + HttpNumIpsOption<&HttpInspect::http_get_max_header_line>::opt_ctor, HttpRangeIpsOption::opt_dtor, nullptr }; //------------------------------------------------------------------------- -// num_trailer_lines +// max_trailer_line //------------------------------------------------------------------------- #undef IPS_OPT -#define IPS_OPT "http_num_trailers" +#define IPS_OPT "http_max_trailer_line" #undef IPS_HELP -#define IPS_HELP "rule option to perform range check on number of trailers" +#define IPS_HELP "rule option to perform range check on longest trailer line" -static Module* num_trailers_mod_ctor() +static const Parameter http_max_trailer_line_params[] = { - return new HttpNumRuleOptModule(IPS_OPT, IPS_HELP, - http_num_hdrs_params); + { "~range", Parameter::PT_INTERVAL, "0:65535", nullptr, + "check that longest line of current trailer is 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* max_trailer_line_mod_ctor() +{ + return new HttpNumRuleOptModule(IPS_OPT, IPS_HELP, + http_max_trailer_line_params); } -static const IpsApi num_trailers_api = +static const IpsApi max_trailer_line_api = { { PT_IPS_OPTION, @@ -179,7 +182,7 @@ static const IpsApi num_trailers_api = API_OPTIONS, IPS_OPT, IPS_HELP, - num_trailers_mod_ctor, + max_trailer_line_mod_ctor, HttpRangeRuleOptModule::mod_dtor }, OPT_TYPE_DETECTION, @@ -188,7 +191,7 @@ static const IpsApi num_trailers_api = nullptr, nullptr, nullptr, - HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor, + HttpNumIpsOption<&HttpInspect::http_get_max_header_line>::opt_ctor, HttpRangeIpsOption::opt_dtor, nullptr }; @@ -241,9 +244,104 @@ static const IpsApi num_cookies_api = nullptr }; +//------------------------------------------------------------------------- +// num_header_lines +//------------------------------------------------------------------------- +#undef IPS_OPT +#define IPS_OPT "http_num_headers" +#undef IPS_HELP +#define IPS_HELP "rule option to perform range check on number of headers" + +static const Parameter http_num_hdrs_params[] = +{ + { "~range", Parameter::PT_INTERVAL, "0:65535", 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" }, + { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, + "this rule is limited to examining HTTP message headers" }, + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +static Module* num_hdrs_mod_ctor() +{ + return new HttpNumRuleOptModule(IPS_OPT, IPS_HELP, + http_num_hdrs_params); +} + +static const IpsApi num_headers_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + num_hdrs_mod_ctor, + HttpRangeRuleOptModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor, + HttpRangeIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// num_trailer_lines +//------------------------------------------------------------------------- +#undef IPS_OPT +#define IPS_OPT "http_num_trailers" +#undef IPS_HELP +#define IPS_HELP "rule option to perform range check on number of trailers" + +static Module* num_trailers_mod_ctor() +{ + return new HttpNumRuleOptModule(IPS_OPT, IPS_HELP, + http_num_hdrs_params); +} + +static const IpsApi num_trailers_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + num_trailers_mod_ctor, + HttpRangeRuleOptModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor, + HttpRangeIpsOption::opt_dtor, + nullptr +}; + //------------------------------------------------------------------------- // plugins //------------------------------------------------------------------------- +const BaseApi* ips_http_max_header_line = &max_header_line_api.base; +const BaseApi* ips_http_max_trailer_line = &max_trailer_line_api.base; +const BaseApi* ips_http_num_cookies = &num_cookies_api.base; 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;