Lucene search

K
talosTalos IntelligenceTALOS-2017-0491
HistoryMar 01, 2018 - 12:00 a.m.

Simple DirectMedia Layer SDL2_image Image Palette Population Code Execution Vulnerability

2018-03-0100:00:00
Talos Intelligence
www.talosintelligence.com
18

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

EPSS

Percentile

76.3%

Summary

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

Tested Versions

Simple DirectMedia Layer SDL2_image 2.0.2

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-121: Stack-based Buffer Overflow

Details

LibSDL is a multi-platform library for easy access to low level hardware and graphics, providing support for a large amount of games, software, and emulators. The last known count of software using LibSDL (from 2012) listed the number at upwards of 120. The LibSDL2_Image library is an optional component that deals specifically with parsing and displaying a variety of image file formats, creating a single and uniform API for image processing, regardless of the type.

When reading in a BMP file, libSDL2_Image must populate a color palette object for the image. As per the BMP file format, one of the headers read in is the โ€œbiClrUsedโ€ field, which designates how many colors are within the color palette. This is read by the following code:

//IMG_bmp.c:683

    biSize = SDL_ReadLE32(src);        //offset 0x16 in file
    if (biSize == 40) {
    	biWidth = SDL_ReadLE32(src);          //0x1A
 	   	biHeight = SDL_ReadLE32(src);         //0x1E 
 	    	biPlanes = SDL_ReadLE16(src);         //0x23
    		biBitCount = SDL_ReadLE16(src);       //0x25
    		biCompression = SDL_ReadLE32(src);
    		biSizeImage = SDL_ReadLE32(src);
    		biXPelsPerMeter = SDL_ReadLE32(src);  //0x2e
   		biYPelsPerMeter = SDL_ReadLE32(src);  //0x32
    		biClrUsed = SDL_ReadLE32(src);        //0x36  [1]
    		biClrImportant = SDL_ReadLE32(src);   //0x3a

At [1], the biClrUsed field is read in as an unsigned 32-bit integer. After this, the variable is never mentioned again, at least until it is used to populate the palette array as such:

if (biBitCount &lt;= 8) {
	if (biClrUsed == 0) {
		biClrUsed = 1 &lt;&lt; biBitCount;
    		}
    		for (i = 0; i &lt; (int) biClrUsed; ++i) {  //[1] 
        		SDL_RWread(src, &palette[i], 4, 1);
   		 }

Since there isnโ€™t any validation on the โ€œbiClrUsedโ€ field at all, the result is a stack based buffer overflow completely under control of an attacker.

Crash Information

$rax   : 0x019c3c51016b173b -&gt; 0x019c3c51016b173b
$rbx   : 0x0000000000000000 -&gt; 0x0000000000000000
$rcx   : 0x0000000001e28b77 -&gt; 0x0000000001e28b77
$rdx   : 0x0000000000000004 -&gt; 0x0000000000000004
$rsp   : 0x00007ffe43fe6810 -&gt; 0x0000000100000000 -&gt; 0x0000000100000000
$rbp   : 0x00007ffe43fe6cd0 -&gt; 0x00007ffe43fe6cf0 -&gt; 0x00007ffe43fe6d30 -&gt; 0x00007ffe43fe6d60 -&gt; 0x00007ffe43fe6da0 -&gt;     
    0x0000000000000000    
-&gt; 0x0000000000000000
$rsi   : 0x0000000002735c60 -&gt; 0x0000000000000000 -&gt; 0x0000000000000000
$rdi   : 0x00007ffe43fe6cc0 -&gt; 0x0000000000000000 -&gt; 0x0000000000000000
rip   : 0x00007f8c982f6105 -&gt; &lt;LoadICOCUR_RW+1197&gt; mov rdx, QWORD PTR [rax+0x20]
$r8    : 0x0000000002735c60 -&gt; 0x0000000000000000 -&gt; 0x0000000000000000
$r9    : 0x00007ffe43fe6cbc -&gt; 0x0000000001e28b78 -&gt; 0x0000000001e28b78
$r10   : 0x0000000000ff0000 -&gt; 0x0000000000ff0000
$r11   : 0x00007f8c9856d5ce -&gt; 0x20ec8348e5894855 -&gt; 0x20ec8348e5894855
$r12   : 0x0000000000400a10 -&gt; &lt;_start+0&gt; xor ebp, ebp
$r13   : 0x00007ffe43fe6e80 -&gt; 0x0000000000000002 -&gt; 0x0000000000000002
$r14   : 0x0000000000000000 -&gt; 0x0000000000000000
$r15   : 0x0000000000000000 -&gt; 0x0000000000000000
$eflags: [CARRY parity adjust zero SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
----------------------------------------------------------------------------------------------------------------------------------------------    --------------------------------------------------------[ stack ]----
0x00007ffe43fe6810|+0x00: 0x0000000100000000 -&gt; 0x0000000100000000      &lt;-$rsp
0x00007ffe43fe6818|+0x08: 0x0000000002756200 -&gt; 0x00007f8c98578e48 -&gt; 0x20ec8348e5894855 -&gt; 0x20ec8348e5894855
0x00007ffe43fe6820|+0x10: 0x000000000000000b -&gt; 0x000000000000000b
0x00007ffe43fe6828|+0x18: 0x0000068800000000 -&gt; 0x0000068800000000
0x00007ffe43fe6830|+0x20: 0x01c2989401703453 -&gt; 0x01c2989401703453
0x00007ffe43fe6838|+0x28: 0x01dd8e7701df886f -&gt; 0x01dd8e7701df886f
0x00007ffe43fe6840|+0x30: 0x0163234e015e1b45 -&gt; 0x0163234e015e1b45
0x00007ffe43fe6848|+0x38: 0x01753b6b01692b59 -&gt; 0x01753b6b01692b59
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------[ code:i386:x86-64 ]----
0x7f8c982f60f4 &lt;LoadICOCUR_RW+1180&gt; rol    BYTE PTR [rbx-0x74fe13bb], 1
0x7f8c982f60fa &lt;LoadICOCUR_RW+1186&gt; rex.RB (bad)
0x7f8c982f60fc &lt;LoadICOCUR_RW+1188&gt; cmp    eax, DWORD PTR [rbp-0x14]
0x7f8c982f60ff &lt;LoadICOCUR_RW+1191&gt; jg     0x7f8c982f60c2 &lt;LoadICOCUR_RW+1130&gt;
0x7f8c982f6101 &lt;LoadICOCUR_RW+1193&gt; mov    rax, QWORD PTR [rbp-0x20]
-&gt;0x7f8c982f6105 &lt;LoadICOCUR_RW+1197&gt; mov    rdx, QWORD PTR [rax+0x20]
0x7f8c982f6109 &lt;LoadICOCUR_RW+1201&gt; mov    rax, QWORD PTR [rbp-0x20]
0x7f8c982f610d &lt;LoadICOCUR_RW+1205&gt; mov    ecx, DWORD PTR [rax+0x14]
0x7f8c982f6110 &lt;LoadICOCUR_RW+1208&gt; mov    rax, QWORD PTR [rbp-0x20]
0x7f8c982f6114 &lt;LoadICOCUR_RW+1212&gt; mov    eax, DWORD PTR [rax+0x18]
0x7f8c982f6117 &lt;LoadICOCUR_RW+1215&gt; imul   eax, ecx
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------[ source:IMG_bmp.c+761 ]----
757          }
758      }
759  
760      /* Read the surface pixels.  Note that the bmp image is upside down */
            // surface=0x00007ffe43fe6cb0 -&gt; [...] -&gt; 0x019c3c51016b173b, bits=0x00007ffe43fe6ca8 -&gt; [...] -&gt; 0x01e4b28b01f7d1a1
-&gt; 761       bits = (Uint8 *) surface-&gt;pixels + (surface-&gt;h * surface-&gt;pitch); //points immediately after 0x1000 buffer
762      switch (ExpandBMP) {
763      case 1:
764          bmpPitch = (biWidth + 7) &gt;&gt; 3;
765          pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------[ threads ]----
[#0] Id 1, Name: "", stopped, reason: SIGSEGV
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------[ trace ]----
[#0] 0x7f8c982f6105-&gt;Name: LoadICOCUR_RW(src=0x2756200, type=0x1, freesrc=0x0)
[#1] 0x7f8c982f6651-&gt;Name: IMG_LoadICO_RW(src=0x2756200)
[#2] 0x7f8c982f47ef-&gt;Name: IMG_LoadTyped_RW(src=0x2756200, freesrc=0x1, type=0x7ffe43fe8459 "/&lt;(^_^)&gt;")
[#3] 0x7f8c982f45e0-&gt;Name: IMG_Load(file=0x7ffe43fe8458 "./&lt;(^_^)&gt;")
[#4] 0x400b85-&gt;Name: main(argc=0x2, argv=0x7ffe43fe6e88)
-----------------------------------------------------------------------------------------------------------------------------------------

Timeline

2017-11-28 - Vendor Disclosure
2018-03-01 - 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.005 Low

EPSS

Percentile

76.3%