Skip to content

Commit 15ddc5b

Browse files
committed
Add XSS attack protect in magic variables $_GET and $_POST
1 parent 677a1f8 commit 15ddc5b

File tree

1 file changed

+113
-96
lines changed

1 file changed

+113
-96
lines changed

main/php_variables.c

Lines changed: 113 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ static bool php_is_forbidden_variable_name(const char *mangled_name, size_t mang
105105
return false;
106106
}
107107

108+
108109
PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *track_vars_array)
109110
{
110111
char *p = NULL;
@@ -341,55 +342,59 @@ typedef struct post_var_data {
341342

342343
static bool add_post_var(zval *arr, post_var_data_t *var, bool eof)
343344
{
344-
char *start, *ksep, *vsep, *val;
345-
size_t klen, vlen;
346-
size_t new_vlen;
347-
348-
if (var->ptr >= var->end) {
349-
return 0;
350-
}
351-
352-
start = var->ptr + var->already_scanned;
353-
vsep = memchr(start, '&', var->end - start);
354-
if (!vsep) {
355-
if (!eof) {
356-
var->already_scanned = var->end - var->ptr;
357-
return 0;
358-
} else {
359-
vsep = var->end;
360-
}
361-
}
362-
363-
ksep = memchr(var->ptr, '=', vsep - var->ptr);
364-
if (ksep) {
365-
*ksep = '\0';
366-
/* "foo=bar&" or "foo=&" */
367-
klen = ksep - var->ptr;
368-
vlen = vsep - ++ksep;
369-
} else {
370-
ksep = "";
371-
/* "foo&" */
372-
klen = vsep - var->ptr;
373-
vlen = 0;
374-
}
375-
376-
php_url_decode(var->ptr, klen);
377-
378-
val = estrndup(ksep, vlen);
379-
if (vlen) {
380-
vlen = php_url_decode(val, vlen);
381-
}
382-
383-
if (sapi_module.input_filter(PARSE_POST, var->ptr, &val, vlen, &new_vlen)) {
384-
php_register_variable_safe(var->ptr, val, new_vlen, arr);
385-
}
386-
efree(val);
387-
388-
var->ptr = vsep + (vsep != var->end);
389-
var->already_scanned = 0;
390-
return 1;
345+
char *start, *ksep, *vsep, *val;
346+
size_t klen, vlen;
347+
size_t new_vlen;
348+
349+
if (var->ptr >= var->end) {
350+
return 0;
351+
}
352+
353+
start = var->ptr + var->already_scanned;
354+
vsep = memchr(start, '&', var->end - start);
355+
if (!vsep) {
356+
if (!eof) {
357+
var->already_scanned = var->end - var->ptr;
358+
return 0;
359+
} else {
360+
vsep = var->end;
361+
}
362+
}
363+
364+
ksep = memchr(var->ptr, '=', vsep - var->ptr);
365+
if (ksep) {
366+
*ksep = '\0';
367+
/* "foo=bar&" or "foo=&" */
368+
klen = ksep - var->ptr;
369+
vlen = vsep - ++ksep;
370+
} else {
371+
ksep = "";
372+
/* "foo&" */
373+
klen = vsep - var->ptr;
374+
vlen = 0;
375+
}
376+
377+
php_url_decode(var->ptr, klen);
378+
379+
val = estrndup(ksep, vlen);
380+
if (vlen) {
381+
vlen = php_url_decode(val, vlen);
382+
}
383+
384+
php_sanitize_value(val, vlen);
385+
vlen = strlen(val);
386+
387+
if (sapi_module.input_filter(PARSE_POST, var->ptr, &val, vlen, &new_vlen)) {
388+
php_register_variable_safe(var->ptr, val, new_vlen, arr);
389+
}
390+
efree(val);
391+
392+
var->ptr = vsep + (vsep != var->end);
393+
var->already_scanned = 0;
394+
return 1;
391395
}
392396

397+
393398
static inline int add_post_vars(zval *arr, post_var_data_t *vars, bool eof)
394399
{
395400
uint64_t max_vars = REQUEST_PARSE_BODY_OPTION_GET(max_input_vars, PG(max_input_vars));
@@ -536,57 +541,58 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data)
536541

537542
var = php_strtok_r(res, separator, &strtok_buf);
538543

539-
while (var) {
540-
size_t val_len;
541-
size_t new_val_len;
542-
543-
val = strchr(var, '=');
544544

545-
if (arg == PARSE_COOKIE) {
546-
/* Remove leading spaces from cookie names, needed for multi-cookie header where ; can be followed by a space */
547-
while (isspace(*var)) {
548-
var++;
549-
}
550-
if (var == val || *var == '\0') {
551-
goto next_cookie;
552-
}
553-
}
554-
555-
zend_long max_input_vars = REQUEST_PARSE_BODY_OPTION_GET(max_input_vars, PG(max_input_vars));
556-
if (++count > max_input_vars) {
557-
php_error_docref(NULL, E_WARNING, "Input variables exceeded " ZEND_LONG_FMT ". To increase the limit change max_input_vars in php.ini.", max_input_vars);
558-
break;
559-
}
560-
561-
if (val) { /* have a value */
562-
563-
*val++ = '\0';
564-
565-
if (arg == PARSE_COOKIE) {
566-
val_len = php_raw_url_decode(val, strlen(val));
567-
} else {
568-
val_len = php_url_decode(val, strlen(val));
569-
}
570-
} else {
571-
val = "";
572-
val_len = 0;
573-
}
574-
575-
val = estrndup(val, val_len);
576-
if (arg != PARSE_COOKIE) {
577-
php_url_decode(var, strlen(var));
578-
}
579-
if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) {
580-
php_register_variable_safe(var, val, new_val_len, &array);
581-
}
582-
efree(val);
545+
while (var) {
546+
size_t val_len;
547+
size_t new_val_len;
548+
549+
val = strchr(var, '=');
550+
551+
if (arg == PARSE_COOKIE) {
552+
/* Remove leading spaces from cookie names, needed for multi-cookie header where ; can be followed by a space */
553+
while (isspace(*var)) {
554+
var++;
555+
}
556+
if (var == val || *var == '\0') {
557+
goto next_cookie;
558+
}
559+
}
560+
561+
zend_long max_input_vars = REQUEST_PARSE_BODY_OPTION_GET(max_input_vars, PG(max_input_vars));
562+
if (++count > max_input_vars) {
563+
php_error_docref(NULL, E_WARNING, "Input variables exceeded " ZEND_LONG_FMT ". To increase the limit change max_input_vars in php.ini.", max_input_vars);
564+
break;
565+
}
566+
567+
if (val) { /* have a value */
568+
*val++ = '\0';
569+
570+
if (arg == PARSE_COOKIE) {
571+
val_len = php_raw_url_decode(val, strlen(val));
572+
} else {
573+
val_len = php_url_decode(val, strlen(val));
574+
}
575+
} else {
576+
val = "";
577+
val_len = 0;
578+
}
579+
580+
val = estrndup(val, val_len);
581+
if (arg != PARSE_COOKIE) {
582+
php_url_decode(var, strlen(var));
583+
}
584+
php_sanitize_value(val, val_len);
585+
val_len = strlen(val);
586+
if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) {
587+
php_register_variable_safe(var, val, new_val_len, &array);
588+
}
589+
efree(val);
583590
next_cookie:
584-
var = php_strtok_r(NULL, separator, &strtok_buf);
585-
}
586-
587-
if (free_buffer) {
588-
efree(res);
589-
}
591+
var = php_strtok_r(NULL, separator, &strtok_buf);
592+
}
593+
if (free_buffer) {
594+
efree(res);
595+
}
590596
}
591597

592598
static zend_always_inline int valid_environment_name(const char *name, const char *end)
@@ -978,3 +984,14 @@ void php_startup_auto_globals(void)
978984
zend_register_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST), PG(auto_globals_jit), php_auto_globals_create_request);
979985
zend_register_auto_global(zend_string_init_interned("_FILES", sizeof("_FILES")-1, 1), 0, php_auto_globals_create_files);
980986
}
987+
988+
void php_sanitize_value(char *value, size_t len) {
989+
size_t write_index = 0;
990+
for (size_t read_index = 0; read_index < len; read_index++) {
991+
if (value[read_index] != '<' && value[read_index] != '>' && value[read_index] != '/') {
992+
value[write_index] = value[read_index];
993+
write_index++;
994+
}
995+
}
996+
value[write_index] = '\0';
997+
}

0 commit comments

Comments
 (0)