Sat, 31 Mar 2007


The php_stream_filter_create() function does support wildcards in filter names for easier implementation. When a filter is not known and there is a dot in the filter name, everything behind is truncated and a * character is appended. This is done without taking the extra byte into account that is needed when the filtername ends on a dot. This results in an off by one overflow vulnerability that can be triggered by accessing a php://filter URL.

Affected versions

Affected is PHP 5 < 5.2.1

Detailed information

When a filter is created by the php_stream_filter_create() function it first searchs the filter by name in its Hashtable and if that is not successfull it checks if there is a wildcard filter that supports the requested filter. This is handled by the following piece of code.

    if (SUCCESS == zend_hash_find(filter_hash, (char*)filtername, n, (void**)&factory)) {
        filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
    } else if ((period = strrchr(filtername, '.'))) {
        /* try a wildcard */
        char *wildname;

        wildname = estrdup(filtername);
        period = wildname + (period - filtername);
        while (period && !filter) {
            *period = '\0';
            strcat(wildname, ".*");
            if (SUCCESS == zend_hash_find(filter_hash, wildname, strlen(wildname), (void**)&factory)) {
                filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);

            *period = '\0';
            period = strrchr(wildname, '.');

It should be obvious that this function assumes that there is never a dot in the end of the string, because it does not reserve the extra byte of memory that is required in this case. Therefore trying to create a filter with a dot at the end of the name will result in an off by one overflow that overwrites the following byte in memory with a '\0' character.

It heavily depends on the heap implementation if this vulnerability is exploitable or not. With PHP 5.2.0 a new memory manager was introduced into PHP that makes this vulnerability exploitable on all little endian platforms.

Proof of concept, exploit or instructions to reproduce

To test for this vulnerability just try the following piece of code.


    $url = "php://filter/read=OFF_BY_ONE./resource=/etc/passwd";
    fopen($url, "r");

This little POC will overflow the buffer by one byte. Depending on your heap implementation this might crash PHP or go unnoticed. In PHP 5.2.0 it will overwrite the low byte of the heap block lenght and should therefore always result in a crash. When you are running with the Suhosin Patch applied it will trigger a buffer overflow ALERT and kill the process. A code execution exploit will be added to this site in the future. So check back soon.


Don't mistake this vulnerability as only a local threat. It can be triggered by a php://filter URL which is not affected by allow_url_fopen or allow_url_include. Any include vulnerability or anytime an attacker can supply an URL to one of the file functions this can result in a remote buffer overflow vulnerability.