Lucene search

K
talosTalos IntelligenceTALOS-2019-0820
HistoryJul 02, 2019 - 12:00 a.m.

Simple DirectMedia Layer SDL2_image IMG_LoadPCX_RW code execution vulnerability

2019-07-0200:00:00
Talos Intelligence
www.talosintelligence.com
71

8.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

6.8 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

0.003 Low

EPSS

Percentile

65.8%

Summary

An exploitable heap-based buffer overflow vulnerability exists when loading a PCX file in SDL2_image, version 2.0.4. A missing error handler can lead to a buffer overflow and potential code execution. An attacker can provide a specially crafted image file to trigger this vulnerability.

Tested Versions

Simple DirectMedia Layer SDL2_image 2.0.4

Product URLs

<https://www.libsdl.org/projects/SDL_image/&gt;

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-390: Detection of Error Condition Without Action

Details

This vulnerability is present in the SDL2_image library, which is used for loading images in different formats.

There is a vulnerability in the function responsible for loading PCX files. A specially crafted PCX file can lead to a heap buffer overflow and remote code execution.

Let’s investigate this vulnerability. After we attempt to load a malformed PCX file, the following state appears:

./showimage PoC.pcx
=================================================================
==25249==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb2c32848 at pc 0x08057d04 bp 0xbf987968 sp 0xbf987958
WRITE of size 1 at 0xb2c32848 thread T0
	#0 0x8057d03 in IMG_LoadPCX_RW ../IMG_pcx.c:178
	#1 0x804c301 in IMG_LoadTyped_RW ../IMG.c:195
	#2 0x804beff in IMG_Load ../IMG.c:136
	#3 0x804c3e7 in IMG_LoadTexture ../IMG.c:212
	#4 0x804b65c in main ../showimage.c:101
	#5 0xb7014636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
	#6 0x804ad50  (/home/icewall/bugs/SDL_src/SDL2_image-2.0.4/build/showimage+0x804ad50)

0xb2c32848 is located 0 bytes to the right of 264-byte region [0xb2c32740,0xb2c32848)
allocated by thread T0 here:
	#0 0xb72c0dee in malloc (/usr/lib/i386-linux-gnu/libasan.so.2+0x96dee)
	#1 0x81258d2 in SDL_malloc_REAL /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/stdlib/SDL_malloc.c:5328
	#2 0x813cbca in SDL_CreateRGBSurfaceWithFormat_REAL /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/video/SDL_surface.c:122
	#3 0x813ce89 in SDL_CreateRGBSurface_REAL /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/video/SDL_surface.c:166
	#4 0x80abf8f in SDL_CreateRGBSurface /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/dynapi/SDL_dynapi_procs.h:473
	#5 0x805797c in IMG_LoadPCX_RW ../IMG_pcx.c:141
	#6 0x804c301 in IMG_LoadTyped_RW ../IMG.c:195
	#7 0x804beff in IMG_Load ../IMG.c:136
	#8 0x804c3e7 in IMG_LoadTexture ../IMG.c:212
	#9 0x804b65c in main ../showimage.c:101
	#10 0xb7014636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)

SUMMARY: AddressSanitizer: heap-buffer-overflow ../IMG_pcx.c:178 IMG_LoadPCX_RW
Shadow bytes around the buggy address:
  0x365864b0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x365864c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x365864d0: 00 00 00 00 00 00 00 00 01 fa fa fa fa fa fa fa
  0x365864e0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x365864f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=&gt;0x36586500: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa
  0x36586510: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x36586520: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x36586530: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
  0x36586540: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x36586550: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==25249==ABORTING

A heap-based buffer overflow appeared inside the IMG_LoadPCX_RW function. Let’s take a closer look at the code where the vulnerability takes place:

IMG_pcx.c
146	   bpl = pcxh.NPlanes * pcxh.BytesPerLine;
147	   if (bpl &gt; surface-&gt;pitch) {
148		 error = "bytes per line is too large (corrupt?)";
149	   }	
150    buf = (Uint8 *)SDL_calloc(SDL_max(bpl, surface-&gt;pitch), 1);
151    row = (Uint8 *)surface-&gt;pixels;	
152    for ( y=0; y&lt;surface-&gt;h; ++y ) {
153        /* decode a scan line to a temporary buffer first */
154        int i, count = 0;
155        Uint8 ch;
156        Uint8 *dst = (src_bits == 8) ? row : buf;
157        if ( pcxh.Encoding == 0 ) {
158            if(!SDL_RWread(src, dst, bpl, 1)) {
159                error = "file truncated";
160                goto done;
161            }
162        } else {
163            for(i = 0; i &lt; bpl; i++) {
164                if(!count) {
165                    if(!SDL_RWread(src, &ch, 1, 1)) {
166                        error = "file truncated";
167                        goto done;
168                    }
169                    if( (ch & 0xc0) == 0xc0) {
170                        count = ch & 0x3f;
171                        if(!SDL_RWread(src, &ch, 1, 1)) {
172                            error = "file truncated";
173                            goto done;
174                        }
175                    } else
176                        count = 1;
177                }
178                dst[i] = ch;
179                count--;
180            }
181        }

		(...)

214        row += surface-&gt;pitch;
215    }

