From: Tom Peters (thopeter) Date: Tue, 4 Oct 2022 16:23:16 +0000 (+0000) Subject: Pull request #3608: allowed and disallowed methods X-Git-Tag: 3.1.43.0~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=450b4e8af37669e2b4c954002745974c9bb637f6;p=thirdparty%2Fsnort3.git Pull request #3608: allowed and disallowed methods Merge in SNORT/snort3 from ~ADMAMOLE/snort3:method to master Squashed commit of the following: commit 62f3acf8011d7002eca476b34764e12f8a60edb5 Author: Adrian Mamolea Date: Thu Aug 18 11:19:30 2022 -0400 http_inspect: allowed and disallowed methods --- diff --git a/doc/reference/builtin_stubs.txt b/doc/reference/builtin_stubs.txt index 00d475f2d..8f60f6c5d 100644 --- a/doc/reference/builtin_stubs.txt +++ b/doc/reference/builtin_stubs.txt @@ -1326,6 +1326,10 @@ HTTP message Request-Line longer than 63780 bytes HTTP/2 preface received instead of an HTTP/1 method +119:287 + +HTTP request method is not on allowed methods list or is on disallowed methods list. + 121:1 Invalid flag set on HTTP/2 frame header diff --git a/doc/user/http_inspect.txt b/doc/user/http_inspect.txt index b0f07f994..bdcb66ba0 100755 --- a/doc/user/http_inspect.txt +++ b/doc/user/http_inspect.txt @@ -130,6 +130,27 @@ depth parameter entirely because that is the default. These limits have no effect on how much data is forwarded to file processing. +===== allowed_methods and disallowed_methods + +When either of these options are set, HTTP inspector will check if the method +in the HTTP request is allowed and if not raise alert 119:287. You can either +define a list of allowed methods or a list of disallowed methods. Defining +both is a configuration error. When a list of disallowed methods is defined, +any method not present on that list is implicitly allowed. Methods on either +of these lists are considered known methods and will not raise alert 119:31. +For example if configured for: + + allowed_methods = "GET,PUT,BLUE" + +HTTP inspector will raise 119:287 for POST and RED, no alert 119:31 will +be raised for BLUE, and 119:31 will be raised for RED. +If configured for + + disallowed_methods = "POST,RED" + +HTTP inspector will raise 119:287 for POST and RED, 119:31 for BLUE, and +no alert 119:31 will be raised for RED. + ===== script_detection Script detection is a feature that enables Snort to more quickly detect and diff --git a/src/service_inspectors/http_inspect/http_enum.h b/src/service_inspectors/http_inspect/http_enum.h index ffbdc80ec..487a3efd0 100755 --- a/src/service_inspectors/http_inspect/http_enum.h +++ b/src/service_inspectors/http_inspect/http_enum.h @@ -299,6 +299,8 @@ enum Infraction INF_INVALID_SUBVERSION = 133, INF_VERSION_0 = 134, INF_GZIP_FEXTRA = 135, + INF_METHOD_NOT_ON_ALLOWED_LIST = 136, + INF_METHOD_ON_DISALLOWED_LIST = 137, INF__MAX_VALUE }; @@ -445,6 +447,7 @@ enum EventSid EVENT_PARTIAL_START = 284, EVENT_REQ_TOO_LONG = 285, EVENT_UNEXPECTED_H2_PREFACE = 286, + EVENT_DISALLOWED_METHOD = 287, EVENT__MAX_VALUE }; diff --git a/src/service_inspectors/http_inspect/http_module.cc b/src/service_inspectors/http_inspect/http_module.cc index a5ac07f13..672d88377 100755 --- a/src/service_inspectors/http_inspect/http_module.cc +++ b/src/service_inspectors/http_inspect/http_module.cc @@ -175,6 +175,12 @@ const Parameter HttpModule::http_params[] = "make HTTP/2 request message bodies available for application detection " "(detection requires AppId)" }, + { "allowed_methods", Parameter::PT_STRING, nullptr, nullptr, + "list of allowed methods" }, + + { "disallowed_methods", Parameter::PT_STRING, nullptr, nullptr, + "list of disallowed methods" }, + #ifdef REG_TEST { "test_input", Parameter::PT_BOOL, nullptr, "false", "read HTTP messages from text file" }, @@ -234,6 +240,14 @@ bool HttpModule::begin(const char* fqn, int, SnortConfig*) return true; } +static void store_tokens(Value& val, std::set& methods) +{ + val.set_first_token(); + std::string tok; + while (val.get_next_csv_token(tok)) + methods.insert(tok); +} + bool HttpModule::set(const char*, Value& val, SnortConfig*) { if (val.is("request_depth")) @@ -424,6 +438,10 @@ bool HttpModule::set(const char*, Value& val, SnortConfig*) { params->publish_request_body = val.get_bool(); } + else if (val.is("allowed_methods")) + store_tokens(val, params->allowed_methods); + else if (val.is("disallowed_methods")) + store_tokens(val, params->disallowed_methods); #ifdef REG_TEST else if (val.is("test_input")) @@ -484,6 +502,9 @@ bool HttpModule::end(const char* fqn, int, SnortConfig*) if (strcmp(fqn, "http_inspect")) return true; + if (!params->allowed_methods.empty() && !params->disallowed_methods.empty()) + ParseError("allowed methods can't be used in conjunction with disallowed methods"); + if (!params->uri_param.utf8 && params->uri_param.utf8_bare_byte) { ParseWarning(WARN_CONF, "Meaningless to do bare byte when not doing UTF-8"); diff --git a/src/service_inspectors/http_inspect/http_module.h b/src/service_inspectors/http_inspect/http_module.h index 7b0070c81..455c8bcc6 100755 --- a/src/service_inspectors/http_inspect/http_module.h +++ b/src/service_inspectors/http_inspect/http_module.h @@ -21,6 +21,7 @@ #define HTTP_MODULE_H #include +#include #include #include @@ -121,6 +122,9 @@ public: // any custom headers mapped with the their respective Header IDs. StrCode header_list[HttpEnums::HEAD__MAX_VALUE + HttpEnums::MAX_CUSTOM_HEADERS + 1] = {}; + std::set allowed_methods; + std::set disallowed_methods; + #ifdef REG_TEST int64_t print_amount = 1200; diff --git a/src/service_inspectors/http_inspect/http_msg_request.cc b/src/service_inspectors/http_inspect/http_msg_request.cc index afc591d2f..1895673a4 100644 --- a/src/service_inspectors/http_inspect/http_msg_request.cc +++ b/src/service_inspectors/http_inspect/http_msg_request.cc @@ -257,7 +257,36 @@ void HttpMsgRequest::gen_events() } } - if (method_id == METH__OTHER) + bool known_method = false; + assert(method.length() > 0); + if (!params->allowed_methods.empty() or !params->disallowed_methods.empty()) + { + string method_str((const char*)method.start(), method.length()); + + if (!params->allowed_methods.empty()) + { + const set::iterator it = params->allowed_methods.find(method_str); + if (it == params->allowed_methods.end()) + { + add_infraction(INF_METHOD_NOT_ON_ALLOWED_LIST); + create_event(EVENT_DISALLOWED_METHOD); + } + else + known_method = true; + } + else + { + const set::iterator it = params->disallowed_methods.find(method_str); + if (it != params->disallowed_methods.end()) + { + add_infraction(INF_METHOD_ON_DISALLOWED_LIST); + create_event(EVENT_DISALLOWED_METHOD); + known_method = true; + } + } + } + + if (method_id == METH__OTHER && !known_method) create_event(EVENT_UNKNOWN_METHOD); if (uri && uri->get_scheme().length() > LONG_SCHEME_LENGTH) diff --git a/src/service_inspectors/http_inspect/http_tables.cc b/src/service_inspectors/http_inspect/http_tables.cc index ff7dc6f1e..e3242dfbc 100755 --- a/src/service_inspectors/http_inspect/http_tables.cc +++ b/src/service_inspectors/http_inspect/http_tables.cc @@ -350,6 +350,8 @@ const RuleMap HttpModule::http_events[] = { EVENT_PARTIAL_START, "partial start line" }, { EVENT_REQ_TOO_LONG, "HTTP message request line longer than 63780 bytes" }, { 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" }, { 0, nullptr } }; diff --git a/src/service_inspectors/http_inspect/test/http_module_test.cc b/src/service_inspectors/http_inspect/test/http_module_test.cc index 3bbd67111..de5324408 100755 --- a/src/service_inspectors/http_inspect/test/http_module_test.cc +++ b/src/service_inspectors/http_inspect/test/http_module_test.cc @@ -46,6 +46,7 @@ void ParseError(const char*, ...) {} void Value::get_bits(std::bitset<256ul>&) const {} void Value::set_first_token() {} +bool Value::get_next_csv_token(std::string&) { return false; } bool Value::get_next_token(std::string& ) { return false; } int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } diff --git a/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc b/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc index 62fa8f0f3..f6f6e17e5 100755 --- a/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc +++ b/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc @@ -42,6 +42,7 @@ void ParseWarning(WarningGroup, const char*, ...) {} void ParseError(const char*, ...) {} void Value::get_bits(std::bitset<256ul>&) const {} void Value::set_first_token() {} +bool Value::get_next_csv_token(std::string&) { return false; } bool Value::get_next_token(std::string& ) { return false; } int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } LiteralSearch::Handle* LiteralSearch::setup() { return nullptr; }