CVE-2017-2908
An exploitable integer overflow exists in the thumbnail functionality of the Blender open-source 3d creation suite version 2.78c. A specially crafted .blend file can cause an integer overflow resulting in a buffer overflow which can allow for code execution under the context of the application. An attacker can convince a user to render the thumbnail for the file while in the File->Open dialog.
Blender v2.78c
http://www.blender.org git://git.blender.org/blender.git
7.5 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-190 - Integer Overflow or Wraparound
Blender is a professional, open-source 3d computer graphics application. It is used for creating animated films, visual effects, art, 3d printed applications, and video games. It is also capable of doing minimalistic video editing and sequencing as needed by the user. There are various features that it provides which allow for a user to perform a multitude of actions as required by a particular project.
This vulnerability exists with how the Blender application loads the thumbnail for a .blend file when browsing directory contents. When allocating space for the thumbnail image within a .blend file, the application will perform some arithmetic which can overflow. This result will then be used to perform an allocation which can allow for an undersized buffer. Later when the application attempts to copy the thumbnail data into this buffer, a heap-based buffer overflow will occur.
When loading a thumbnail from a .blend file, the BLO_thumbnail_from_file
is called. Near the beginning of this function, the application will call the blo_openblenderfile_minimal
function to read the header from the file [1]. The header from the file contains a magic value which determines the pointer-size and byte order used within the file. Immediately afterwards at [2], the application will call the read_file_thumbnail
function. This function will search for the block-header matching the value “TEST” [3]. After this is determined, the application will validate the length of the block. During this process, the application will read two signed 32-bit numbers. Afterwards, the application will validate that the block’s length is smaller than the result of the BLEN_THUMB_MEMSIZE_FILE
macro [4]. This macro will multiply the two numbers together, add the constant 2
, and then multiply them by the size of an int. Due to the application failing to check that the product of these values can result in more than 32-bits, this test can overflow thus bypassing the validation.
source/blender/blenloader/intern/readfile.c:1401
BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
FileData *fd;
BlendThumbnail *data;
int *fd_data;
fd = blo_openblenderfile_minimal(filepath); // [1]
fd_data = fd ? read_file_thumbnail(fd) : NULL; // [2] \
if (fd_data) {
const size_t sz = BLEN_THUMB_MEMSIZE(fd_data[0], fd_data[1]);
data = MEM_mallocN(sz, __func__);
BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(fd_data[0], fd_data[1]) - (sizeof(*fd_data) * 2)));
data->width = fd_data[0];
data->height = fd_data[1];
memcpy(data->rect, &fd_data[2], sz - sizeof(*data));
\
source/blender/blenloader/intern/readfile.c:946
static int *read_file_thumbnail(FileData *fd)
BHead *bhead;
int *blend_thumb = NULL;
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
if (bhead->code == TEST) { // [3]
const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
int *data = (int *)(bhead + 1);
if (bhead->len < (2 * sizeof(int))) {
break;
if (do_endian_swap) {
BLI_endian_switch_int32(&data[0]);
BLI_endian_switch_int32(&data[1]);
if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(data[0], data[1])) { // [4] \
break;
blend_thumb = data;
break;
...
return blend_thumb;
source/blender/blenloader/BLO_blend_defs.h:78
#define BLEN_THUMB_MEMSIZE_FILE(_x, _y) (sizeof(int) * (size_t)(2 + (_x) * (_y)))
Once validating the thumbnail header and then returning a pointer to the thumbnail data, the application will resume execution of the BLO_thumbnail_from_file
function. Using the data returned from read_file_thumbnail
, the application will then pass both of the signed 32-bit numbers to the BLEN_THUMB_MEMSIZE
macro [5]. This macro will multiply the two numbers together along with the size of an int. Afterwards, the size of a BlendThumbnail
structure will be added to the result. Due to the application not checking that this result may be larger than 32-bits, an integer overflow may occur. Once this overflown size is calculated, an allocation will be made which may be undersized due to this vulnerability. The overflow is then triggered by the assignments to data->width
, data->height
, or the memcpy
operation that happens at [6].
source/blender/blenloader/intern/readfile.c:1401
BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
FileData *fd;
BlendThumbnail *data;
int *fd_data;
fd = blo_openblenderfile_minimal(filepath);
fd_data = fd ? read_file_thumbnail(fd) : NULL;
if (fd_data) {
const size_t sz = BLEN_THUMB_MEMSIZE(fd_data[0], fd_data[1]); // [5] \
data = MEM_mallocN(sz, __func__);
BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(fd_data[0], fd_data[1]) - (sizeof(*fd_data) * 2)));
data->width = fd_data[0];
data->height = fd_data[1];
memcpy(data->rect, &fd_data[2], sz - sizeof(*data)); // [6]
\
source/blender/blenkernel/BKE_main.h:125
#define BLEN_THUMB_MEMSIZE(_x, _y) (sizeof(BlendThumbnail) + (size_t)((_x) * (_y)) * sizeof(int))
(20.2d90): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=3295affc ebx=336b2ff8 ecx=0b6a51a1 edx=010186b0 esi=00000000 edi=32b4ab3c
eip=0081c8be esp=2e56ca98 ebp=2e56cab0 iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010216
blender!PyInit_mathutils_noise_types+0x12de3e:
0081c8be 894804 mov dword ptr [eax+4],ecx ds:002b:3295b000=????????
0:016> !heap -p -a @eax
address 3295affc found in
_DPH_HEAP_ROOT @ 8811000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
32990ed4: 3295aff8 4 - 3295a000 2000
Included with this advisory is a generator for the vulnerability. This proof-of-concept requires python and takes a single-argument which is the filename to write the .blend file to.
$ python poc.py $FILENAME.blend
To trigger the vulnerability, one can simply browse to the same directory as the file via the File->Open dialog and then view thumbnails by enabling it on the toolbar.
In order to mitigate this vulnerability, it is recommended to not use thumbnails when browsing a directory of projects.
2017-09-06 - Vendor Disclosure
2018-01-11 - Public Release
Discovered by a member of Cisco Talos.