From 49a4321cec080d61ff112aaf27f55257e62402f9 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 25 Sep 2014 18:07:55 +0200 Subject: array index whitelist/blacklist for multipart formdata --- ifilter.c | 8 ++--- php_suhosin.h | 2 ++ .../post_fileupload_array_index_blacklist.phpt | 41 ++++++++++++++++++++++ .../post_fileupload_array_index_whitelist.phpt | 41 ++++++++++++++++++++++ ufilter.c | 18 ++++++++++ 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 tests/filter/post_fileupload_array_index_blacklist.phpt create mode 100644 tests/filter/post_fileupload_array_index_whitelist.phpt diff --git a/ifilter.c b/ifilter.c index 4ea846f..47ab6f2 100644 --- a/ifilter.c +++ b/ifilter.c @@ -41,7 +41,7 @@ static size_t strnlen(const char *s, size_t maxlen) { } #endif -static size_t strnspn(const char *input, size_t n, const char *accept) +size_t suhosin_strnspn(const char *input, size_t n, const char *accept) { size_t count = 0; for (; *input != '\0' && count < n; input++, count++) { @@ -51,7 +51,7 @@ static size_t strnspn(const char *input, size_t n, const char *accept) return count; } -static size_t strncspn(const char *input, size_t n, const char *reject) +size_t suhosin_strncspn(const char *input, size_t n, const char *reject) { size_t count = 0; for (; *input != '\0' && count < n; input++, count++) { @@ -581,14 +581,14 @@ unsigned int suhosin_input_filter(int arg, char *var, char **val, unsigned int v /* index whitelist/blacklist */ if (SUHOSIN_G(array_index_whitelist) && *(SUHOSIN_G(array_index_whitelist))) { - if (strnspn(index, index_length, SUHOSIN_G(array_index_whitelist)) != index_length) { + if (suhosin_strnspn(index, index_length, SUHOSIN_G(array_index_whitelist)) != index_length) { suhosin_log(S_VARS, "array index contains not whitelisted characters - dropped variable '%s'", var); if (!SUHOSIN_G(simulation)) { return 0; } } } else if (SUHOSIN_G(array_index_blacklist) && *(SUHOSIN_G(array_index_blacklist))) { - if (strncspn(index, index_length, SUHOSIN_G(array_index_blacklist)) != index_length) { + if (suhosin_strncspn(index, index_length, SUHOSIN_G(array_index_blacklist)) != index_length) { suhosin_log(S_VARS, "array index contains blacklisted characters - dropped variable '%s'", var); if (!SUHOSIN_G(simulation)) { return 0; diff --git a/php_suhosin.h b/php_suhosin.h index 8877e53..7be628a 100644 --- a/php_suhosin.h +++ b/php_suhosin.h @@ -446,6 +446,8 @@ extern unsigned int (*old_input_filter)(int arg, char *var, char **val, unsigned void normalize_varname(char *varname); int suhosin_rfc1867_filter(unsigned int event, void *event_data, void **extra TSRMLS_DC); void suhosin_bailout(TSRMLS_D); +size_t suhosin_strnspn(const char *input, size_t n, const char *accept); +size_t suhosin_strncspn(const char *input, size_t n, const char *reject); /* Add pseudo refcount macros for PHP version < 5.3 */ #ifndef Z_REFCOUNT_PP diff --git a/tests/filter/post_fileupload_array_index_blacklist.phpt b/tests/filter/post_fileupload_array_index_blacklist.phpt new file mode 100644 index 0000000..f0e003b --- /dev/null +++ b/tests/filter/post_fileupload_array_index_blacklist.phpt @@ -0,0 +1,41 @@ +--TEST-- +suhosin file upload filter (array index whitelist) +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=0 +suhosin.log.stdout=255 +suhosin.log.script=0 +file_uploads=1 +suhosin.request.array_index_blacklist=ABC +--SKIPIF-- + +--COOKIE-- +--GET-- +--POST_RAW-- +Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737 +-----------------------------20896060251896012921717172737 +Content-Disposition: form-data; name="fn[foo][bar]" + +ok +-----------------------------20896060251896012921717172737 +Content-Disposition: form-data; name="fn[foo][BAR]" + +bad +-----------------------------20896060251896012921717172737-- +--FILE-- + +--EXPECTF-- +array(1) { + ["fn"]=> + array(1) { + ["foo"]=> + array(1) { + ["bar"]=> + string(2) "ok" + } + } +} +ALERT - array index contains blacklisted characters - dropped variable 'fn[foo][BAR]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - dropped 1 request variables - (0 in GET, 1 in POST, 0 in COOKIE) (attacker 'REMOTE_ADDR not set', file '%s') diff --git a/tests/filter/post_fileupload_array_index_whitelist.phpt b/tests/filter/post_fileupload_array_index_whitelist.phpt new file mode 100644 index 0000000..f2fe8c8 --- /dev/null +++ b/tests/filter/post_fileupload_array_index_whitelist.phpt @@ -0,0 +1,41 @@ +--TEST-- +suhosin file upload filter (array index whitelist) +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=0 +suhosin.log.stdout=255 +suhosin.log.script=0 +file_uploads=1 +suhosin.request.array_index_whitelist=abcdefghijklmnopqrstuvwxyz +--SKIPIF-- + +--COOKIE-- +--GET-- +--POST_RAW-- +Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737 +-----------------------------20896060251896012921717172737 +Content-Disposition: form-data; name="fn[foo][bar]" + +ok +-----------------------------20896060251896012921717172737 +Content-Disposition: form-data; name="fn[foo][BAR]" + +bad +-----------------------------20896060251896012921717172737-- +--FILE-- + +--EXPECTF-- +array(1) { + ["fn"]=> + array(1) { + ["foo"]=> + array(1) { + ["bar"]=> + string(2) "ok" + } + } +} +ALERT - array index contains not whitelisted characters - dropped variable 'fn[foo][BAR]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - dropped 1 request variables - (0 in GET, 1 in POST, 0 in COOKIE) (attacker 'REMOTE_ADDR not set', file '%s') diff --git a/ufilter.c b/ufilter.c index 1669e88..28b61e1 100644 --- a/ufilter.c +++ b/ufilter.c @@ -113,6 +113,24 @@ static int check_fileupload_varname(char *varname) } } + /* index whitelist/blacklist */ + if (SUHOSIN_G(array_index_whitelist) && *(SUHOSIN_G(array_index_whitelist))) { + if (suhosin_strnspn(index, index_length, SUHOSIN_G(array_index_whitelist)) != index_length) { + suhosin_log(S_VARS, "array index contains not whitelisted characters - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + } else if (SUHOSIN_G(array_index_blacklist) && *(SUHOSIN_G(array_index_blacklist))) { + if (suhosin_strncspn(index, index_length, SUHOSIN_G(array_index_blacklist)) != index_length) { + suhosin_log(S_VARS, "array index contains blacklisted characters - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + } + + index = strchr(index, '['); } -- cgit v1.3