From 328f29d7f456d793eb486de30b302294bb910f3c Mon Sep 17 00:00:00 2001 From: "Tom Peters (thopeter)" Date: Wed, 18 Oct 2017 13:50:56 -0400 Subject: [PATCH] Merge pull request #1046 in SNORT/snort3 from nhttp93 to master Squashed commit of the following: commit 8964af3ce07990e4f30562a64ddc4ba0bc9303d7 Author: Tom Peters Date: Tue Oct 10 12:10:01 2017 -0400 http_inspect: true IP enhancements --- doc/http_inspect.txt | 7 +++ .../http_inspect/http_api.cc | 3 ++ .../http_inspect/http_enum.h | 4 +- .../http_inspect/http_inspect.cc | 2 +- .../http_inspect/http_msg_header.cc | 41 +++++++++++---- .../http_inspect/http_msg_header.h | 2 + .../http_inspect/http_msg_section.cc | 5 ++ .../http_inspect/ips_http.cc | 51 +++++++++++++++++++ .../http_inspect/ips_http.h | 2 +- 9 files changed, 104 insertions(+), 13 deletions(-) diff --git a/doc/http_inspect.txt b/doc/http_inspect.txt index 6b93a9dfa..2d19e472f 100644 --- a/doc/http_inspect.txt +++ b/doc/http_inspect.txt @@ -403,6 +403,13 @@ will be concatenated into a comma-separated list. Normalization for http_cookie is the same URI-style normalization applied to http_header when no specific header is specified. +===== http_true_ip + +This provides the original IP address of the client sending the request as +it was stored by a proxy in the request message headers. Specifically it +is the last IP address listed in the X-Forwarded-For or True-Client-IP +header. If both headers are present the former is used. + ===== http_client_body This is the body of a request message such as POST or PUT. Normalization diff --git a/src/service_inspectors/http_inspect/http_api.cc b/src/service_inspectors/http_inspect/http_api.cc index 849e0f75c..0b18d384d 100644 --- a/src/service_inspectors/http_inspect/http_api.cc +++ b/src/service_inspectors/http_inspect/http_api.cc @@ -50,6 +50,7 @@ const char* HttpApi::classic_buffer_names[] = "http_stat_code", "http_stat_msg", "http_trailer", + "http_true_ip", "http_uri", "http_version", nullptr @@ -97,6 +98,7 @@ extern const BaseApi* ips_http_raw_uri; extern const BaseApi* ips_http_stat_code; extern const BaseApi* ips_http_stat_msg; extern const BaseApi* ips_http_trailer; +extern const BaseApi* ips_http_true_ip; extern const BaseApi* ips_http_uri; extern const BaseApi* ips_http_version; @@ -121,6 +123,7 @@ const BaseApi* sin_http[] = ips_http_stat_code, ips_http_stat_msg, ips_http_trailer, + ips_http_true_ip, ips_http_uri, ips_http_version, nullptr diff --git a/src/service_inspectors/http_inspect/http_enum.h b/src/service_inspectors/http_inspect/http_enum.h index a62b51926..3f31f3148 100644 --- a/src/service_inspectors/http_inspect/http_enum.h +++ b/src/service_inspectors/http_inspect/http_enum.h @@ -56,8 +56,8 @@ enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOT_COMPUTE=-14, SEC enum HTTP_BUFFER { HTTP_BUFFER_CLIENT_BODY = 1, HTTP_BUFFER_COOKIE, HTTP_BUFFER_HEADER, HTTP_BUFFER_METHOD, HTTP_BUFFER_RAW_BODY, HTTP_BUFFER_RAW_COOKIE, HTTP_BUFFER_RAW_HEADER, HTTP_BUFFER_RAW_REQUEST, HTTP_BUFFER_RAW_STATUS, HTTP_BUFFER_RAW_TRAILER, HTTP_BUFFER_RAW_URI, - HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG, HTTP_BUFFER_TRAILER, HTTP_BUFFER_URI, - HTTP_BUFFER_VERSION, HTTP_BUFFER_MAX }; + HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG, HTTP_BUFFER_TRAILER, HTTP_BUFFER_TRUE_IP, + HTTP_BUFFER_URI, HTTP_BUFFER_VERSION, HTTP_BUFFER_MAX }; // 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 a8335e3bc..f0d3fad95 100644 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -175,7 +175,7 @@ int HttpInspect::get_xtra_trueip(Flow* flow, uint8_t** buf, uint32_t* len, uint3 HttpMsgHeader* const req_header = transaction->get_header(SRC_CLIENT); if (req_header == nullptr) return 0; - const Field& true_ip = req_header->get_true_ip(); + const Field& true_ip = req_header->get_true_ip_addr(); if (true_ip.length() <= 0) return 0; diff --git a/src/service_inspectors/http_inspect/http_msg_header.cc b/src/service_inspectors/http_inspect/http_msg_header.cc index 5cb474efa..31f01620f 100644 --- a/src/service_inspectors/http_inspect/http_msg_header.cc +++ b/src/service_inspectors/http_inspect/http_msg_header.cc @@ -76,33 +76,51 @@ const Field& HttpMsgHeader::get_true_ip() } } - // This is potentially a comma-separated list of IP addresses. Just take the first one in - // the list. Since this is a normalized header field any whitespace will be an actual space. - uint8_t* addr_str = new uint8_t[header_to_use->length()+1]; + // This is potentially a comma-separated list of IP addresses. Take the last one in the list. + // Since this is a normalized header field any whitespace will be an actual space. int32_t length; for (length = 0; length < header_to_use->length(); length++) { - if (is_sp_comma[header_to_use->start()[length]]) + if (is_sp_comma[header_to_use->start()[header_to_use->length() - length - 1]]) break; - addr_str[length] = header_to_use->start()[length]; } - addr_str[length] = '\0'; + + true_ip.set(length, header_to_use->start() + (header_to_use->length() - length)); + return true_ip; +} + +const Field& HttpMsgHeader::get_true_ip_addr() +{ + if (true_ip_addr.length() != STAT_NOT_COMPUTE) + return true_ip_addr; + + const Field& true_ip = get_true_ip(); + if (true_ip.length() <= 0) + { + true_ip_addr.set(STAT_NOT_PRESENT); + return true_ip_addr; + } + + // Need a temporary copy so we can add null termination + uint8_t* addr_str = new uint8_t[true_ip.length()+1]; + memcpy(addr_str, true_ip.start(), true_ip.length()); + addr_str[true_ip.length()] = '\0'; SfIp tmp_sfip; const SfIpRet status = tmp_sfip.set((char*)addr_str); delete[] addr_str; if (status != SFIP_SUCCESS) { - true_ip.set(STAT_PROBLEMATIC); + true_ip_addr.set(STAT_PROBLEMATIC); } else { const size_t addr_length = (tmp_sfip.is_ip6() ? 4 : 1); uint32_t* const addr_buf = new uint32_t[addr_length]; memcpy(addr_buf, tmp_sfip.get_ptr(), addr_length * sizeof(uint32_t)); - true_ip.set(addr_length * sizeof(uint32_t), (uint8_t*)addr_buf, true); + true_ip_addr.set(addr_length * sizeof(uint32_t), (uint8_t*)addr_buf, true); } - return true_ip; + return true_ip_addr; } void HttpMsgHeader::gen_events() @@ -490,6 +508,11 @@ void HttpMsgHeader::print_section(FILE* output) HttpApi::classic_buffer_names[HTTP_BUFFER_COOKIE-1]); get_classic_buffer(HTTP_BUFFER_HEADER, 0, 0).print(output, HttpApi::classic_buffer_names[HTTP_BUFFER_HEADER-1]); + if (source_id == SRC_CLIENT) + { + get_classic_buffer(HTTP_BUFFER_TRUE_IP, 0, 0).print(output, + HttpApi::classic_buffer_names[HTTP_BUFFER_TRUE_IP-1]); + } get_classic_buffer(HTTP_BUFFER_RAW_COOKIE, 0, 0).print(output, HttpApi::classic_buffer_names[HTTP_BUFFER_RAW_COOKIE-1]); get_classic_buffer(HTTP_BUFFER_RAW_HEADER, 0, 0).print(output, diff --git a/src/service_inspectors/http_inspect/http_msg_header.h b/src/service_inspectors/http_inspect/http_msg_header.h index 0733485d5..f1fbdecfc 100644 --- a/src/service_inspectors/http_inspect/http_msg_header.h +++ b/src/service_inspectors/http_inspect/http_msg_header.h @@ -42,6 +42,7 @@ public: void gen_events() override; void publish() override; const Field& get_true_ip(); + const Field& get_true_ip_addr(); private: // Dummy configurations to support MIME processing @@ -57,6 +58,7 @@ private: bool detection_section = true; Field true_ip; + Field true_ip_addr; #ifdef REG_TEST void print_section(FILE* output) override; diff --git a/src/service_inspectors/http_inspect/http_msg_section.cc b/src/service_inspectors/http_inspect/http_msg_section.cc index 07bb17dc5..cd965d30b 100644 --- a/src/service_inspectors/http_inspect/http_msg_section.cc +++ b/src/service_inspectors/http_inspect/http_msg_section.cc @@ -191,6 +191,11 @@ const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, ui HttpMsgStatus* status = transaction->get_status(); return (status != nullptr) ? status->get_reason_phrase() : Field::FIELD_NULL; } + case HTTP_BUFFER_TRUE_IP: + { + HttpMsgHeader* header = transaction->get_header(SRC_CLIENT); + return (header != nullptr) ? header->get_true_ip() : Field::FIELD_NULL; + } case HTTP_BUFFER_URI: case HTTP_BUFFER_RAW_URI: { diff --git a/src/service_inspectors/http_inspect/ips_http.cc b/src/service_inspectors/http_inspect/ips_http.cc index fadd23fe3..13c529cfa 100644 --- a/src/service_inspectors/http_inspect/ips_http.cc +++ b/src/service_inspectors/http_inspect/ips_http.cc @@ -54,6 +54,7 @@ bool HttpCursorModule::begin(const char*, int, SnortConfig*) case HTTP_BUFFER_RAW_URI: case HTTP_BUFFER_STAT_CODE: case HTTP_BUFFER_STAT_MSG: + case HTTP_BUFFER_TRUE_IP: case HTTP_BUFFER_URI: case HTTP_BUFFER_VERSION: inspect_section = IS_DETECTION; @@ -931,6 +932,55 @@ static const IpsApi trailer_api = nullptr }; +//------------------------------------------------------------------------- +// http_true_ip +//------------------------------------------------------------------------- + +static const Parameter http_true_ip_params[] = +{ + { "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 } +}; + +#undef IPS_OPT +#define IPS_OPT "http_true_ip" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the final client IP address" + +static Module* true_ip_mod_ctor() +{ + return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRUE_IP, CAT_SET_OTHER, + PSI_TRUE_IP, http_true_ip_params); +} + +static const IpsApi true_ip_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + true_ip_mod_ctor, + HttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + HttpIpsOption::opt_ctor, + HttpIpsOption::opt_dtor, + nullptr +}; + //------------------------------------------------------------------------- // http_uri //------------------------------------------------------------------------- @@ -1061,6 +1111,7 @@ const BaseApi* ips_http_raw_uri = &raw_uri_api.base; const BaseApi* ips_http_stat_code = &stat_code_api.base; const BaseApi* ips_http_stat_msg = &stat_msg_api.base; const BaseApi* ips_http_trailer = &trailer_api.base; +const BaseApi* ips_http_true_ip = &true_ip_api.base; const BaseApi* ips_http_uri = &uri_api.base; const BaseApi* ips_http_version = &version_api.base; diff --git a/src/service_inspectors/http_inspect/ips_http.h b/src/service_inspectors/http_inspect/ips_http.h index 498b4e6dc..1b00b8053 100644 --- a/src/service_inspectors/http_inspect/ips_http.h +++ b/src/service_inspectors/http_inspect/ips_http.h @@ -30,7 +30,7 @@ enum PsIdx { PSI_CLIENT_BODY, PSI_COOKIE, PSI_HEADER, PSI_METHOD, PSI_RAW_BODY, PSI_RAW_COOKIE, PSI_RAW_HEADER, PSI_RAW_REQUEST, PSI_RAW_STATUS, PSI_RAW_TRAILER, PSI_RAW_URI, PSI_STAT_CODE, - PSI_STAT_MSG, PSI_TRAILER, PSI_URI, PSI_VERSION, PSI_MAX }; + PSI_STAT_MSG, PSI_TRAILER, PSI_TRUE_IP, PSI_URI, PSI_VERSION, PSI_MAX }; class HttpCursorModule : public Module { -- 2.47.3