From: Mike Stepanek (mstepane) Date: Thu, 21 Jan 2021 13:40:16 +0000 (+0000) Subject: Merge pull request #2709 in SNORT/snort3 from ~MDAGON/snort3:settings to master X-Git-Tag: 3.1.1.0~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da7abfb149789b772288caf63d88ee663c2d255f;p=thirdparty%2Fsnort3.git Merge pull request #2709 in SNORT/snort3 from ~MDAGON/snort3:settings to master Squashed commit of the following: commit 40fdd7a388e51d4d2c8cdac04b79178989a6dea4 Author: mdagon Date: Tue Jan 12 16:57:13 2021 -0500 payload_injector: inject settings frame --- diff --git a/src/payload_injector/payload_injector.cc b/src/payload_injector/payload_injector.cc index 0afb93706..849a66989 100644 --- a/src/payload_injector/payload_injector.cc +++ b/src/payload_injector/payload_injector.cc @@ -78,7 +78,8 @@ InjectionReturnStatus PayloadInjector::inject_http2_payload(Packet* p, { uint8_t* http2_payload; uint32_t payload_len; - status = get_http2_payload(control, http2_payload, payload_len); + const bool send_settings = (session_data->was_server_settings_received() == false); + status = get_http2_payload(control, http2_payload, payload_len, send_settings); if (status == INJECTION_SUCCESS) { p->active->send_data(p, df, http2_payload, payload_len); diff --git a/src/payload_injector/payload_injector.h b/src/payload_injector/payload_injector.h index 009bb0662..8bca77497 100644 --- a/src/payload_injector/payload_injector.h +++ b/src/payload_injector/payload_injector.h @@ -60,17 +60,20 @@ public: private: static InjectionReturnStatus inject_http2_payload(snort::Packet* p, const - InjectionControl& control, snort::EncodeFlags df); + InjectionControl& control, snort::EncodeFlags df); #ifdef UNIT_TEST public: #endif - static InjectionReturnStatus get_http2_payload(InjectionControl control, uint8_t*& http2_payload, uint32_t& payload_len); + static InjectionReturnStatus get_http2_payload(InjectionControl control, + uint8_t*& http2_payload, uint32_t& payload_len, bool send_settings); }; #ifdef UNIT_TEST -InjectionReturnStatus write_7_bit_prefix_int(uint32_t val, uint8_t*& out, uint32_t& out_free_space); +InjectionReturnStatus write_7_bit_prefix_int(uint32_t val, uint8_t*& out, + uint32_t& out_free_space); #endif #endif + diff --git a/src/payload_injector/payload_injector_translate_page.cc b/src/payload_injector/payload_injector_translate_page.cc index 933a73d1c..5c3d08d1a 100644 --- a/src/payload_injector/payload_injector_translate_page.cc +++ b/src/payload_injector/payload_injector_translate_page.cc @@ -52,6 +52,9 @@ static const char location[] = "Location: "; static const uint32_t max_hdr_size = 2000; +// Empty settings frame +static const uint8_t empty_settings_frame[] = { 0, 0, 0, FT_SETTINGS, 0, 0, 0, 0, 0 }; + static InjectionReturnStatus write_translation(uint8_t*& out, uint32_t& out_free_space, const uint8_t* translation, uint32_t size) { @@ -245,7 +248,7 @@ static void write_frame_hdr(uint8_t*& out, uint32_t len, uint8_t type, uint8_t f } InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl control, - uint8_t*& http2_payload, uint32_t& payload_len) + uint8_t*& http2_payload, uint32_t& payload_len, bool send_settings) { if (control.http_page == nullptr || control.http_page_len == 0) return ERR_PAGE_TRANSLATION; @@ -263,9 +266,16 @@ InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl contro if (body_len % (1<<14) != 0) num_data_frames++; payload_len = FRAME_HEADER_LENGTH*(num_data_frames + 1) + hdr_len + body_len; + if (send_settings) + payload_len += sizeof(empty_settings_frame); http2_payload = (uint8_t*)snort_alloc(payload_len); uint8_t* http2_payload_cur = http2_payload; + if (send_settings) + { + memcpy(http2_payload_cur, empty_settings_frame, sizeof(empty_settings_frame)); + http2_payload_cur += sizeof(empty_settings_frame); + } write_frame_hdr(http2_payload_cur, hdr_len, FT_HEADERS, END_HEADERS, control.stream_id); memcpy(http2_payload_cur, http2_hdr, hdr_len); http2_payload_cur += hdr_len; diff --git a/src/payload_injector/test/payload_injector_test.cc b/src/payload_injector/test/payload_injector_test.cc index d77efba24..db592eefe 100644 --- a/src/payload_injector/test/payload_injector_test.cc +++ b/src/payload_injector/test/payload_injector_test.cc @@ -117,7 +117,7 @@ public: static InjectionReturnStatus translation_status = INJECTION_SUCCESS; InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl, - uint8_t*& http2_payload, uint32_t& payload_len) + uint8_t*& http2_payload, uint32_t& payload_len, bool) { if (translation_status == INJECTION_SUCCESS) { diff --git a/src/payload_injector/test/payload_injector_translate_test.cc b/src/payload_injector/test/payload_injector_translate_test.cc index d59eeb20d..b6cc1b75e 100644 --- a/src/payload_injector/test/payload_injector_translate_test.cc +++ b/src/payload_injector/test/payload_injector_translate_test.cc @@ -46,7 +46,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); uint8_t out[] = @@ -78,7 +78,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation2) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); @@ -107,7 +107,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation3) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); @@ -136,7 +136,7 @@ TEST(payload_injector_translate_test, mix_n_and_rn) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); @@ -164,7 +164,7 @@ TEST(payload_injector_translate_test, only_body) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -178,7 +178,7 @@ TEST(payload_injector_translate_test, no_body) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -192,7 +192,7 @@ TEST(payload_injector_translate_test, missing_last_rn) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -206,7 +206,7 @@ TEST(payload_injector_translate_test, missing_space_after_colon) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -220,7 +220,7 @@ TEST(payload_injector_translate_test, extra_space_before_colon) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -234,7 +234,7 @@ TEST(payload_injector_translate_test, unsupported_status) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -248,7 +248,7 @@ TEST(payload_injector_translate_test, unsupported_hdr) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -261,7 +261,7 @@ TEST(payload_injector_translate_test, hdr_ends_wo_value) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -274,7 +274,7 @@ TEST(payload_injector_translate_test, missing_value) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -292,7 +292,7 @@ TEST(payload_injector_translate_test, val_len1) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); @@ -329,7 +329,7 @@ TEST(payload_injector_translate_test, val_len2) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); uint8_t out[] = @@ -364,7 +364,7 @@ TEST(payload_injector_translate_test, val_len3) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); @@ -440,7 +440,7 @@ TEST(payload_injector_translate_test, http2_hdr_is_max) control.http_page = http_page; control.http_page_len = size; control.stream_id = 0xf000; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); CHECK(payload_len == 2019); @@ -472,7 +472,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -499,7 +499,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big3) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -527,7 +527,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big4) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -554,7 +554,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big5) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -570,7 +570,7 @@ TEST(payload_injector_translate_test, payload_body_is_exactly_1_data_frame) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); // Headers frame header + status ok + data frame header uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 1, 0, 0, 0, 1 }; @@ -592,7 +592,7 @@ TEST(payload_injector_translate_test, payload_body_is_data_frame_plus_1) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == INJECTION_SUCCESS); // Headers frame header + status ok + data frame header uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 0, 0, 0, 0, 1 }; @@ -611,7 +611,7 @@ TEST(payload_injector_translate_test, http_page_is_nullptr) InjectionControl control; control.http_page = nullptr; control.http_page_len = 1; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -622,7 +622,7 @@ TEST(payload_injector_translate_test, http_page_is_0_length) InjectionControl control; control.http_page = http_page; control.http_page_len = 0; - status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false); CHECK(status == ERR_PAGE_TRANSLATION); } diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.h b/src/service_inspectors/http2_inspect/http2_flow_data.h index 932dcf2ac..a7e9c7baa 100644 --- a/src/service_inspectors/http2_inspect/http2_flow_data.h +++ b/src/service_inspectors/http2_inspect/http2_flow_data.h @@ -113,6 +113,14 @@ public: // frame into the S2C direction of an HTTP/2 flow. bool is_mid_frame() const; + // Used by payload injection to determine whether we should inject S2C settings frame + // before injecting payload + bool was_server_settings_received() const + { return server_settings_frame_received; } + + void set_server_settings_received() + { server_settings_frame_received = true; } + #ifdef UNIT_TEST void set_mid_frame(bool); // Not implemented outside of unit tests #endif @@ -140,6 +148,7 @@ protected: // them is the stream that http_inspect is actually processing at the moment. uint32_t stream_in_hi = Http2Enums::NO_STREAM_ID; HttpMsgSection* hi_msg_section = nullptr; + bool server_settings_frame_received = false; // Reassemble() data to eval() uint8_t lead_frame_header[2][Http2Enums::FRAME_HEADER_LENGTH]; diff --git a/src/service_inspectors/http2_inspect/http2_settings_frame.cc b/src/service_inspectors/http2_inspect/http2_settings_frame.cc index 9447131fa..da0b08427 100644 --- a/src/service_inspectors/http2_inspect/http2_settings_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_settings_frame.cc @@ -61,6 +61,9 @@ Http2SettingsFrame::Http2SettingsFrame(const uint8_t* header_buffer, const uint3 if (ACK & get_flags()) return; + if (src_id == HttpCommon::SRC_SERVER && !ssn_data->was_server_settings_received()) + ssn_data->set_server_settings_received(); + parse_settings_frame(); } @@ -94,9 +97,7 @@ bool Http2SettingsFrame::sanity_check() // FIXIT-E this next check should possibly be moved to valid_sequence() if (get_stream_id() != 0) bad_frame = true; - else if (!ack and ((data.length() <= 0) or ((data.length() % 6) != 0))) - bad_frame = true; - else if (ack and data.length() > 0) + else if (((data.length() % 6) != 0) or (ack and data.length() != 0)) bad_frame = true; return !(bad_frame);