Talos Vulnerability Report

TALOS-2018-0515

Walt Disney Per-Face Texture Mapping faceInfoSize Code Execution Vulnerability

January 26, 2018
CVE Number

CVE-2018-3835

Summary

An exploitable out of bounds write vulnerability exists in version 2.2 of the Per Face Texture mapping application known as PTEX. The vulnerability is present in the reading of a file without proper parameter checking. The value read in, is not verified to be valid and its use can lead to a buffer overflow, potentially resulting in code execution.

Tested Versions

Walt Disney Animation Studios PTEX 2.2

Product URLs

http://ptex.us/

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

PTEX is a texture mapping system developed by Walt Disney Animation Studios for production-quality rendering. PTEX is able to store hundreds of thousands of texture mappings in a single file. This library is used in many applications including Pixar’s RenderMan, giving it a large user base thus making it a valuable target.

The vulnerability arises when the value, faceinfosize, is read in from the file header and used without verification.

bool PtexReader::open(const char* pathArg, Ptex::String& error)
{
    ...

    memset(&_header, 0, sizeof(_header));
    readBlock(&_header, HeaderSize); [0]

    ...

    // compute offsets of various blocks
    FilePos pos = HeaderSize + _header.extheadersize;
    _faceinfopos = pos;   pos += _header.faceinfosize; [1]

    ...
    // read basic file info
    readFaceInfo(); [2]

At location 0, the header is being read into the structure. Then, at 1, the position of the face information is calculated and the function readFaceInfo() is called, at 2.

void PtexReader::readFaceInfo()
{
    ...
    readZipBlock(&_faceinfo[0], _header.faceinfosize,   (int)(sizeof(FaceInfo)    *    nfaces)); [3]

At 3, the faceinfosize value is used directly from the header and has not been verified for validity. Looking at the readZipBlock function the vulnerability becomes apparent.

bool PtexReader::readZipBlock(void* data, int zipsize, int unzipsize) [4]
{

    ...

    while (1) {
        int size = (zipsize < BlockSize) ? zipsize : BlockSize; [5]
        zipsize -= size;
        if (!readBlock(buff, size)) break; [6]

The value zipsize is of the type integer, 4, thus allowing it to potentially be a negative number. If this value is negative then it will always pass the check at 5. It is then converted to a large positive number implicitly when used for reading. This allows attacker controlled data to be read in beyond the bounds of the buffer leading to a buffer overflow and an exploitable condition.

There is a patch file included to check to ensure the zipsize is greater than 0 before processing the vulnerable block.

Crash Information

Crashed thread log =
: Dispatch queue: com.apple.main-thread
* thread #1: tid = 0x12c2345, 0x00007fff9ed74fbf libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 287
  * frame #0: 0x00007fff9ed74fbf libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 287
    frame #1: 0x00007fff9ebd650e libsystem_c.dylib`__fread + 375
    frame #2: 0x00007fff9ebd6380 libsystem_c.dylib`fread + 48
    frame #3: 0x0000000100011ed4 ptxinfo-debug`Ptex::v2_2::PtexReader::DefaultInputHandler::read
    frame #4: 0x0000000100009cbc ptxinfo-debug`Ptex::v2_2::PtexReader::readBlocksize
    frame #5: 0x000000010000b4fe ptxinfo-debug`Ptex::v2_2::PtexReader::readZipBlock


exception=EXC_BAD_ACCESS:signal=11:is_exploitable= yes:instruction_disassembly=vmovaps %ymm2,       
0x20(%rdi):instruction_address=0x00000007fff9ed74fbf:access_type=write:access_address=0x7fff5fbfffe0:

Timeline

2018-01-22 - Vendor Disclosure
2018-01-26 - Public Release

Credit

Discovered by Tyler Bohan of Cisco Talos .