Headline
CVE-2017-12086: TALOS-2017-0438 || Cisco Talos Intelligence Group
An exploitable integer overflow exists in the ‘BKE_mesh_calc_normals_tessface’ functionality of the Blender open-source 3d creation suite. 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 BKE_mesh_calc_normals_tessface functionality of the Blender open-source 3d creation suite. 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
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.
This vulnerability exists with how the Blender application fixes the normals within a Mesh object when loading an older version of a .blend file. When allocating space for the faces and vertices of a Mesh object, the application will perform some arithmetic which can overflow. This will then be used to perform an allocation which can allow for an undersized buffer. Later when the application attempts to calculate the normals for the vertices and faces of the mesh, the application will write outside the bounds of the buffer resulting in a heap-based buffer overflow.
After initially loading the 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. At [1], if the version is less than 256 (exclusive) or the version is equal to 256 and sub-version is less than 6 then the application will iterate through all of the Mesh data-blocks with the Code ‘ME\x00\x00’ that were read from the file. For each of these Mesh objects, the function BKE_mesh_calc_normals_tessface will be called at [2]. The arguments that are passed to this function come from the Mesh object. The fields that are directly responsible for this vulnerability are the totvert and the totface fields of the Mesh structure.
source/blender/blenloader/intern/versioning_250.c:732
void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
{
...
if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 6)) { // [1]
Mesh *me;
for (me = main->mesh.first; me; me = me->id.next)
BKE_mesh_calc_normals_tessface(me->mvert, me->totvert, me->mface, me->totface, NULL); // [2]
}
Once inside the BKE_mesh_calc_normals_tessface function, the application will take the values from the totface and totvert fields and use them to perform a multiplication at [3] in order to allocate space for the calculations required for both the faces and vertices of the mesh. The size of both fields are a 4 for a float, and 3 for three of them. This results in the multiplication for both allocations being 12 and the totvert field or the totface field. If the result of this product is larger than 32-bits then an integer overflow will occur. This will cause the memory that is allocated to be undersized. Later at [4], the application will use one of these undersized buffers to calculate the normals of each face of the Mesh. Also at [5], the normals for each vertex will be calculated. The provided-proof-of-concept utilizes the calculation of the normal for each vertex in order to corrupt memory and trigger the vulnerability. At [6], the application will store the normal that was calculated into the buffer that was allocated corrupting memory outside the bounds of the allocated buffer. This type of memory corruption could allow for code execution under the context of the application.
source/blender/blenkernel/intern/mesh_evaluate.c:317
void BKE_mesh_calc_normals_tessface(
MVert *mverts, int numVerts,
const MFace *mfaces, int numFaces,
float (*r_faceNors)[3])
{
float (*tnorms)[3] = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, "tnorms"); // [3]
float (*fnors)[3] = (r_faceNors) ? r_faceNors : MEM_callocN(sizeof(*fnors) * (size_t)numFaces, "meshnormals");
...
for (i = 0; i < numFaces; i++) {
const MFace *mf = &mfaces[i];
float *f_no = fnors[i];
float *n4 = (mf->v4) ? tnorms[mf->v4] : NULL;
const float *c4 = (mf->v4) ? mverts[mf->v4].co : NULL; // [4]
...
}
...
for (i = 0; i < numVerts; i++) {
MVert *mv = &mverts[i];
float *no = tnorms[i];
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
normalize_v3_v3(no, mv->co); // [5]
}
normal_float_to_short_v3(mv->no, no); // [6] \
}
...
}
\
source/blender/blenlib/intern/math_vector_inline.c:959
MINLINE void normal_float_to_short_v3(short out[3], const float in[3])
{
out[0] = (short) (in[0] * 32767.0f);
out[1] = (short) (in[1] * 32767.0f);
out[2] = (short) (in[2] * 32767.0f);
}
Crash Information
(1aa0.1464): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=0d9acfa4 ecx=00007ff0 edx=01018e2c esi=0d9f53cc edi=0da3dff8
eip=01b83423 esp=00f9ee28 ebp=00f9ee48 iopl=0 nv up ei pl nz na po cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010203
blender!PyInit_mathutils_noise_types+0x2949a3:
01b83423 66894708 mov word ptr [edi+8],ax ds:002b:0da3e000=????
0:000> dc @edi
0da3dff8 00000000 00000000 ???????? ???????? ........????????
0da3e008 ???????? ???????? ???????? ???????? ????????????????
0da3e018 ???????? ???????? ???????? ???????? ????????????????
0da3e028 ???????? ???????? ???????? ???????? ????????????????
0da3e038 ???????? ???????? ???????? ???????? ????????????????
0da3e048 ???????? ???????? ???????? ???????? ????????????????
0da3e058 ???????? ???????? ???????? ???????? ????????????????
0da3e068 ???????? ???????? ???????? ???????? ????????????????
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
Mitigation
In order to mitigate this vulnerability, it is recommended to not use untrusted blender files.
Timeline
2017-09-06 - Vendor Disclosure
2018-01-11 - Public Release
Discovered by a member of Cisco Talos.