Headline
CVE-2017-12101: TALOS-2017-0453 || Cisco Talos Intelligence Group
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.
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
Discovered by Cory Duplantis of Cisco Talos.