The overflow appears at line 178. It happens because, as you can see at line 147, the calculated bpl value is checked against the surface-&gt;pitch field. If bpl is bigger, the error variable is set at line 148, but no action is taken (like e.g in lines 159-160 where the goto done instruction is executed).
That lack of action leads to a heap-based buffer overflow in a scenario where src_bits is equal to 8, causing the dst pointer to have the value of row, where row == surface-&gt;pixels.

The overflow will take place during the first iteration, when bpl &gt; sizeof(surface-&gt;pixels), or later because in line 214 the row pointer is moved by the value of surface-&gt;pitch.

A dump of malformed PCX file :

struct PCX file			0h	80h	Fg: Bg:	
ubyte Manufacturer		Ah	0h	1h	Fg: Bg:	
enum PCX_TYPE version	v3up (5h)	1h	1h	Fg: Bg:	
ubyte encoding			1h	2h	1h	Fg: Bg:	
ubyte BitsPerPixel		8h	3h	1h	Fg: Bg:	
ushort Xmin				FF7Fh	4h	2h	Fg: Bg:	
ushort Ymin				FFFFh	6h	2h	Fg: Bg:	
ushort Xmax				0h	8h	2h	Fg: Bg:	
ushort Ymax				0h	Ah	2h	Fg: Bg:	
ushort HDpi				100h	Ch	2h	Fg: Bg:	
ushort VDpi				101h	Eh	2h	Fg: Bg:	
ubyte Colormap[48]		10h	30h	Fg: Bg:	
ubyte Reserved			1h	40h	1h	Fg: Bg:	
ubyte NPlanes			1h	41h	1h	Fg: Bg:	
ushort BytesPerLine		1000h	42h	2h	Fg: Bg:	
ushort PaletteInfo		1001h	44h	2h	Fg: Bg:	
ushort HscreenSize		0h	46h	2h	Fg: Bg:	
ushort VscreenSize		100h	48h	2h	Fg: Bg:	
ubyte Filler[54]		4Ah	36h	Fg: Bg:	

An attacker fulling controlling the size of overwrite and its content can turn this heap-based buffer overflow in a remote code execution.

Crash Information

./showimage PoC.pcx
=================================================================
==25249==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb2c32848 at pc 0x08057d04 bp 0xbf987968 sp 0xbf987958
WRITE of size 1 at 0xb2c32848 thread T0
	#0 0x8057d03 in IMG_LoadPCX_RW ../IMG_pcx.c:178
	#1 0x804c301 in IMG_LoadTyped_RW ../IMG.c:195
	#2 0x804beff in IMG_Load ../IMG.c:136
	#3 0x804c3e7 in IMG_LoadTexture ../IMG.c:212
	#4 0x804b65c in main ../showimage.c:101
	#5 0xb7014636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
	#6 0x804ad50  (/home/icewall/bugs/SDL_src/SDL2_image-2.0.4/build/showimage+0x804ad50)

0xb2c32848 is located 0 bytes to the right of 264-byte region [0xb2c32740,0xb2c32848)
allocated by thread T0 here:
	#0 0xb72c0dee in malloc (/usr/lib/i386-linux-gnu/libasan.so.2+0x96dee)
	#1 0x81258d2 in SDL_malloc_REAL /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/stdlib/SDL_malloc.c:5328
	#2 0x813cbca in SDL_CreateRGBSurfaceWithFormat_REAL /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/video/SDL_surface.c:122
	#3 0x813ce89 in SDL_CreateRGBSurface_REAL /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/video/SDL_surface.c:166
	#4 0x80abf8f in SDL_CreateRGBSurface /home/icewall/bugs/SDL_src/SDL2-2.0.9/src/dynapi/SDL_dynapi_procs.h:473
	#5 0x805797c in IMG_LoadPCX_RW ../IMG_pcx.c:141
	#6 0x804c301 in IMG_LoadTyped_RW ../IMG.c:195
	#7 0x804beff in IMG_Load ../IMG.c:136
	#8 0x804c3e7 in IMG_LoadTexture ../IMG.c:212
	#9 0x804b65c in main ../showimage.c:101
	#10 0xb7014636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)

SUMMARY: AddressSanitizer: heap-buffer-overflow ../IMG_pcx.c:178 IMG_LoadPCX_RW
Shadow bytes around the buggy address:
  0x365864b0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x365864c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x365864d0: 00 00 00 00 00 00 00 00 01 fa fa fa fa fa fa fa
  0x365864e0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x365864f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=&gt;0x36586500: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa
  0x36586510: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x36586520: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x36586530: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
  0x36586540: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x36586550: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==25249==ABORTING

Timeline

2019-05-08 - Vendor Disclosure
2019-07-02 - Vendor Patched; Public Release

8.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

6.8 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

0.003 Low

EPSS

Percentile

65.8%