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
20

6.8 Medium

CVSS2

Attack Vector

NETWORK

Attack 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

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

0.005 Low

EPSS

Percentile

76.6%

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

6.8 Medium

CVSS2

Attack Vector

NETWORK

Attack 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

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

0.005 Low

EPSS

Percentile

76.6%