From: Mike Stepanek (mstepane) Date: Tue, 27 Oct 2020 13:13:31 +0000 (+0000) Subject: Merge pull request #2573 in SNORT/snort3 from ~MDAGON/snort3:h2_inject_big to master X-Git-Tag: 3.0.3-4~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=38b148a1efb216d60e342619aa6ab66627ec48bb;p=thirdparty%2Fsnort3.git Merge pull request #2573 in SNORT/snort3 from ~MDAGON/snort3:h2_inject_big to master Squashed commit of the following: commit 6cbee883ef13974c2fa3daf7794fda64fc743edb Author: mdagon Date: Tue Sep 22 15:12:36 2020 -0400 payload_injector: support page > 16k --- diff --git a/src/payload_injector/payload_injector_module.cc b/src/payload_injector/payload_injector_module.cc index b33a69075..0187242ef 100644 --- a/src/payload_injector/payload_injector_module.cc +++ b/src/payload_injector/payload_injector_module.cc @@ -59,7 +59,6 @@ static const std::map InjectionErrorToStrin { ERR_HTTP2_MID_FRAME, "HTTP/2 - attempt to inject mid frame. Currently not supported." }, { ERR_TRANSLATED_HDRS_SIZE, "HTTP/2 translated header size is bigger than expected. Update max size." }, - { ERR_HTTP2_BODY_SIZE, "HTTP/2 body is > 16k. Currently not supported." }, { ERR_HTTP2_EVEN_STREAM_ID, "HTTP/2 - injection to server initiated stream" }, { ERR_PKT_FROM_SERVER, "Packet is from server" } }; diff --git a/src/payload_injector/payload_injector_module.h b/src/payload_injector/payload_injector_module.h index 466319213..18b225879 100644 --- a/src/payload_injector/payload_injector_module.h +++ b/src/payload_injector/payload_injector_module.h @@ -49,9 +49,8 @@ enum InjectionReturnStatus : int8_t ERR_PAGE_TRANSLATION = -5, ERR_HTTP2_MID_FRAME = -6, ERR_TRANSLATED_HDRS_SIZE = -7, - ERR_HTTP2_BODY_SIZE = -8, - ERR_HTTP2_EVEN_STREAM_ID = -9, - ERR_PKT_FROM_SERVER = -10, + ERR_HTTP2_EVEN_STREAM_ID = -8, + ERR_PKT_FROM_SERVER = -9, // Update InjectionErrorToString when adding/removing error codes }; diff --git a/src/payload_injector/payload_injector_translate_page.cc b/src/payload_injector/payload_injector_translate_page.cc index d85dbaab8..aaeaeff4f 100644 --- a/src/payload_injector/payload_injector_translate_page.cc +++ b/src/payload_injector/payload_injector_translate_page.cc @@ -260,21 +260,29 @@ InjectionReturnStatus PayloadInjectorModule::get_http2_payload(InjectionControl if (status != INJECTION_SUCCESS) return status; - const uint32_t body_len = control.http_page_len - body_offset; - // FIXIT-E support larger body size - if (body_len > 1<<14) - return ERR_HTTP2_BODY_SIZE; - - payload_len = 2*FRAME_HEADER_LENGTH + hdr_len + body_len; + uint32_t body_len = control.http_page_len - body_offset; + uint32_t num_data_frames = body_len / (1<<14); + if (body_len % (1<<14) != 0) + num_data_frames++; + payload_len = FRAME_HEADER_LENGTH*(num_data_frames + 1) + hdr_len + body_len; http2_payload = (uint8_t*)snort_alloc(payload_len); uint8_t* http2_payload_cur = http2_payload; 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; - write_frame_hdr(http2_payload_cur, body_len, FT_DATA, END_STREAM, control.stream_id); - memcpy(http2_payload_cur, control.http_page + body_offset, body_len); - + const uint8_t* http_body_cur = control.http_page + body_offset; + while (body_len) + { + const uint32_t cur_len = (body_len > 1<<14) ? 1<<14 : body_len; + body_len -= cur_len; + const uint8_t flags = (body_len == 0) ? END_STREAM : 0; + write_frame_hdr(http2_payload_cur, cur_len, FT_DATA, flags, control.stream_id); + memcpy(http2_payload_cur, http_body_cur, cur_len); + http2_payload_cur += cur_len; + http_body_cur += cur_len; + } + assert((http2_payload_cur - http2_payload) == payload_len); return INJECTION_SUCCESS; } diff --git a/src/payload_injector/test/payload_injector_test.cc b/src/payload_injector/test/payload_injector_test.cc index 12a8abebe..6e0c1fccf 100644 --- a/src/payload_injector/test/payload_injector_test.cc +++ b/src/payload_injector/test/payload_injector_test.cc @@ -331,6 +331,18 @@ TEST(payload_injector_test, http2_pkt_from_srvr) delete flow.gadget; } +TEST(payload_injector_test, flow_is_null) +{ + mod.set_configured(true); + Packet p(false); + p.packet_flags = PKT_STREAM_EST; + InjectionReturnStatus status = mod.inject_http_payload(&p, control); + CHECK(counts->http_injects == 0); + CHECK(status == ERR_UNIDENTIFIED_PROTOCOL); + const char* err_string = mod.get_err_string(status); + CHECK(strcmp(err_string, "Unidentified protocol") == 0); +} + TEST_GROUP(payload_injector_translate_err_test) { PayloadInjectorModule mod; @@ -389,17 +401,6 @@ TEST(payload_injector_translate_err_test, http2_hdrs_size) "HTTP/2 translated header size is bigger than expected. Update max size.") == 0); } -TEST(payload_injector_translate_err_test, http2_body_size) -{ - Packet p(false); - p.packet_flags = PKT_STREAM_EST; - p.flow = &flow; - translation_status = ERR_HTTP2_BODY_SIZE; - status = mod.inject_http_payload(&p, control); - const char* err_string = mod.get_err_string(status); - CHECK(strcmp(err_string, "HTTP/2 body is > 16k. Currently not supported.") == 0); -} - int main(int argc, char** argv) { return CommandLineTestRunner::RunAllTests(argc, argv); diff --git a/src/payload_injector/test/payload_injector_translate_test.cc b/src/payload_injector/test/payload_injector_translate_test.cc index b62006889..d0ea288ba 100644 --- a/src/payload_injector/test/payload_injector_translate_test.cc +++ b/src/payload_injector/test/payload_injector_translate_test.cc @@ -584,19 +584,51 @@ TEST(payload_injector_translate_test, http2_hdr_too_big5) CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } -TEST(payload_injector_translate_test, payload_body_larger_than_max) +TEST(payload_injector_translate_test, payload_body_is_exactly_1_data_frame) { - static const uint32_t size = (1<<14) + 1 + strlen("HTTP/1.1 403 Forbidden\r\n\r\n"); + static const uint32_t size = (1<<14) + strlen("HTTP/1.1 200 OK\r\n\r\n"); uint8_t http_page[size]; memset(http_page,'a',size); - memcpy(http_page,"HTTP/1.1 403 Forbidden\r\n\r\n", strlen("HTTP/1.1 403 Forbidden\r\n\r\n")); + memcpy(http_page,"HTTP/1.1 200 OK\r\n\r\n", strlen("HTTP/1.1 200 OK\r\n\r\n")); InjectionControl control; control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); - CHECK(status == ERR_HTTP2_BODY_SIZE); + 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 }; + CHECK(memcmp(http2_payload, out, sizeof(out))==0); + // Data frame == http body + CHECK(memcmp(http2_payload + sizeof(out), http_page + strlen("HTTP/1.1 200 OK\r\n\r\n"), + 1<<14)==0); + snort_free(http2_payload); +} + +TEST(payload_injector_translate_test, payload_body_is_data_frame_plus_1) +{ + static const uint32_t size = (1<<14) + 1 + strlen("HTTP/1.1 200 OK\r\n\r\n"); + uint8_t http_page[size]; + memset(http_page,'a',size); + memcpy(http_page,"HTTP/1.1 200 OK\r\n\r\n", strlen("HTTP/1.1 200 OK\r\n\r\n")); + + InjectionControl control; + control.stream_id = 1; + control.http_page = http_page; + control.http_page_len = size; + status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + 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 }; + CHECK(memcmp(http2_payload, out, sizeof(out))==0); + // First data frame + CHECK(memcmp(http2_payload + sizeof(out), http_page + strlen("HTTP/1.1 200 OK\r\n\r\n"), + 1<<14)==0); + // Second data frame header + 1 last byte of body + uint8_t out2[] = { 0, 0, 1, 0, 1, 0, 0, 0, 1, 'a' }; + CHECK(memcmp(http2_payload + sizeof(out) + (1<<14), out2, sizeof(out2))==0); + snort_free(http2_payload); } TEST(payload_injector_translate_test, http_page_is_nullptr) @@ -621,27 +653,26 @@ TEST(payload_injector_translate_test, http_page_is_0_length) TEST(payload_injector_translate_test, 7_bit_int_min_max) { - uint8_t out[6]; - uint32_t out_free_space = sizeof(out); - - // Translate 0 - uint8_t* cur = out; - InjectionReturnStatus status = write_7_bit_prefix_int(0, cur, out_free_space); - uint8_t expected_out[] = {0}; - CHECK(status == INJECTION_SUCCESS); - CHECK(out_free_space == 5); - CHECK(memcmp(out, expected_out, 1) == 0); - - // Translate max uint_32 - cur = out; - out_free_space = sizeof(out); - status = write_7_bit_prefix_int(UINT32_MAX, cur, out_free_space); - uint8_t expected_out2[] = {0x7f, 0x80, 0xff, 0xff, 0xff, 0xf}; - CHECK(status == INJECTION_SUCCESS); - CHECK(out_free_space == 0); - CHECK(memcmp(out, expected_out2, 6) == 0); -} + uint8_t out[6]; + uint32_t out_free_space = sizeof(out); + // Translate 0 + uint8_t* cur = out; + InjectionReturnStatus status = write_7_bit_prefix_int(0, cur, out_free_space); + uint8_t expected_out[] = { 0 }; + CHECK(status == INJECTION_SUCCESS); + CHECK(out_free_space == 5); + CHECK(memcmp(out, expected_out, 1) == 0); + + // Translate max uint_32 + cur = out; + out_free_space = sizeof(out); + status = write_7_bit_prefix_int(UINT32_MAX, cur, out_free_space); + uint8_t expected_out2[] = { 0x7f, 0x80, 0xff, 0xff, 0xff, 0xf }; + CHECK(status == INJECTION_SUCCESS); + CHECK(out_free_space == 0); + CHECK(memcmp(out, expected_out2, 6) == 0); +} int main(int argc, char** argv) {