Lucene search

K
talosTalos IntelligenceTALOS-2019-0841
HistoryJul 29, 2019 - 12:00 a.m.

SDL_image PCX Image Code execution Vulnerability

2019-07-2900:00:00
Talos Intelligence
www.talosintelligence.com
87

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.004 Low

EPSS

Percentile

72.4%

Summary

An exploitable code execution vulnerability exists in the PCX image-rendering functionality of SDL2_image 2.0.4. A specially crafted PCX image can cause a heap overflow, resulting in code execution. An attacker can display a specially crafted image to trigger this vulnerability.

Tested Versions

SDL_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-122: Heap-based Buffer Overflow

Details

LibSDL is a multi-platform library for easy access to low-level hardware and graphics, providing support for a large number of video games, software and emulators. The LibSDL2_Image library is an optional component that deals specifically with parsing and displaying a variety of image file formats, creating a single, uniform API for image processing, regardless of the type.

When parsing a PCX image, SDL allocated a buffer to hold the pixels in the image sized to the parameters provided in the PCX image [0].

SDL/src/video/SDL_surface.c:112

/* Get the pixels */
if (surface-&gt;w && surface-&gt;h) {
    /* Assumptions checke   d in surface_size_assumptions assert above */
    Sint64 size = ((Sint64)surface-&gt;h * surface-&gt;pitch);
    if (size &lt; 0 || size &gt; SDL_MAX_SINT32) {
        /* Overflow... */
        SDL_FreeSurface(surface);
        SDL_OutOfMemory();
        return NULL;
    }

    surface-&gt;pixels = SDL_SIMDAlloc((size_t)size); [0]
    if (!surface-&gt;pixels) {
        SDL_FreeSurface(surface);
        SDL_OutOfMemory();
        return NULL;
    }

Later, the PCX header is read from the image into a PCXHeader struct [1].

SDL_image/Img_PCX.c:108
if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) { [1]
    error = "file truncated";
    goto done;
}

Using the data from this header, a number of bytes per line is calculated [2]. This bpl is used as a loop counter to populate a row or column buffer [3] based on a calculation also from the PCXHeader [4].

SDL_image/Img_PCX.c:42
struct PCXheader {
    Uint8 Manufacturer;
    Uint8 Version;
    Uint8 Encoding;
    Uint8 BitsPerPixel;
    Sint16 Xmin, Ymin, Xmax, Ymax;
    Sint16 HDpi, VDpi;
    Uint8 Colormap[48];
    Uint8 Reserved;
    Uint8 NPlanes;
    Sint16 BytesPerLine;
    Sint16 PaletteInfo;
    Sint16 HscreenSize;
    Sint16 VscreenSize;
    Uint8 Filler[54];
};

SDL_image/Img_PCX.c:122
src_bits = pcxh.BitsPerPixel * pcxh.NPlanes; [4]
...
bpl = pcxh.NPlanes * pcxh.BytesPerLine; [2]
if (bpl &gt; surface-&gt;pitch) {
    error = "bytes per line is too large (corrupt?)";
}

buf = (Uint8 *)SDL_calloc(SDL_max(bpl, surface-&gt;pitch), 1);
row = (Uint8 *)surface-&gt;pixels;
for ( y=0; y&lt;surface-&gt;h; ++y ) {
    /* decode a scan line to a temporary buffer first */
    int i, count = 0;
    Uint8 ch;
    Uint8 *dst = (src_bits == 8) ? row : buf; [3]
    if ( pcxh.Encoding == 0 ) {
        if(!SDL_RWread(src, dst, bpl, 1)) {
            error = "file truncated";
            goto done;
        }
    } else {
        for(i = 0; i &lt; bpl; i++) {
            if(!count) {
                if(!SDL_RWread(src, &ch, 1, 1)) {
                    error = "file truncated";
                    goto done;
                }
                if( (ch & 0xc0) == 0xc0) {
                    count = ch & 0x3f;
                    if(!SDL_RWread(src, &ch, 1, 1)) {
                        error = "file truncated";
                        goto done;
                    }
                } else
                    count = 1;
            }
            dst[i] = ch; [5]
            count--;
        }
    }

If the correct bytes are set in the header to select the row buffer, an attacker can select the pixel buffer provided by SDL to populate. This population is controlled by the previous bytes per line calculation. An attacker can control this counter to write beyond the bounds of the heap buffer causing a heap based overflow potentially resulting in code execution.

Crash Information

=================================================================
==21589==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607000000148 at pc 0x000000511489 bp 0x7ffd4f3378d0 sp 0x7ffd4f3378c8
WRITE of size 1 at 0x607000000148 thread T0
    #0 0x511488 in IMG_LoadPCX_RW /home/vagrant/fuzzing/SDL_image/build-afl-asan/../IMG_pcx.c:178:24
    #1 0x4ef64c in IMG_LoadTyped_RW /home/vagrant/fuzzing/SDL_image/build-afl-asan/../IMG.c:195:17
    #2 0x4ee16f in main /home/vagrant/fuzzing/SDL_image/build-afl-asan/../showimage.c:56:22
    #3 0x7f70518a182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x41a8a8 in _start (/ramdisk/SDL_image/build-afl-asan/showimage+0x41a8a8)

0x607000000148 is located 0 bytes to the right of 72-byte region [0x607000000100,0x607000000148)
allocated by thread T0 here:
    #0 0x4c15ac in malloc /scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:66:3
    #1 0x7f70527fd122 in SDL_malloc_REAL /home/vagrant/fuzzing/SDL/src/stdlib/SDL_malloc.c:5387:11

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/vagrant/fuzzing/SDL_image/build-afl-asan/../IMG_pcx.c:178:24 in IMG_LoadPCX_RW
Shadow bytes around the buggy address:
0x0c0e7fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c0e7fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c0e7fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c0e7fff8000: fa fa fa fa 00 00 00 00 00 00 00 00 07 fa fa fa
0x0c0e7fff8010: fa fa 00 00 00 00 00 00 00 00 00 fa fa fa fa fa
0x0c0e7fff8020: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa &lt;=
0x0c0e7fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

Timeline

2019-05-30 - Vendor Disclosure
2019-07-03 - Vendor Patched
2019-07-29 - 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.004 Low

EPSS

Percentile

72.4%