Fri, 02 Mar 2007


The Month of PHP Bugs started with one of the possible ways to exploit the 16bit reference counter of PHP 4. It was only exploitable with local access. However because PHP does not protect against these overflows anywhere there are other exploit vectors. With unserialize() it is triggerable remotely because many popular PHP applications still use unserialize() on user supplied data. For example phpBB2.

Affected versions

Affected is only PHP 4.4.4 and below.

The PHP developers forgot to mention this important security bugfix in the PHP 4.4.5 release announcement.

Detailed information

MOPB-01-2007 already described the general problem with a 16bit reference counter. When it overflows this can lead to arbitrary code execution.

That this is even remotely possible is demonstrated by the unserialize() function that is used to deserialize previously serialized PHP variables. It is actually never a good idea to feed user data to unserialize() because PHP will call the __wakeup() method of deserialised objects and this might result in unintended code execution. However the PHP manual called it a data exchange format for a long time and therefore many popular PHP applications like phpBB2 use it to decode serialized data stored in the cookie.

Whenever unserialize() is used on an attacker supplied string, this can result in a ZVAL reference counter overflow which can be exploited to execute arbitrary code.

The following demonstrates the gdb debugging session that shows how a remote version of the exploit is launched against a phpBB2 2.0.22 forum.

$ gdb
(gdb) attach 12345
(gdb) continue(gdb) continue

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1211611456 (LWP 9582)]
0x99887766 in ?? ()
(gdb) i r eip
eip            0x99887766       0x99887766
(gdb) zbacktrace
[0xbf845ac0] unserialize() /var/www/forum/includes/sessions.php:283
[0xbf84c560] session_pagestart() /var/www/forum/index.php:31

From the backtrace and the registers one can see that PHP's unserialize resulted in an attempt to execute code at 0x99887766 which is the attacker supplied offset and in our case points to not mapped memory. Therefore it crashs. However if you put in a pointer to your shellcode it will execute it.

Proof of concept, exploit or instructions to reproduce

The attached exploit will demonstrate how one can control the instruction pointer with an unserialize() string. To get it to execute code an offset to your own shellcode is needed. Additionally the string will not work out of the box against for example phpBB2, because it is very long and does not fit into a simple cookie.


PHP 4.4.5 already contains a hard limit of 65500 references in the unserialize() code and is therefore not vulnerable anymore.

Actually I commited that fix myself 4 months ago. The PHP Security Response Team seems to have forgotten that this important security fix was made. And this is the usual problem with PHP. If there is no external advisory the normal user will never realise that there was an important bugfix. On the other hand the "bad guys" have this information for 4 months now by watching the CVS commit list.

However when you cannot upgrade you can protect yourself with Suhosin or with a web application firewall, because the attack string you need to supply to unserialize() is more than 500kbytes big.