Sat, 17 Mar 2007


Since PHP 5.2.0 there is a new memory manager that allows exploiting of even one byte underflow vulnerabilities like the one described by this advisory.

When an all whitespace string is passed to the header() function this can result in a buffer underflow that allows code execution on atleast big endian systems like MacOS X on PPC.

Affected versions

Affected is PHP 5.2.0

Detailed information

PHP 5.2.0 comes with a brand new memory manager that is no longer a simple wrapper around malloc()/free() but implements a own heap implementation for the request memory pool. The new heap manager stores control information inbound and is therefore vulnerable to overflow attacks. Additionally it is unlike the previous memory manager vulnerable against one byte underflows.

When the header() function is called. It will first perform a whitespace trimming on the parameter. This is performed by the following code.

    /* cut of trailing spaces, linefeeds and carriage-returns */

The code trims the trailing whitespace by moving backward through the header and overwriting NULL bytes over the end. Unfortunately the trimming does not work correctly on an all whitespace string, because the move backward does not stop at the beginning of the string. Therefore the trimming operation will write NULL bytes infront of the allocated buffer when the bytes before the buffer start contain ASCII characters belonging to the whitespace charset.

The new memory manager stores the size of the previous memory block infront of the buffer. On a little endian system it is therefore possible but unrealistic that the byte infront of the buffer contains a whitespace character. However on big endian systems like PPC it is possible for a remote attacker to create a heap layout that results in a whitespace character infront of the buffer. The trimming function will overwrite it with a NULL byte. The control information is therefore corrupted and a standard attack against the unlink from the linked list of free blocks is possible, which can result in remote code execution as demonstrated by the POC.

$ gdb ./php
(gdb) run MOPB-25-2007.php
Starting program: /Users/Benutzer/php-5.2.0/sapi/cli/php MOPB-25-2007.php
Reading symbols for shared libraries . done

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x55555561
_zend_mm_free_int (heap=0x2000400, p=0xcba9e8) at /Users/Benutzer/php-5.2.0/Zend/zend_alloc.c:480
480             prev->next_free_block = next;

This shows the typical crash inside the linked freelist unlink. By using good offsets it is possible to execute arbitrary code. The demonstration exploit works locally and can therefore determine the needed offsets automatically through the substr_compare() information leak vulnerability. This looks like this.

$ gdb ./php
(gdb) run MOPB-25-2007.php
Starting program: /Users/Benutzer/php-5.2.0/sapi/cli/php MOPB-25-2007.php
Reading symbols for shared libraries . done
Program received signal SIGINT, Interrupt.
0x00cd4544 in ?? ()
(gdb) x/20x $pc
0xcd4544:       0x44000002      0x7c000278      0x7c7e1b78      0x38a00002
0xcd4554:       0x3800005a      0x7fc3f378      0x7ca42b78      0x44000002
0xcd4564:       0x7c000278      0x38a5ffff      0x2c05ffff      0x4082ffe5
0xcd4574:       0x38000042      0x44000002      0x7c000278      0x7ca52a79
0xcd4584:       0x4082fffd      0x7c6802a6      0x38630028      0x9061fff8
(gdb) x/5i $pc
0xcd4594:       stw     r5,-4(r1)
0xcd4598:       addi    r4,r1,-8
0xcd459c:       li      r0,59
0xcd45a0:       sync
0xcd45a4:       sc
(gdb) bt
#0  0x00cd4544 in ?? ()
#1  0x00cd44fc in ?? ()
warning: Previous frame identical to this frame (corrupt stack?)
#2  0x0020ffd8 in _zval_dtor_func (zvalue=0xb) at /.../php-5.2.0/Zend/zend_variables.c:43
#3  0x00204144 in _zval_ptr_dtor (zval_ptr=0xcbb4bc) at /.../php-5.2.0/Zend/zend_variables.h:35
(gdb) continue

This example shows a successfull code execution exploit that currently waits for someone to connect to port 4444.

Proof of concept, exploit or instructions to reproduce

The attached exploit demonstrates that the buffer underflow is exploitable and allows code execution on the demonstration platform MacOS X on PPC. Actually the exploit is identical to the MOPB-19-2007 exploit with just the exploited function exchanged and the output removed because otherwise header() will fail

The exploit uses the substr_compare() information leak vulnerability to determine what offsets to overwrite.

When successfull the attached exploit will spawn a shell on port 4444. Shellcode was borrowed from the Metasploit shellcode generator.


This vulnerability could theoretically be triggered from remote. Many PHP applications are still vulnerable to header() injection. However for a remote exploit to work this injection has to be at the start of the string (with a \0 byte truncation).

Another thing this exploit demonstrates is how whole exploits can be reused against similar vulnerabilities without real changes.