The session_regenerate_id() function that is used to generate a new session identifier fails to clear an already freed pointer to the former session identifier before calling the session identifier generator. When this generator triggers an error this can result in a double free that is easily exploitable locally and might be remotely exploitable.
The session_regenerate_id() function first frees the old session identifier and then immediately assigns a new value generated by the session identifier generator.
PHP_FUNCTION(session_regenerate_id)
{
...
if (PS(id)) {
...
efree(PS(id));
}
PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
PS(send_cookie) = 1;
php_session_reset_id(TSRMLS_C);
RETURN_TRUE;
}
RETURN_FALSE;
}
However this assignment is not an atomic operation an can be interrupted by for example a memory limit violation. Additionally, depending on the PHP configuration, the generator can trigger PHP errors that will also lead to an interruption.
PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS)
{
...
switch (PS(hash_func)) {
...
default:
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
efree(buf);
return NULL;
}
...
if (PS(hash_bits_per_character) < 4
|| PS(hash_bits_per_character) > 6) {
PS(hash_bits_per_character) = 4;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ini setting hash_bits_per_character...");
}
...
Because of this it is trivial to exploit this problem locally by registering a malicious userspace error handler. When this handler is called a Hashtable is allocated into the same place as the former session identifier. Then the malicious error handler can trigger another free of the former session identifier by calling the session_id() function and allocate a string containing a fake Hashtable into the same place as the Hashtable. When the user error handler is finished it will destruct the overwritten Hashtable and call the attacker supplied code.
Proof of concept, exploit or instructions to reproduce
When the attached exploit is executed, it will use the substr_compare() information leak vulnerability to determine the address of the shellcode and use the vulnerability to execute it.
Notes
This vulnerability is very easy to exploit locally with a user defined error handler. However a double free is also triggered when the request shutdown is triggered during the session identifier generation. This could for example be caused by a memory limit violation during the session identifier generation.
Therefore it seems possible but highly complicated to trigger this bug remotely. We might dig into this in the future to verify if our assumption is correct.
SecurityReason Note :
Exploit - http://securityreason.com/exploitalert/2113