diff options
| -rw-r--r-- | Changelog | 4 | ||||
| -rw-r--r-- | execute.c | 51 | ||||
| -rw-r--r-- | php_suhosin.h | 45 | ||||
| -rw-r--r-- | suhosin.c | 15 | ||||
| -rw-r--r-- | tests/sql/mysqli_user_match_error.phpt | 18 | ||||
| -rw-r--r-- | tests/sql/mysqli_user_match_ok.phpt | 18 |
6 files changed, 106 insertions, 45 deletions
| @@ -1,6 +1,8 @@ | |||
| 1 | 2014-06-24 - 0.9.37-dev | 1 | 2014-06-24 - 0.9.37-dev |
| 2 | 2 | ||
| 3 | - Added SQL injection protection for Mysqli and several test cases | 3 | - Added SQL injection protection for Mysqli and several test cases |
| 4 | - Added wildcard matching for SQL username | ||
| 5 | - Added check for SQL username to only contain valid characters (>= ASCII 32) | ||
| 4 | 6 | ||
| 5 | 2014-06-10 - 0.9.36 | 7 | 2014-06-10 - 0.9.36 |
| 6 | 8 | ||
| @@ -24,6 +24,7 @@ | |||
| 24 | #endif | 24 | #endif |
| 25 | 25 | ||
| 26 | #include <fcntl.h> | 26 | #include <fcntl.h> |
| 27 | #include <fnmatch.h> | ||
| 27 | #include "php.h" | 28 | #include "php.h" |
| 28 | #include "php_ini.h" | 29 | #include "php_ini.h" |
| 29 | #include "zend_hash.h" | 30 | #include "zend_hash.h" |
| @@ -1024,17 +1025,20 @@ int ih_fixusername(IH_HANDLER_PARAMS) | |||
| 1024 | void **p = EG(argument_stack).top_element-2; | 1025 | void **p = EG(argument_stack).top_element-2; |
| 1025 | #endif | 1026 | #endif |
| 1026 | unsigned long arg_count; | 1027 | unsigned long arg_count; |
| 1027 | zval **arg;char *prefix, *postfix, *user; | 1028 | zval **arg; |
| 1029 | char *prefix, *postfix, *user, *user_match, *cp; | ||
| 1028 | zval *backup, *my_user; | 1030 | zval *backup, *my_user; |
| 1029 | int prefix_len, postfix_len, len; | 1031 | int prefix_len, postfix_len, len; |
| 1030 | 1032 | ||
| 1031 | SDEBUG("function: %s", ih->name); | 1033 | SDEBUG("function (fixusername): %s", ih->name); |
| 1032 | 1034 | ||
| 1033 | prefix = SUHOSIN_G(sql_user_prefix); | 1035 | prefix = SUHOSIN_G(sql_user_prefix); |
| 1034 | postfix = SUHOSIN_G(sql_user_postfix); | 1036 | postfix = SUHOSIN_G(sql_user_postfix); |
| 1037 | user_match = SUHOSIN_G(sql_user_match); | ||
| 1035 | 1038 | ||
| 1036 | if ((prefix == NULL || prefix[0] == 0)&& | 1039 | if ((prefix == NULL || prefix[0] == 0) && |
| 1037 | (postfix == NULL || postfix[0] == 0)) { | 1040 | (postfix == NULL || postfix[0] == 0) && |
| 1041 | (user_match == NULL || user_match[0] == 0)) { | ||
| 1038 | return (0); | 1042 | return (0); |
| 1039 | } | 1043 | } |
| 1040 | 1044 | ||
| @@ -1065,23 +1069,40 @@ int ih_fixusername(IH_HANDLER_PARAMS) | |||
| 1065 | user = Z_STRVAL_P(backup); | 1069 | user = Z_STRVAL_P(backup); |
| 1066 | } | 1070 | } |
| 1067 | 1071 | ||
| 1068 | if (prefix_len && prefix_len <= len) { | 1072 | cp = user; |
| 1069 | if (strncmp(prefix, user, prefix_len)==0) { | 1073 | while (cp < user+len) { |
| 1070 | prefix = ""; | 1074 | if (*cp < 32) { |
| 1071 | len -= prefix_len; | 1075 | suhosin_log(S_SQL, "SQL username contains invalid characters"); |
| 1072 | } | 1076 | if (!SUHOSIN_G(simulation)) { |
| 1073 | } | 1077 | suhosin_bailout(TSRMLS_C); |
| 1074 | 1078 | } | |
| 1075 | if (postfix_len && postfix_len <= len) { | ||
| 1076 | if (strncmp(postfix, user+len-postfix_len, postfix_len)==0) { | ||
| 1077 | postfix = ""; | ||
| 1078 | } | 1079 | } |
| 1080 | cp++; | ||
| 1079 | } | 1081 | } |
| 1080 | 1082 | ||
| 1081 | MAKE_STD_ZVAL(my_user); | 1083 | MAKE_STD_ZVAL(my_user); |
| 1082 | my_user->type = IS_STRING; | 1084 | my_user->type = IS_STRING; |
| 1083 | my_user->value.str.len = spprintf(&my_user->value.str.val, 0, "%s%s%s", prefix, user, postfix); | 1085 | my_user->value.str.len = spprintf(&my_user->value.str.val, 0, "%s%s%s", prefix, user, postfix); |
| 1084 | 1086 | ||
| 1087 | if (user_match && user_match[0]) { | ||
| 1088 | len = Z_STRLEN_P(my_user); | ||
| 1089 | user = Z_STRVAL_P(my_user); | ||
| 1090 | #ifdef HAVE_FNMATCH | ||
| 1091 | if (fnmatch(user_match, user, 0) != 0) { | ||
| 1092 | suhosin_log(S_SQL, "SQL username ('%s') does not match suhosin.sql.user_match ('%s')", user, user_match); | ||
| 1093 | if (!SUHOSIN_G(simulation)) { | ||
| 1094 | suhosin_bailout(TSRMLS_C); | ||
| 1095 | } | ||
| 1096 | } | ||
| 1097 | #else | ||
| 1098 | #warning no support for fnmatch() - setting suhosin.sql.user_match will always fail. | ||
| 1099 | suhosin_log(S_SQL, "suhosin.sql.user_match specified, but system does not support fnmatch()"); | ||
| 1100 | if (!SUHOSIN_G(simulation)) { | ||
| 1101 | suhosin_bailout(TSRMLS_C); | ||
| 1102 | } | ||
| 1103 | #endif | ||
| 1104 | } | ||
| 1105 | |||
| 1085 | /* XXX: memory_leak? */ | 1106 | /* XXX: memory_leak? */ |
| 1086 | *arg = my_user; | 1107 | *arg = my_user; |
| 1087 | 1108 | ||
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) | |||
| 76 | char *filter_action; | 76 | char *filter_action; |
| 77 | char *sql_user_prefix; | 77 | char *sql_user_prefix; |
| 78 | char *sql_user_postfix; | 78 | char *sql_user_postfix; |
| 79 | long sql_comment; | 79 | char *sql_user_match; |
| 80 | long sql_opencomment; | 80 | long sql_comment; |
| 81 | long sql_union; | 81 | long sql_opencomment; |
| 82 | long sql_mselect; | 82 | long sql_union; |
| 83 | long sql_mselect; | ||
| 83 | 84 | ||
| 84 | long max_execution_depth; | 85 | long max_execution_depth; |
| 85 | zend_bool abort_request; | 86 | zend_bool abort_request; |
| 86 | long executor_include_max_traversal; | 87 | long executor_include_max_traversal; |
| 87 | zend_bool executor_include_allow_writable_files; | 88 | zend_bool executor_include_allow_writable_files; |
| 88 | 89 | ||
| 89 | 90 | ||
| 90 | HashTable *include_whitelist; | 91 | HashTable *include_whitelist; |
| @@ -152,11 +153,11 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) | |||
| 152 | zend_bool upload_remove_binary; | 153 | zend_bool upload_remove_binary; |
| 153 | char *upload_verification_script; | 154 | char *upload_verification_script; |
| 154 | 155 | ||
| 155 | zend_bool no_more_variables; | 156 | zend_bool no_more_variables; |
| 156 | zend_bool no_more_get_variables; | 157 | zend_bool no_more_get_variables; |
| 157 | zend_bool no_more_post_variables; | 158 | zend_bool no_more_post_variables; |
| 158 | zend_bool no_more_cookie_variables; | 159 | zend_bool no_more_cookie_variables; |
| 159 | zend_bool no_more_uploads; | 160 | zend_bool no_more_uploads; |
| 160 | 161 | ||
| 161 | 162 | ||
| 162 | 163 | ||
| @@ -198,8 +199,8 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) | |||
| 198 | int (*old_s_destroy)(void **mod_data, const char *key TSRMLS_DC); | 199 | int (*old_s_destroy)(void **mod_data, const char *key TSRMLS_DC); |
| 199 | 200 | ||
| 200 | BYTE fi[24],ri[24]; | 201 | BYTE fi[24],ri[24]; |
| 201 | WORD fkey[120]; | 202 | WORD fkey[120]; |
| 202 | WORD rkey[120]; | 203 | WORD rkey[120]; |
| 203 | 204 | ||
| 204 | zend_bool session_encrypt; | 205 | zend_bool session_encrypt; |
| 205 | char* session_cryptkey; | 206 | char* session_cryptkey; |
| @@ -247,16 +248,16 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) | |||
| 247 | zend_bool mt_is_seeded; | 248 | zend_bool mt_is_seeded; |
| 248 | 249 | ||
| 249 | /* PERDIR Handling */ | 250 | /* PERDIR Handling */ |
| 250 | char *perdir; | 251 | char *perdir; |
| 251 | zend_bool log_perdir; | 252 | zend_bool log_perdir; |
| 252 | zend_bool exec_perdir; | 253 | zend_bool exec_perdir; |
| 253 | zend_bool get_perdir; | 254 | zend_bool get_perdir; |
| 254 | zend_bool post_perdir; | 255 | zend_bool post_perdir; |
| 255 | zend_bool cookie_perdir; | 256 | zend_bool cookie_perdir; |
| 256 | zend_bool request_perdir; | 257 | zend_bool request_perdir; |
| 257 | zend_bool upload_perdir; | 258 | zend_bool upload_perdir; |
| 258 | zend_bool sql_perdir; | 259 | zend_bool sql_perdir; |
| 259 | zend_bool misc_perdir; | 260 | zend_bool misc_perdir; |
| 260 | 261 | ||
| 261 | ZEND_END_MODULE_GLOBALS(suhosin) | 262 | ZEND_END_MODULE_GLOBALS(suhosin) |
| 262 | 263 | ||
| @@ -989,13 +989,14 @@ PHP_INI_BEGIN() | |||
| 989 | STD_PHP_INI_ENTRY("suhosin.upload.verification_script", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadString, upload_verification_script, zend_suhosin_globals, suhosin_globals) | 989 | STD_PHP_INI_ENTRY("suhosin.upload.verification_script", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadString, upload_verification_script, zend_suhosin_globals, suhosin_globals) |
| 990 | 990 | ||
| 991 | 991 | ||
| 992 | 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) | 992 | 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) |
| 993 | STD_PHP_INI_ENTRY("suhosin.sql.user_prefix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_prefix, zend_suhosin_globals, suhosin_globals) | 993 | STD_PHP_INI_ENTRY("suhosin.sql.user_prefix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_prefix, zend_suhosin_globals, suhosin_globals) |
| 994 | STD_PHP_INI_ENTRY("suhosin.sql.user_postfix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_postfix, zend_suhosin_globals, suhosin_globals) | 994 | STD_PHP_INI_ENTRY("suhosin.sql.user_postfix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_postfix, zend_suhosin_globals, suhosin_globals) |
| 995 | STD_PHP_INI_ENTRY("suhosin.sql.comment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_comment, zend_suhosin_globals, suhosin_globals) | 995 | STD_PHP_INI_ENTRY("suhosin.sql.user_match", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_match, zend_suhosin_globals, suhosin_globals) |
| 996 | STD_PHP_INI_ENTRY("suhosin.sql.opencomment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_opencomment, zend_suhosin_globals, suhosin_globals) | 996 | STD_PHP_INI_ENTRY("suhosin.sql.comment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_comment, zend_suhosin_globals, suhosin_globals) |
| 997 | STD_PHP_INI_ENTRY("suhosin.sql.multiselect", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_mselect, zend_suhosin_globals, suhosin_globals) | 997 | STD_PHP_INI_ENTRY("suhosin.sql.opencomment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_opencomment, zend_suhosin_globals, suhosin_globals) |
| 998 | STD_PHP_INI_ENTRY("suhosin.sql.union", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_union, zend_suhosin_globals, suhosin_globals) | 998 | STD_PHP_INI_ENTRY("suhosin.sql.multiselect", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_mselect, zend_suhosin_globals, suhosin_globals) |
| 999 | STD_PHP_INI_ENTRY("suhosin.sql.union", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_union, zend_suhosin_globals, suhosin_globals) | ||
| 999 | 1000 | ||
| 1000 | STD_ZEND_INI_BOOLEAN("suhosin.session.encrypt", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, session_encrypt, zend_suhosin_globals, suhosin_globals) | 1001 | STD_ZEND_INI_BOOLEAN("suhosin.session.encrypt", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, session_encrypt, zend_suhosin_globals, suhosin_globals) |
| 1001 | STD_PHP_INI_ENTRY("suhosin.session.cryptkey", "", PHP_INI_ALL, OnUpdateString, session_cryptkey, zend_suhosin_globals, suhosin_globals) | 1002 | 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 @@ | |||
| 1 | --TEST-- | ||
| 2 | Mysqli connect with user_match not matching username | ||
| 3 | --INI-- | ||
| 4 | extension=mysqli.so | ||
| 5 | suhosin.sql.user_match=complicated_userprefix* | ||
| 6 | suhosin.log.stdout=32 | ||
| 7 | --SKIPIF-- | ||
| 8 | <?php | ||
| 9 | include('skipifmysqli.inc'); | ||
| 10 | include('skipif.inc'); | ||
| 11 | ?> | ||
| 12 | --FILE-- | ||
| 13 | <?php | ||
| 14 | include('connect.inc'); | ||
| 15 | $mysqli = new mysqli($host, 'invalid_username', $passwd, $db, $port, $socket); | ||
| 16 | ?> | ||
| 17 | --EXPECTREGEX-- | ||
| 18 | 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 @@ | |||
| 1 | --TEST-- | ||
| 2 | Mysqli connect with user_match not matching username | ||
| 3 | --INI-- | ||
| 4 | extension=mysqli.so | ||
| 5 | suhosin.sql.user_match=invalid_* | ||
| 6 | suhosin.log.stdout=32 | ||
| 7 | --SKIPIF-- | ||
| 8 | <?php | ||
| 9 | include('skipifmysqli.inc'); | ||
| 10 | include('skipif.inc'); | ||
| 11 | ?> | ||
| 12 | --FILE-- | ||
| 13 | <?php | ||
| 14 | include('connect.inc'); | ||
| 15 | $mysqli = new mysqli($host, 'invalid_username', $passwd, $db, $port, $socket); | ||
| 16 | ?> | ||
| 17 | --EXPECTREGEX-- | ||
| 18 | .*Access denied for user 'invalid_username'.* \ No newline at end of file | ||
