Ever wonder what it takes to crash PHP, well here is a quick guide
. Technically speaking PHP being a high level language should not crash, but reality speaks for itself. By knowing what could make PHP crash it may be possible to implement various safety mechanisms in your PHP configuration that would prevent users from crashing your PHP. This is quite important since a crash is not only a 'bad thing' [tm] in general but can also have several adverse affect on the web server potentially creating a possibility for a local DOS (Denial of Service). So without further ado here is the current crash list:
- Stack overflow. PHP does not have any internal stack protection choosing to rely upon the system stack without any protection. This means that if you have a recursive function or a method PHP will eventually crash.
function a() { a(); } a();
There are 2 solutions to this problem, 1 avoid using recursive functions they are generally a bad idea anyway, and if you MUST use them implement some counter using a global variable that would prevent the function from iterating itself more then X amount of time for values of X between 500 to 1000. The other solution involves using the xdebug extension that implements protection against stack overflows by defining a limit on how deep can recursive functions go via a php.ini value. This is a better solution in hosting environments where you have no control over the scripts that are being ran on the server.
- Bug inside the pack() function. This is not a terribly common function, however it is a part of the standard PHP distribution meaning that despite it's rare usage everyone has it and is vulnreable to it.
The nature of the crash involves making PHP to try to allocate more memory then is generally avaliable on the system, when this happens PHP will immediately exit terminating the request or if you are using the debug build dump core and crash
pack("d4294967297", 2);
The only solution to this problem at this time to disable the pack function via the disable_functions php.ini directive and hopefuly non of your scripts or the scripts used by your users (hosting environment) use this functionality. Like I mentioned earlier this function is pretty rarely used so this is a more or less valid solution. Another solution is to enable memory_limit directive that would set the limit on the maximum amount of memory PHP script may use and when it tries to use more PHP will nicely terminate the request and not cause the termination of the child/process used to serve the request.
- Various header parsing vulnerabilities. Through a series of extensions PHP has the ability to work with images, these extensions include exif, GD, imagemagick, ext/standard's getimagesize(). To work with images PHP often needs to allocate various buffer to store the image data. The size of these buffers is determined by parsing the image header that contains this data. By modifying this data via the use of hexeditor or generating a bogus image header you can force PHP through those image extension to try to allocate more memory then avaliable or try to allocate invalid memory value such as -1 resulting in a crash.
No example given since it would make it too easy to exploit, which is especially bad since many of these functions are often used to work on external images that web users can often specify. What it means that vulnerabilities of this nature have a potential of being exploited remotely.
In most cases there are sufficient checks to prevent allocation of invalid memory sizes such as -1, so most common problem would be overallocation problem identical to the one in item #2. Just about the only solution other then the disabling of these extensions (fine solution if you don't use them) is to once again use memory_limit to prevent PHP from trying to allocate more memory then it should/can.
- Stack overflow in GD library that is exposed via the imagefilltoborder() function. The internals of this function rely on a recursive function call that given a certain type of image can result in a stack overflow.
You can find an example of a crash script inside the ext/gd/tests/bug27582_2.phpt test.
The solution to the problem would be to rewrite the GD library function that imagefilltoborder() is a wrapper of in such a way that the recursive function algorithm is not being used. Meanwhile the only fix to the problem is to use the disable_functions directive to prevent users from accessing this function.
- Forced over-allocation inside unserialize function.
$a = "a";
unserialize(str_replace('1', 2147483647, serialize($a)));
Once we can 'force' PHP to try to allocate more memory then it can resulting in a request termination. The solution is once again to use memory_limit to allow PHP to handle the situation safely.
- Refcount overflow. In ZendEngine 1 the number of references to a particular variable is limited to 65535 because they are stored inside an unsigned short. This is something fixed in ZendEgine 2 where this value is stored inside an integer with a much greater capacity. However, since stable PHP is built against ZendEngine 1 this means that any PHP 4.X is vulnreable to this problem and what's even worse there is no easy solution.
$t = array(1);
while (1) {
$a[] = &$t;
}
The only way to prevent this problem in PHP4 is to apply the following patch and rebuild your PHP. If you are using any external Zend or PHP modules those would need to be rebuilt as well. The only time you will not be able to do this if you are using binary modules that you cannot recompile because you do not have access to their source, such as PHPA, Zend extensions, etc...
CODE:
Index: zend.h
====================================
RCS file: /repository/Zend/Attic/zend.h,v
retrieving revision 1.164.2.21
diff -u -3 -p -r1.164.2.21 zend.h
--- zend.h 16 Mar 2004 17:36:17 -0000 1.164.2.21
+++ zend.h 14 Apr 2004 18:01:37 -0000
@@ -263,7 +263,7 @@ struct _zval_struct {
zvalue_value value; /* value */
zend_uchar type; /* active type */
zend_uchar is_ref;
- zend_ushort refcount;
+ int refcount;
};
- Since the previous crash was specific to PHP4 let's have one specific to PHP5 to keep things fair. As you may know in PHP5 a number of extensions (SQlite, Tidy, etc...) implement native OO interface, which is very convenient, but has 1 problem. Due to the destruct order of externally loadable modules loaded via dl() function (deprecated btw) the module would be freed before the objects created by that module are freed. The end result is that when PHP tries to free the object the 'free' functions are no longer avaliable (they were inside the module) and PHP crashes.
dl("sqlite.so");
$db = new SqliteDatabase("foo");
The solution to this problem is to either disable dl(), people should not be using it away, needed extensions should be loaded via PHP.ini or ensure that you manually destroy any objects created by that extensions by using unset().
- PCRE library bug. While this not a PHP bug per say since the cause of the bug is the bundled pcre library (non-bundled library suffers from the same problem) it still allows a PHP script to crash the process.
preg_match('/(.(?!b))*/', str_repeat("a", 10000));
There is no solution to this bug at this time, it is my hope that PCRE developers will consider this problem and implement a fix for it in the next release.
- Back to the old favorite, memory allocation. This time str_repeat() function allows us to very easily make PHP try to allocate excessive amount of memory and crash or exit when it fails to do so.
str_repeat("a", 10000000000);
The solution once again is to use memory_limit to allow PHP to handle the situation gracefully.
- The last way is not really a crash but still a very effective nastiness a disgruntled user can do on an Apache server.
shell_exec("killall -11 httpd");
As you can imagine this little command will result in the termination of all running apache children other the deamon that is running as root since all Apache children run under the same privilege meaning that 1 child could kill the rest. There are several protections against this, first of all make sure that the environment variable PATH for your webserver does not contain any dangerous paths, such as the ones containing kill & killall utilities. You can also disable execution commands by enabling safe_mode or using the disable_functions directive. The last solution is to run PHP as CGI or FastCGI where the processes would run under the same user as the one executing the script. This means that PHP script will not have permissions allowing it to kill Apache children.
There are a number of other crashes in PHP, some were fixed and some may still be present. However those tend to be inside obscure extensions that most people do not have enabled and as such are very unlikely. Other crashes while may still exist are in the process of being resolved, unlike the ones listed above that are likely to be around for quite a while.
Taufpate´s a basic life on : Top 10 ways to crash PHP