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 is PHP 5.2.0
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 */ while(isspace(header_line[header_line_len-1])) header_line[--header_line_len]='\0';
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 ^C 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.