Vulnerabilidad crítica en PHP producida al corregir otra

Stefan Esser (@i0n1c), consultor de seguridad independiente y creador de la popular extensión de seguridad Suhosin para PHP, identificó hace unos días un fallo de seguridad crítico que puede ser explotado para ejecutar código arbitrario en los servidores con PHP 5.3.9 y anteriores.

Lo gracioso es que, esta vulnerabilidad ya catalogada como CVE-2012-0830, fue introdudica accidentalmente a principios de enero para corregir otra vulnerabilidad, la CVE-2011-4885, que solucionaba un DoS por colisiones de hashes.

Esta corrección añadió la propiedad 'max_input_vars' en php.ini que limita el número de variables que pueden ser usados en una petición (por ej. http://request.com/foo.php?a=1&b=2&c=3), por defecto hasta un máximo de 1.000.

Los cambios fueron hechos en 'php_variables.c', que registra todas las variables de una petición llamando a la función vulnerable 'register_variable_ex':

 PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array TSRMLS_DC)
{
...tons of code removed...
if (is_array) {
... code removed ...
if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
}
MAKE_STD_ZVAL(gpc_element);
array_init(gpc_element);
zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
}
... some code removed...
symtable1 = Z_ARRVAL_PP(gpc_element_p);
... tons more code removed ...
}

El problema es que cuando el número de variables excede los declarados en 'max_input_vars' y la variable es de tipo array (if (*p == ‘[')), en vez de parar y volver, el código continua ejecutándose hasta la macro 'Z_ARRVAL_PP'. Esta macro intenta obtener una referencia de la tabla de hashes con un valor 'gpc_element_p' que no ha sido inicializado en memoria (si se trata de un array como comentamos). Es ahí donde puede ocurrir la ejecución arbitraria de código.

Ya existen varias PoC en Internet (vease el de Paul Westin y el de Worawit (sleepya)) y, sobretodo, una nueva versión de PHP para solucionarlo: la 5.3.10.

Comentarios