Talos Vulnerability Report

TALOS-2017-0453

Blender modifier_mdef_compact_influences Integer Overflow Code Execution Vulnerability

January 11, 2018
CVE Number

CVE-2017-12101

Summary

An exploitable integer overflow exists in the modifier_mdef_compact_influences functionality of the Blender open-source 3d creation suite v2.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 open a .blend file in order to trigger this vulnerability.

Tested Versions

Blender v2.78c (32-bit)

Product URLs

http://www.blender.org git://git.blender.org/blender.git

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-190 - Integer Overflow or Wraparound

Details

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.

The following module was audited to discover this vulnerability:

0:000> lm vm blender
start    end        module name
00400000 03d68000   blender  C (export symbols)       G:\targets\blender\blender-2.78c-windows32\blender.exe
    Loaded symbol image file: G:\targets\blender\blender-2.78c-windows32\blender.exe
    Image path: blender.exe
    Image name: blender.exe
    Timestamp:        Fri Feb 24 08:33:13 2017 (58B06049)
    CheckSum:         00000000
    ImageSize:        03968000
    File version:     2.7.8.0
    Product version:  2.7.8.0

This vulnerability occurs when loading an old bindcos structure from a MeshDeformModifierData into the new format. When creating bindinfluences, the total number of vertex influences (vertex and weight) is used for the calculation to determine the size of allocation necessary to hold the influences. This value can be crafted to cause an overflow resulting in an allocation smaller than the total number of influences. When populating the array with the necessary values, the application can write beyond the bounds of the allocation, causing a heap-based buffer overflow.

After loading all the basic-blocks in a file, the application will call the blo_do_versions_250 function. This function will check the version of the file as specified in the FileGlobals structure and use it to perform various transformations on the data-structures in the file in order to provide backwards compatibility. At [1], the application will check if the version is less than 253. After this is verified, the main object is passed to do_version_mdef_250 at [2].

source/blender/blenloader/intern/versioning_250.c:732
void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
{
    if (main->versionfile < 253) { [1]
        ...
        do_version_mdef_250(main); [2]

Once inside the do_version_mdef_250 function, at [3] the application will loop through the modifiers in each available object searching for a modifier with type eModifierType_MeshDeform [4]. If this modifier has a bindcos array [5], then the application proceeds to try to upgrade this deprecated field by passing the modifier to modifier_mdef_compact_influences [6].

source/blender/blenloader/intern/versioning_250.c:584
static void do_version_mdef_250(Main *main)
{
    for (ob = main->object.first; ob; ob = ob->id.next) { [3]
        for (md = ob->modifiers.first; md; md = md->next) {
            if (md->type == eModifierType_MeshDeform) { [4]
                mmd = (MeshDeformModifierData*) md;

                if (mmd->bindcos) { [5]
                    /* make bindcos NULL in order to trick older versions
                    * into thinking that the mesh was not bound yet */
                    mmd->bindcagecos = mmd->bindcos;
                    mmd->bindcos = NULL;

                    modifier_mdef_compact_influences(md); [6]
                }
            }
        }
    }
}

The modifier_mdef_compact_influences function is responsible for, among other things, creating a bindinfluences array for the given ModifierData. At [7], the application will create the array by multiplying the totinfluence field from the passed in object (read from the file) by the size of MDefInfluence objects that will populate this array. This product could overflow resulting in a much smaller than indended array. During the initialization of the array at [8], the index into the array can be such that the value written will write beyond the bounds of the allocation, resulting in a heap-based buffer overflow potentially leading to code execution within the context of the application.

source/blender/modifiers/intern/MOD_meshdeform.c:456
void modifier_mdef_compact_influences(ModifierData *md)
{
    MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
    weights = mmd->bindweights;
    ...
    totvert = mmd->totvert;
    totcagevert = mmd->totcagevert;
    ...
    /* allocate bind influences */
    mmd->bindinfluences = MEM_callocN(sizeof(MDefInfluence) * mmd->totinfluence, "MDefBindInfluence"); [7]
    ...
    /* write influences */
    totinfluence = 0;

    for (b = 0; b < totvert; b++) {
        ...
        /* assign weights normalized */
        for (a = 0; a < totcagevert; a++) {
            weight = weights[a + b * totcagevert];

            if (weight > MESHDEFORM_MIN_INFLUENCE) {
                mmd->bindinfluences[totinfluence].weight = weight / totweight; [8]
                mmd->bindinfluences[totinfluence].vertex = a;
                totinfluence++;
            }
        }
    }

Crash Information

Call to malloc with size 8

eax=00000008 ebx=00000014 ecx=00000014 edx=00000050 esi=2141aecc edi=00000014
eip=009da976 esp=0022f474 ebp=0022f498 iopl=0         nv up ei pl nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000203
blender!PyInit_mathutils_noise_types+0x8bef6:
009da976 ff1578485803    call    dword ptr [blender!NvOptimusEnablement+0x9b0 (03584878)] ds:0023:03584878=00efd110

Allocation of size 8
0:000> dc 21d84ff4
21d84ff4  00000000 00000000 d0d0d0d0 ????????  ............????
21d85004  ???????? ???????? ???????? ????????  ????????????????
21d85014  ???????? ???????? ???????? ????????  ????????????????
21d85024  ???????? ???????? ???????? ????????  ????????????????
21d85034  ???????? ???????? ???????? ????????  ????????????????
21d85044  ???????? ???????? ???????? ????????  ????????????????
21d85054  ???????? ???????? ???????? ????????  ????????????????
21d85064  ???????? ???????? ???????? ????????  ????????????????

Page Heap detailing that the allocation was being written out of bounds

(448.844): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=21d84ff4 ebx=00000001 ecx=00000001 edx=23ea6fb0 esi=2141aecc edi=00000014
eip=009daa65 esp=0022f47c ebp=0022f498 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
blender!PyInit_mathutils_noise_types+0x8bfe5:
009daa65 f30f1154d804    movss   dword ptr [eax+ebx*8+4],xmm2 ds:0023:21d85000=????????
0:000> dc eax
21d84ff4  00000000 3d4c537b d0d0d0d0 ????????  ....{SL=....????
21d85004  ???????? ???????? ???????? ????????  ????????????????
21d85014  ???????? ???????? ???????? ????????  ????????????????
21d85024  ???????? ???????? ???????? ????????  ????????????????
21d85034  ???????? ???????? ???????? ????????  ????????????????
21d85044  ???????? ???????? ???????? ????????  ????????????????
21d85054  ???????? ???????? ???????? ????????  ????????????????
21d85064  ???????? ???????? ???????? ????????  ????????????????

Exploit Proof-of-Concept

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.zip $FILENAME.blend

To trigger the vulnerability, one can simply open the file or use it as a library. It can also be passed as an argument to the blender executable.

$ /path/to/blender.exe $FILENAME.blend

Timeline

2017-09-27 - Vendor Disclosure
2018-01-11 - Public Release

Credit

Discovered by Cory Duplantis of Cisco Talos.