From 63de1053dfda1faca22a84afb82d6b1315b8db6e Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 9 Jul 2014 12:47:03 +0200 Subject: added sql.user_match + username character check --- Changelog | 4 ++- execute.c | 51 ++++++++++++++++++++++++---------- php_suhosin.h | 45 +++++++++++++++--------------- suhosin.c | 15 +++++----- tests/sql/mysqli_user_match_error.phpt | 18 ++++++++++++ tests/sql/mysqli_user_match_ok.phpt | 18 ++++++++++++ 6 files changed, 106 insertions(+), 45 deletions(-) create mode 100644 tests/sql/mysqli_user_match_error.phpt create mode 100644 tests/sql/mysqli_user_match_ok.phpt diff --git a/Changelog b/Changelog index 4e83cb3..ad2438f 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,8 @@ 2014-06-24 - 0.9.37-dev - - Added SQL injection protection for Mysqli and several test cases + - Added SQL injection protection for Mysqli and several test cases + - Added wildcard matching for SQL username + - Added check for SQL username to only contain valid characters (>= ASCII 32) 2014-06-10 - 0.9.36 diff --git a/execute.c b/execute.c index 098b074..2f280b7 100644 --- a/execute.c +++ b/execute.c @@ -24,6 +24,7 @@ #endif #include +#include #include "php.h" #include "php_ini.h" #include "zend_hash.h" @@ -1024,17 +1025,20 @@ int ih_fixusername(IH_HANDLER_PARAMS) void **p = EG(argument_stack).top_element-2; #endif unsigned long arg_count; - zval **arg;char *prefix, *postfix, *user; + zval **arg; + char *prefix, *postfix, *user, *user_match, *cp; zval *backup, *my_user; int prefix_len, postfix_len, len; - SDEBUG("function: %s", ih->name); + SDEBUG("function (fixusername): %s", ih->name); prefix = SUHOSIN_G(sql_user_prefix); postfix = SUHOSIN_G(sql_user_postfix); + user_match = SUHOSIN_G(sql_user_match); - if ((prefix == NULL || prefix[0] == 0)&& - (postfix == NULL || postfix[0] == 0)) { + if ((prefix == NULL || prefix[0] == 0) && + (postfix == NULL || postfix[0] == 0) && + (user_match == NULL || user_match[0] == 0)) { return (0); } @@ -1065,23 +1069,40 @@ int ih_fixusername(IH_HANDLER_PARAMS) user = Z_STRVAL_P(backup); } - if (prefix_len && prefix_len <= len) { - if (strncmp(prefix, user, prefix_len)==0) { - prefix = ""; - len -= prefix_len; - } - } - - if (postfix_len && postfix_len <= len) { - if (strncmp(postfix, user+len-postfix_len, postfix_len)==0) { - postfix = ""; + cp = user; + while (cp < user+len) { + if (*cp < 32) { + suhosin_log(S_SQL, "SQL username contains invalid characters"); + if (!SUHOSIN_G(simulation)) { + suhosin_bailout(TSRMLS_C); + } } + cp++; } - + MAKE_STD_ZVAL(my_user); my_user->type = IS_STRING; my_user->value.str.len = spprintf(&my_user->value.str.val, 0, "%s%s%s", prefix, user, postfix); + if (user_match && user_match[0]) { + len = Z_STRLEN_P(my_user); + user = Z_STRVAL_P(my_user); +#ifdef HAVE_FNMATCH + if (fnmatch(user_match, user, 0) != 0) { + suhosin_log(S_SQL, "SQL username ('%s') does not match suhosin.sql.user_match ('%s')", user, user_match); + if (!SUHOSIN_G(simulation)) { + suhosin_bailout(TSRMLS_C); + } + } +#else +#warning no support for fnmatch() - setting suhosin.sql.user_match will always fail. + suhosin_log(S_SQL, "suhosin.sql.user_match specified, but system does not support fnmatch()"); + if (!SUHOSIN_G(simulation)) { + suhosin_bailout(TSRMLS_C); + } +#endif + } + /* XXX: memory_leak? */ *arg = my_user; diff --git a/php_suhosin.h b/php_suhosin.h index e5604a7..e85fc38 100644 --- a/php_suhosin.h +++ b/php_suhosin.h @@ -76,15 +76,16 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) char *filter_action; char *sql_user_prefix; char *sql_user_postfix; - long sql_comment; - long sql_opencomment; - long sql_union; - long sql_mselect; + char *sql_user_match; + long sql_comment; + long sql_opencomment; + long sql_union; + long sql_mselect; long max_execution_depth; zend_bool abort_request; long executor_include_max_traversal; - zend_bool executor_include_allow_writable_files; + zend_bool executor_include_allow_writable_files; HashTable *include_whitelist; @@ -152,11 +153,11 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) zend_bool upload_remove_binary; char *upload_verification_script; - zend_bool no_more_variables; - zend_bool no_more_get_variables; - zend_bool no_more_post_variables; - zend_bool no_more_cookie_variables; - zend_bool no_more_uploads; + zend_bool no_more_variables; + zend_bool no_more_get_variables; + zend_bool no_more_post_variables; + zend_bool no_more_cookie_variables; + zend_bool no_more_uploads; @@ -198,8 +199,8 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) int (*old_s_destroy)(void **mod_data, const char *key TSRMLS_DC); BYTE fi[24],ri[24]; - WORD fkey[120]; - WORD rkey[120]; + WORD fkey[120]; + WORD rkey[120]; zend_bool session_encrypt; char* session_cryptkey; @@ -247,16 +248,16 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) zend_bool mt_is_seeded; /* PERDIR Handling */ - char *perdir; - zend_bool log_perdir; - zend_bool exec_perdir; - zend_bool get_perdir; - zend_bool post_perdir; - zend_bool cookie_perdir; - zend_bool request_perdir; - zend_bool upload_perdir; - zend_bool sql_perdir; - zend_bool misc_perdir; + char *perdir; + zend_bool log_perdir; + zend_bool exec_perdir; + zend_bool get_perdir; + zend_bool post_perdir; + zend_bool cookie_perdir; + zend_bool request_perdir; + zend_bool upload_perdir; + zend_bool sql_perdir; + zend_bool misc_perdir; ZEND_END_MODULE_GLOBALS(suhosin) diff --git a/suhosin.c b/suhosin.c index 0d1eba0..469e88f 100644 --- a/suhosin.c +++ b/suhosin.c @@ -989,13 +989,14 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("suhosin.upload.verification_script", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadString, upload_verification_script, zend_suhosin_globals, suhosin_globals) - STD_ZEND_INI_BOOLEAN("suhosin.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSQLBool, sql_bailout_on_error, zend_suhosin_globals, suhosin_globals) - STD_PHP_INI_ENTRY("suhosin.sql.user_prefix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_prefix, zend_suhosin_globals, suhosin_globals) - STD_PHP_INI_ENTRY("suhosin.sql.user_postfix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_postfix, zend_suhosin_globals, suhosin_globals) - STD_PHP_INI_ENTRY("suhosin.sql.comment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_comment, zend_suhosin_globals, suhosin_globals) - STD_PHP_INI_ENTRY("suhosin.sql.opencomment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_opencomment, zend_suhosin_globals, suhosin_globals) - STD_PHP_INI_ENTRY("suhosin.sql.multiselect", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_mselect, zend_suhosin_globals, suhosin_globals) - STD_PHP_INI_ENTRY("suhosin.sql.union", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_union, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSQLBool, sql_bailout_on_error, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.user_prefix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_prefix, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.user_postfix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_postfix, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.user_match", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_match, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.comment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_comment, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.opencomment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_opencomment, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.multiselect", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_mselect, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.union", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_union, zend_suhosin_globals, suhosin_globals) STD_ZEND_INI_BOOLEAN("suhosin.session.encrypt", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, session_encrypt, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.session.cryptkey", "", PHP_INI_ALL, OnUpdateString, session_cryptkey, zend_suhosin_globals, suhosin_globals) diff --git a/tests/sql/mysqli_user_match_error.phpt b/tests/sql/mysqli_user_match_error.phpt new file mode 100644 index 0000000..69db081 --- /dev/null +++ b/tests/sql/mysqli_user_match_error.phpt @@ -0,0 +1,18 @@ +--TEST-- +Mysqli connect with user_match not matching username +--INI-- +extension=mysqli.so +suhosin.sql.user_match=complicated_userprefix* +suhosin.log.stdout=32 +--SKIPIF-- + +--FILE-- + +--EXPECTREGEX-- +ALERT - SQL username .* does not match.* \ No newline at end of file diff --git a/tests/sql/mysqli_user_match_ok.phpt b/tests/sql/mysqli_user_match_ok.phpt new file mode 100644 index 0000000..4d7a438 --- /dev/null +++ b/tests/sql/mysqli_user_match_ok.phpt @@ -0,0 +1,18 @@ +--TEST-- +Mysqli connect with user_match not matching username +--INI-- +extension=mysqli.so +suhosin.sql.user_match=invalid_* +suhosin.log.stdout=32 +--SKIPIF-- + +--FILE-- + +--EXPECTREGEX-- +.*Access denied for user 'invalid_username'.* \ No newline at end of file -- cgit v1.3