From 594c8df58c6f7f9b9610c7f0fd11da08a532de98 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 25 Sep 2014 17:24:39 +0200 Subject: array index whitelist/blacklist --- execute.c | 1 - ifilter.c | 40 +++++++++++++++- php_suhosin.h | 2 + suhosin.c | 2 + ...input_filter_request_array_index_blacklist.phpt | 53 ++++++++++++++++++++++ ...input_filter_request_array_index_whitelist.phpt | 51 +++++++++++++++++++++ 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 tests/filter/input_filter_request_array_index_blacklist.phpt create mode 100644 tests/filter/input_filter_request_array_index_whitelist.phpt diff --git a/execute.c b/execute.c index 560d8f5..a27d82f 100644 --- a/execute.c +++ b/execute.c @@ -415,7 +415,6 @@ static void suhosin_execute_ex(zend_op_array *op_array, int zo, long dummy TSRML SUHOSIN_G(att_get_vars)-SUHOSIN_G(cur_get_vars), SUHOSIN_G(att_post_vars)-SUHOSIN_G(cur_post_vars), SUHOSIN_G(att_cookie_vars)-SUHOSIN_G(cur_cookie_vars)); - } if (!SUHOSIN_G(simulation) && SUHOSIN_G(filter_action)) { diff --git a/ifilter.c b/ifilter.c index 48b62c7..4ea846f 100644 --- a/ifilter.c +++ b/ifilter.c @@ -41,6 +41,26 @@ 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 count = 0; + for (; *input != '\0' && count < n; input++, count++) { + if (strchr(accept, *input) == NULL) + break; + } + return count; +} + +static size_t strncspn(const char *input, size_t n, const char *reject) +{ + size_t count = 0; + for (; *input != '\0' && count < n; input++, count++) { + if (strchr(reject, *input) != NULL) + break; + } + return count; +} + /* {{{ normalize_varname */ @@ -524,7 +544,8 @@ unsigned int suhosin_input_filter(int arg, char *var, char **val, unsigned int v } index_length = index_end - index; - + + /* max. array index length */ if (SUHOSIN_G(max_array_index_length) && SUHOSIN_G(max_array_index_length) < index_length) { suhosin_log(S_VARS, "configured request variable array index length limit exceeded - dropped variable '%s'", var); if (!SUHOSIN_G(simulation)) { @@ -558,6 +579,23 @@ unsigned int suhosin_input_filter(int arg, char *var, char **val, unsigned int v break; } + /* 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) { + 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) { + suhosin_log(S_VARS, "array index contains blacklisted characters - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + } + index = strchr(index, '['); } diff --git a/php_suhosin.h b/php_suhosin.h index d567877..8877e53 100644 --- a/php_suhosin.h +++ b/php_suhosin.h @@ -208,6 +208,8 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) long max_value_length; long max_array_depth; long max_array_index_length; + char* array_index_whitelist; + char* array_index_blacklist; zend_bool disallow_nul; zend_bool disallow_ws; /* cookie variables */ diff --git a/suhosin.c b/suhosin.c index fc84a94..4a965ac 100644 --- a/suhosin.c +++ b/suhosin.c @@ -790,6 +790,8 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("suhosin.request.max_array_depth", "50", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_array_depth, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.request.max_totalname_length", "256", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_totalname_length, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.request.max_array_index_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_array_index_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.array_index_whitelist", "", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, array_index_whitelist, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.array_index_blacklist", "", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, array_index_blacklist, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.request.disallow_nul", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestBool, disallow_nul, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.request.disallow_ws", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestBool, disallow_ws, zend_suhosin_globals, suhosin_globals) diff --git a/tests/filter/input_filter_request_array_index_blacklist.phpt b/tests/filter/input_filter_request_array_index_blacklist.phpt new file mode 100644 index 0000000..01d551f --- /dev/null +++ b/tests/filter/input_filter_request_array_index_blacklist.phpt @@ -0,0 +1,53 @@ +--TEST-- +suhosin input filter (suhosin.request.array_index_blacklist) +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=0 +suhosin.log.stdout=511 +suhosin.log.script=0 +suhosin.request.array_index_blacklist="=ABC%{}\\$;" +--SKIPIF-- + +--COOKIE-- +var1[aaa]=1;var2[bbB]=1;var3[ccc][ccC]=1 +--GET-- +var1[aaa]=1&var2[bbB]=1&var3[ccc][ccC]=1 +--POST-- +var1[aaa]=1&var2[bbB]=1&var3[ccc][ccC]=1 +--FILE-- + +--EXPECTF-- +string(10) "=ABC%{}\$;" +array(1) { + ["var1"]=> + array(1) { + ["aaa"]=> + string(1) "1" + } +} +array(1) { + ["var1"]=> + array(1) { + ["aaa"]=> + string(1) "1" + } +} +array(1) { + ["var1"]=> + array(1) { + ["aaa"]=> + string(1) "1" + } +} +ALERT - array index contains blacklisted characters - dropped variable 'var2[bbB]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains blacklisted characters - dropped variable 'var3[ccc][ccC]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains blacklisted characters - dropped variable 'var2[bbB]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains blacklisted characters - dropped variable 'var3[ccc][ccC]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains blacklisted characters - dropped variable 'var2[bbB]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains blacklisted characters - dropped variable 'var3[ccc][ccC]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - dropped 6 request variables - (2 in GET, 2 in POST, 2 in COOKIE) (attacker 'REMOTE_ADDR not set', file '%s') diff --git a/tests/filter/input_filter_request_array_index_whitelist.phpt b/tests/filter/input_filter_request_array_index_whitelist.phpt new file mode 100644 index 0000000..8e63a36 --- /dev/null +++ b/tests/filter/input_filter_request_array_index_whitelist.phpt @@ -0,0 +1,51 @@ +--TEST-- +suhosin input filter (suhosin.request.array_index_whitelist) +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=0 +suhosin.log.stdout=255 +suhosin.log.script=0 +suhosin.request.array_index_whitelist=abcdefghijklmnopqrstuvwxyz +--SKIPIF-- + +--COOKIE-- +var1[aaa]=1;var2[bbB]=1;var3[ccc][ccC]=1 +--GET-- +var1[aaa]=1&var2[bbB]=1&var3[ccc][ccC]=1 +--POST-- +var1[aaa]=1&var2[bbB]=1&var3[ccc][ccC]=1 +--FILE-- + +--EXPECTF-- +array(1) { + ["var1"]=> + array(1) { + ["aaa"]=> + string(1) "1" + } +} +array(1) { + ["var1"]=> + array(1) { + ["aaa"]=> + string(1) "1" + } +} +array(1) { + ["var1"]=> + array(1) { + ["aaa"]=> + string(1) "1" + } +} +ALERT - array index contains not whitelisted characters - dropped variable 'var2[bbB]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains not whitelisted characters - dropped variable 'var3[ccc][ccC]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains not whitelisted characters - dropped variable 'var2[bbB]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains not whitelisted characters - dropped variable 'var3[ccc][ccC]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains not whitelisted characters - dropped variable 'var2[bbB]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - array index contains not whitelisted characters - dropped variable 'var3[ccc][ccC]' (attacker 'REMOTE_ADDR not set', file '%s') +ALERT - dropped 6 request variables - (2 in GET, 2 in POST, 2 in COOKIE) (attacker 'REMOTE_ADDR not set', file '%s') -- cgit v1.3