Thu, 15 Mar 2007


Internal session storage modules can reject session identifiers since PHP 5.2.0 when they contain for example characters consideres malicious. When the session extension gets notified that the session id is invalid, it fails to clear an already freed pointer to the invalid 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.

Affected versions

Affected are PHP 5.2.0 and PHP 5.2.1

Detailed information

When an internal session storage module rejects a session identifier it notifies the session extension by setting a flag. At the moment only the default file storage module makes use of this. When this flag is encountered the invalid session identifier is freed and a newly generated one is assigned.

        PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
    PS(invalid_session_id) = 0;
    if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, &vallen TSRMLS_CC) == SUCCESS) {
        php_session_decode(val, vallen TSRMLS_CC);
    } else if (PS(invalid_session_id)) { /* address instances where ... due to an invalid id */
        PS(invalid_session_id) = 0;
        goto new_session;

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)) {
        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
        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 invalid 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 then triggers the vulnerability with a invalid session identifier which results in the shellcode being executed.


This vulnerability is very similiar to the previous one. However they are not the same vulnerability but only of the same type/class. Both code areas were introduced with different PHP versions and are not directly related to each other, although the exploits are nearly identical. Additionally this vulnerability, unlike the previous one, is easier to trigger from remote and therefore it is more likely to be exploitable from remote. We will dig into this in the future to verify if our assumption is correct.