From ca437251769196bb80e082c1c968fcaa2b96deb6 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 4 Dec 2017 17:47:13 +0100 Subject: Improve the `.dump` filter --- doc/source/features.rst | 5 +++++ src/sp_config.h | 2 ++ src/sp_config_keywords.c | 1 + src/sp_utils.c | 43 ++++++++++++++++++++++--------------------- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/doc/source/features.rst b/doc/source/features.rst index 407c0c0..e560925 100644 --- a/doc/source/features.rst +++ b/doc/source/features.rst @@ -345,6 +345,11 @@ line number. By using the *right* set of restrictive rules (or by using the *overly* restrictives ones in ``simulation`` mode), you might be able to gather interesting vulnerabilities used against your website. +Dumps are stored in the folder that you pass to the ``dump()`` filter, +in files named ``sp_dump.SHA`` with ``SHA`` being the *sha256* of the +rule that matched. This approach allows to mitigate denial of services attacks +that could fill up your filesystem. + Misc low-hanging fruits in the default configuration file ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/sp_config.h b/src/sp_config.h index b8fd679..8ef62a2 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -66,6 +66,8 @@ typedef struct { } sp_config_unserialize; typedef struct { + char *textual_representation; + char *filename; pcre *r_filename; diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 9bb8021..dd9a880 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -287,6 +287,7 @@ int parse_disabled_functions(char *line) { } } df->allow = allow; + df->textual_representation = estrdup(line); if (df->function) { df->functions_list = parse_functions_list(df->function); diff --git a/src/sp_utils.c b/src/sp_utils.c index e2747fb..74fbff7 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -80,7 +80,8 @@ int compute_hash(const char* const filename, char* file_hash) { return SUCCESS; } -static int construct_filename(char* filename, const char* folder) { +static int construct_filename(char* filename, const char* folder, + const char* textual) { time_t t = time(NULL); struct tm* tm = localtime(&t); // FIXME use `localtime_r` instead struct timeval tval; @@ -91,25 +92,22 @@ static int construct_filename(char* filename, const char* folder) { return -1; } - memcpy(filename, folder, strlen(folder)); - strcat(filename, "sp_dump_"); - strftime(filename + strlen(filename), 27, "%F_%T:", tm); - gettimeofday(&tval, NULL); - sprintf(filename + strlen(filename), "%04ld", tval.tv_usec); - strcat(filename, "_"); - - char* remote_addr = getenv("REMOTE_ADDR"); - if (remote_addr) { // ipv6: 8*4 bytes + 7 colons = 39 chars max - strncat(filename, remote_addr, 40); - } else { - strcat(filename, "0.0.0.0"); - } - strcat(filename, ".dump"); + /* We're using the sha256 sum of the rule's textual representation + * as filename, in order to only have one dump per rule, to migitate + * DoS attacks. */ + PHP_SHA256_CTX context; + unsigned char digest[SHA256_SIZE] = {0}; + char strhash[65] = {0}; + PHP_SHA256Init(&context); + PHP_SHA256Update(&context, (const unsigned char *) textual, strlen(textual)); + PHP_SHA256Final(digest, &context); + make_digest_ex(strhash, digest, SHA256_SIZE); + snprintf(filename, MAX_FOLDER_LEN-1, "%s/sp_dump.%s", folder, strhash); return 0; } -int sp_log_request(const char* folder) { +int sp_log_request(const char* folder, const char* text_repr) { FILE* file; const char* current_filename = zend_get_executed_filename(TSRMLS_C); const int current_line = zend_get_executed_lineno(TSRMLS_C); @@ -124,15 +122,18 @@ int sp_log_request(const char* folder) { // Apparently, PHP has trouble always giving SERVER, // and REQUEST is never used in its source code. - if (0 != construct_filename(filename, folder)) { + if (0 != construct_filename(filename, folder, text_repr)) { return -1; } if (NULL == (file = fopen(filename, "w+"))) { - sp_log_err("request_logging", "Unable to open %s", filename); + sp_log_err("request_logging", "Unable to open %s: %s", filename, + strerror(errno)); return -1; } - fprintf(file, "%s:%d\n", current_filename, current_line); + fprintf(file, "RULE: %s\n", text_repr); + + fprintf(file, "FILE: %s:%d\n", current_filename, current_line); for (size_t i = 0; i < (sizeof(zones) / sizeof(zones[0])) - 1; i++) { zval* variable_value; zend_string* variable_key; @@ -249,7 +250,7 @@ void sp_log_disable(const char* restrict path, const char* restrict arg_name, } } if (dump) { - sp_log_request(config_node->dump); + sp_log_request(config_node->dump, config_node->textual_representation); } } @@ -273,7 +274,7 @@ void sp_log_disable_ret(const char* restrict path, zend_get_executed_lineno(TSRMLS_C), ret_value?ret_value:"?", path); } if (dump) { - sp_log_request(dump); + sp_log_request(dump, config_node->textual_representation); } } -- cgit v1.3