summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/features.rst5
-rw-r--r--src/sp_config.h2
-rw-r--r--src/sp_config_keywords.c1
-rw-r--r--src/sp_utils.c43
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
345*overly* restrictives ones in ``simulation`` mode), you might be able 345*overly* restrictives ones in ``simulation`` mode), you might be able
346to gather interesting vulnerabilities used against your website. 346to gather interesting vulnerabilities used against your website.
347 347
348Dumps are stored in the folder that you pass to the ``dump()`` filter,
349in files named ``sp_dump.SHA`` with ``SHA`` being the *sha256* of the
350rule that matched. This approach allows to mitigate denial of services attacks
351that could fill up your filesystem.
352
348 353
349Misc low-hanging fruits in the default configuration file 354Misc low-hanging fruits in the default configuration file
350^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 355^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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 {
66} sp_config_unserialize; 66} sp_config_unserialize;
67 67
68typedef struct { 68typedef struct {
69 char *textual_representation;
70
69 char *filename; 71 char *filename;
70 pcre *r_filename; 72 pcre *r_filename;
71 73
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) {
287 } 287 }
288 } 288 }
289 df->allow = allow; 289 df->allow = allow;
290 df->textual_representation = estrdup(line);
290 291
291 if (df->function) { 292 if (df->function) {
292 df->functions_list = parse_functions_list(df->function); 293 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) {
80 return SUCCESS; 80 return SUCCESS;
81} 81}
82 82
83static int construct_filename(char* filename, const char* folder) { 83static int construct_filename(char* filename, const char* folder,
84 const char* textual) {
84 time_t t = time(NULL); 85 time_t t = time(NULL);
85 struct tm* tm = localtime(&t); // FIXME use `localtime_r` instead 86 struct tm* tm = localtime(&t); // FIXME use `localtime_r` instead
86 struct timeval tval; 87 struct timeval tval;
@@ -91,25 +92,22 @@ static int construct_filename(char* filename, const char* folder) {
91 return -1; 92 return -1;
92 } 93 }
93 94
94 memcpy(filename, folder, strlen(folder)); 95 /* We're using the sha256 sum of the rule's textual representation
95 strcat(filename, "sp_dump_"); 96 * as filename, in order to only have one dump per rule, to migitate
96 strftime(filename + strlen(filename), 27, "%F_%T:", tm); 97 * DoS attacks. */
97 gettimeofday(&tval, NULL); 98 PHP_SHA256_CTX context;
98 sprintf(filename + strlen(filename), "%04ld", tval.tv_usec); 99 unsigned char digest[SHA256_SIZE] = {0};
99 strcat(filename, "_"); 100 char strhash[65] = {0};
100 101 PHP_SHA256Init(&context);
101 char* remote_addr = getenv("REMOTE_ADDR"); 102 PHP_SHA256Update(&context, (const unsigned char *) textual, strlen(textual));
102 if (remote_addr) { // ipv6: 8*4 bytes + 7 colons = 39 chars max 103 PHP_SHA256Final(digest, &context);
103 strncat(filename, remote_addr, 40); 104 make_digest_ex(strhash, digest, SHA256_SIZE);
104 } else { 105 snprintf(filename, MAX_FOLDER_LEN-1, "%s/sp_dump.%s", folder, strhash);
105 strcat(filename, "0.0.0.0");
106 }
107 strcat(filename, ".dump");
108 106
109 return 0; 107 return 0;
110} 108}
111 109
112int sp_log_request(const char* folder) { 110int sp_log_request(const char* folder, const char* text_repr) {
113 FILE* file; 111 FILE* file;
114 const char* current_filename = zend_get_executed_filename(TSRMLS_C); 112 const char* current_filename = zend_get_executed_filename(TSRMLS_C);
115 const int current_line = zend_get_executed_lineno(TSRMLS_C); 113 const int current_line = zend_get_executed_lineno(TSRMLS_C);
@@ -124,15 +122,18 @@ int sp_log_request(const char* folder) {
124 // Apparently, PHP has trouble always giving SERVER, 122 // Apparently, PHP has trouble always giving SERVER,
125 // and REQUEST is never used in its source code. 123 // and REQUEST is never used in its source code.
126 124
127 if (0 != construct_filename(filename, folder)) { 125 if (0 != construct_filename(filename, folder, text_repr)) {
128 return -1; 126 return -1;
129 } 127 }
130 if (NULL == (file = fopen(filename, "w+"))) { 128 if (NULL == (file = fopen(filename, "w+"))) {
131 sp_log_err("request_logging", "Unable to open %s", filename); 129 sp_log_err("request_logging", "Unable to open %s: %s", filename,
130 strerror(errno));
132 return -1; 131 return -1;
133 } 132 }
134 133
135 fprintf(file, "%s:%d\n", current_filename, current_line); 134 fprintf(file, "RULE: %s\n", text_repr);
135
136 fprintf(file, "FILE: %s:%d\n", current_filename, current_line);
136 for (size_t i = 0; i < (sizeof(zones) / sizeof(zones[0])) - 1; i++) { 137 for (size_t i = 0; i < (sizeof(zones) / sizeof(zones[0])) - 1; i++) {
137 zval* variable_value; 138 zval* variable_value;
138 zend_string* variable_key; 139 zend_string* variable_key;
@@ -249,7 +250,7 @@ void sp_log_disable(const char* restrict path, const char* restrict arg_name,
249 } 250 }
250 } 251 }
251 if (dump) { 252 if (dump) {
252 sp_log_request(config_node->dump); 253 sp_log_request(config_node->dump, config_node->textual_representation);
253 } 254 }
254} 255}
255 256
@@ -273,7 +274,7 @@ void sp_log_disable_ret(const char* restrict path,
273 zend_get_executed_lineno(TSRMLS_C), ret_value?ret_value:"?", path); 274 zend_get_executed_lineno(TSRMLS_C), ret_value?ret_value:"?", path);
274 } 275 }
275 if (dump) { 276 if (dump) {
276 sp_log_request(dump); 277 sp_log_request(dump, config_node->textual_representation);
277 } 278 }
278} 279}
279 280