From 0d550de551b91d5e57ba23e2b1e2c6430fad6818 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Mon, 12 Aug 2024 14:06:40 +0200 Subject: [PATCH] headers: put a configurable limit on their numbers So as to avoid quadratic complexity Ticket: 7191 --- htp/htp_config.c | 8 ++++++++ htp/htp_config.h | 8 ++++++++ htp/htp_config_private.h | 3 +++ htp/htp_core.h | 1 + htp/htp_request_generic.c | 11 +++++++++++ htp/htp_response_generic.c | 10 ++++++++++ 6 files changed, 41 insertions(+) diff --git a/htp/htp_config.c b/htp/htp_config.c index 00ae8531..942a7a45 100644 --- a/htp/htp_config.c +++ b/htp/htp_config.c @@ -145,6 +145,8 @@ static unsigned char bestfit_1252[] = { 0xff, 0x5d, 0x7d, 0xff, 0x5e, 0x7e, 0x00, 0x00, 0x00 }; +#define HTP_HEADERS_LIMIT 1024 + htp_cfg_t *htp_config_create(void) { htp_cfg_t *cfg = calloc(1, sizeof (htp_cfg_t)); if (cfg == NULL) return NULL; @@ -163,6 +165,7 @@ htp_cfg_t *htp_config_create(void) { cfg->response_lzma_layer_limit = 1; // default is only one layer cfg->compression_bomb_limit = HTP_COMPRESSION_BOMB_LIMIT; cfg->compression_time_limit = HTP_COMPRESSION_TIME_LIMIT_USEC; + cfg->number_headers_limit = HTP_HEADERS_LIMIT; cfg->allow_space_uri = 0; // Default settings for URL-encoded data. @@ -547,6 +550,11 @@ void htp_config_set_compression_time_limit(htp_cfg_t *cfg, size_t useclimit) { } } +void htp_config_set_number_headers_limit(htp_cfg_t *cfg, uint32_t limit) { + if (cfg == NULL) return; + cfg->number_headers_limit = limit; +} + void htp_config_set_log_level(htp_cfg_t *cfg, enum htp_log_level_t log_level) { if (cfg == NULL) return; cfg->log_level = log_level; diff --git a/htp/htp_config.h b/htp/htp_config.h index 57544f79..1636f804 100644 --- a/htp/htp_config.h +++ b/htp/htp_config.h @@ -466,6 +466,14 @@ void htp_config_set_compression_time_limit(htp_cfg_t *cfg, size_t useclimit); */ void htp_config_set_max_tx(htp_cfg_t *cfg, uint32_t limit); +/** + * Configures the maximum number of headers LibHTP will accept per request or response. + * + * @param[in] cfg + * @param[in] limit + */ +void htp_config_set_number_headers_limit(htp_cfg_t *cfg, uint32_t limit); + /** * Configures the desired log level. * diff --git a/htp/htp_config_private.h b/htp/htp_config_private.h index 83ff8f68..ecc8717c 100644 --- a/htp/htp_config_private.h +++ b/htp/htp_config_private.h @@ -363,6 +363,9 @@ struct htp_cfg_t { /** Maximum number of transactions. */ uint32_t max_tx; + + /** Maximum number of headers. */ + uint32_t number_headers_limit; }; #ifdef __cplusplus diff --git a/htp/htp_core.h b/htp/htp_core.h index e4c933e5..7c23212a 100644 --- a/htp/htp_core.h +++ b/htp/htp_core.h @@ -235,6 +235,7 @@ enum htp_file_source_t { #define HTP_REQUEST_INVALID 0x100000000ULL #define HTP_REQUEST_INVALID_C_L 0x200000000ULL #define HTP_AUTH_INVALID 0x400000000ULL +#define HTP_HEADERS_TOO_MANY 0x800000000ULL #define HTP_MAX_HEADERS_REPETITIONS 64 diff --git a/htp/htp_request_generic.c b/htp/htp_request_generic.c index 7045b527..28099f12 100644 --- a/htp/htp_request_generic.c +++ b/htp/htp_request_generic.c @@ -120,6 +120,17 @@ htp_status_t htp_process_request_header_generic(htp_connp_t *connp, unsigned cha bstr_free(h->value); free(h); } else { + if (htp_table_size(connp->in_tx->request_headers) > connp->cfg->number_headers_limit) { + if (!(connp->in_tx->flags & HTP_HEADERS_TOO_MANY)) { + connp->in_tx->flags |= HTP_HEADERS_TOO_MANY; + htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Too many request headers"); + } + bstr_free(h->name); + bstr_free(h->value); + free(h); + // give up on what comes next + return HTP_ERROR; + } // Add as a new header. if (htp_table_add(connp->in_tx->request_headers, h->name, h) != HTP_OK) { bstr_free(h->name); diff --git a/htp/htp_response_generic.c b/htp/htp_response_generic.c index f5fa59e3..69da6254 100644 --- a/htp/htp_response_generic.c +++ b/htp/htp_response_generic.c @@ -321,6 +321,16 @@ htp_status_t htp_process_response_header_generic(htp_connp_t *connp, unsigned ch bstr_free(h->value); free(h); } else { + if (htp_table_size(connp->out_tx->response_headers) > connp->cfg->number_headers_limit) { + if (!(connp->out_tx->flags & HTP_HEADERS_TOO_MANY)) { + connp->out_tx->flags |= HTP_HEADERS_TOO_MANY; + htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Too many response headers"); + } + bstr_free(h->name); + bstr_free(h->value); + free(h); + return HTP_ERROR; + } // Add as a new header. if (htp_table_add(connp->out_tx->response_headers, h->name, h) != HTP_OK) { bstr_free(h->name);