Quantcast
Channel: Cisco Talos Blog
Viewing all articles
Browse latest Browse all 1948

Talos 2016 0047

$
0
0

TALOS-2016-0047

FFMpeg LibAvCodec SMC Opcodes 6,7 Heap-based Buffer overflow

April 7, 2016

Report ID

CVE-2016-1528

Description

This vulnerability is located within the libavcodec library within the ffmpeg project. The libavcodec library is responsible for parsing codec streams within ffmpeg and hence is used in various open-source projects. Within the SMC decoder, which is responsible for decoding QuickTime Video sample data, is a heap-based buffer overflow and was introduced during revision 2488 to the project. The overflow occurs when decoding video sample data and can be used to write outside the video frame. This can be used to overwrite heap data which can lead to code execution under the context of the application.

Product Urls

http://www.ffmpeg.org
https://github.com/FFmpeg/FFmpeg

Details

The SMC codec’s sample data can be described as a stream of opcodes. Each element is a 3-bit opcode followed by a single-bit that is used to describe whether a count is encoded in the next 4-bits or within an octet that follows the opcode. Each of these elements act on the video frame by applying an operation to a 4x4 block.

When parsing a container that utilizes this codec, the decoder will chunk the frame into 4x4 blocks and then proceed to apply each opcode to the video frame. When the decoder encounters opcode 3, an 8-bit pixel color will be pulled from the sample stream. This pixel will then be used to fill the specified number of blocks with. The pixel color comes the palette defined within the movie container.

libavformat/smc.c:80
static void smc_decode_stream(SmcContext *s)
{
...
    unsigned char *pixels = s->frame->data[0];
...
    int row_ptr = 0;
    int pixel_ptr = 0;
...
    total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
...
    while (total_blocks) {
...
        opcode = bytestream2_get_byte(&s->gb);
        switch (opcode & 0xF0) {
...
        /* 1-color block encoding */
        case 0x60: // 3
        case 0x70:
            n_blocks = GET_BLOCK_COUNT();               // XXX: get the count
            pixel = bytestream2_get_byte(&s->gb);       // XXX: get the color to fill the block with

            while (n_blocks--) {
                block_ptr = row_ptr + pixel_ptr;
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
                        pixels[block_ptr++] = pixel;    // XXX: fill the 4x4 block with the specified color
                    }
                    block_ptr += row_inc;
                }
                ADVANCE_BLOCK();
            }
            break;
...
        }
    }

Due to a lack of bounds checking when decoding this opcode, an aggressor can specify a block count that will cause the inner loop to write a number of 4x4 blocks of the specified color outside the bounds of the video frame. Due to this, a heap-based buffer overflow can be made to occur.

Crash Analysis

The provided proof-of-concept was developed against ffplay.exe which utilizes libavcodec for decoding. ffplay.exe was built with MinGW under the Msys environment and run with Full-page heap utilizing gflags.exe +hpa.

(239c.2010): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000007f ebx=00000000 ecx=00000004 edx=00000440 esi=0000001c edi=074f7bc0
eip=007ea931 esp=0ab6fac0 ebp=00000400 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010212
image00400000+0x3ea931:
007ea931 880417          mov     byte ptr [edi+edx],al      ds:002b:074f8000=??
0:003> !heap -p -a @edi
    address 074f7bc0 found in
    _DPH_HEAP_ROOT @ 74d1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 74d1bf8:          74f7bb8              442 -          74f7000             2000
    629e8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    775d104e ntdll!RtlDebugAllocateHeap+0x00000030
    7758b16e ntdll!RtlpAllocateHeap+0x000000c4
    77533074 ntdll!RtlAllocateHeap+0x0000023a
    76ea9d45 msvcrt!malloc+0x0000008d
    76ed02f4 msvcrt!_aligned_offset_malloc+0x0000008a
    76ed029f msvcrt!_aligned_malloc_dbg+0x00000012

Description of the proof-of-concept

Within ffmpeg, the SMC codec is only available via the ISO standardized .MP4 format. This format as well as all movie containers are implemented by libavformat is and is the same as utilized by Apple Quicktime’s MOV format. Within the MP4 format, is an atom known as the Sample Description (STSD) atom. The Sample description atom contains a fourcc ‘SMC ‘ in the data format field and then contains an array of format-specific data. Within the provided poc, the Sample Description atom is located at offset 0x1fec.

<class atom.Atom> '0'
[1fec] <instance be(pQTInt) 'size'> 0x0000086e (2158)
[1ff0] <instance be(pQTType) 'type'> type 'stsd' (73747364)
[1ff4] <instance be(uint_t) 'extended_size'> 0x0 (0)
[1ff4] <instance c(atom.stsd) 'data'> "\x00\x00\x00\x00\x00\x00\x00   ..skipped ~2130 bytes..  \x00\x00\xff\xff\xff\xff"

The first entry in the array selects the video stream used by the container. In order to select the SMC codec, the Data format field must be ‘smc ‘. This is at offset 0x2000 in the provided poc.

<class atom.Entry> '0'
[1ffc] <instance be(pQTInt) 'Sample description size'> 0x0000085e (2142)
[2000] <instance be(pQTType) 'Data format'> Data format 'smc ' (736d6320)
[2004] <instance dynamic.block(6) 'Reserved'> "\x00\x00\x00\x00\x00\x00"
[200a] <instance be(uint16_t) 'Data reference index'> 0x0001 (1)
[200c] <instance dynamic.block(2126) 'Data specific'> "\x00\x01\x00\x02\x61\x70\x70   ..skipped ~2106 bytes..  \x00\x00\xff\xff\xff\xff"

At the very end of the entry, contains codec-specific data. If the codec format decribes a video sample, the following structure can be located. Within this structure is the frame’s width and height. Whereas the width and height can also be described in the TKHD atom, the width and height defined within the STSD atom is given priority and used to allocate a pool of video frames by ffmpeg.

<class atom.Video> '0x41787d8'
[200c] <instance be(uint16_t) 'Version'> 0x0001 (1)                     // XXX: ignored by ffmpeg
[200e] <instance be(uint16_t) 'Revision level'> 0x0002 (2)
[2010] <instance be(pQTType) 'Vendor'> Vendor 'appl' (6170706c)
[2014] <instance be(pQTInt) 'Temporal Quality'> 0x00000000 (0)
[2018] <instance be(pQTInt) 'Spatial Quality'> 0x00000400 (1024)
[201c] <instance be(uint16_t) 'Width'> 0x0258 (600)                     // XXX: used to control allocation
[201e] <instance be(uint16_t) 'Height'> 0x0190 (400)                    // XXX: of frame within the frame pool
[2020] <instance be(pQTInt) 'Horizontal Resolution'> 0x00480000 (4718592)
[2024] <instance be(pQTInt) 'Vertical Resolution'> 0x00480000 (4718592)
[2028] <instance atom.MediaVideo_v1 'Versioned'> "\x00\x00\x00\x00\x00\x01\x08   ..skipped ~2078 bytes..  \x00\x00\xff\xff\xff\xff"

At offset 0x2028 within the PoC is the bit-depth. The SMC codec utilizes a palette in order to fill each 4x4 block. If the bit-depth has it’s 6th bit set (0x20), the palette will be grayscale. If the bit-depth is 1,2,4,or 8 a default palette wlil be set based on the Color Table Id. If Color Table Id is defined as 0, a non-default palette can be provided. This can allow the agressor to control the exact values that can be written by an opcode.

<class atom.MediaVideo_v1> 'Versioned'
[2028] <instance be(primitives.pQTInt) 'Data size'> 0x00000000 (0)
[202c] <instance be(pint.uint16_t) 'Frame Count'> 0x0001 (1)
[202e] <instance atom.CompressorName 'Compressor Name'> "\x08\x47\x72\x61\x70\x68\x69\x63\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
[204f] <instance pint.uint16_t 'Depth'> 0x0008 (8)                  // XXX: Must be one of the values defined
[2051] <instance be(pint.uint16_t) 'Color Table ID'> 0x0000 (0)     // XXX: To include a custom palette, specify 0
[2053] <instance atom.ColorTable 'Color Table'> "\x00\x00\x00\x00\x00\x00\xff   ..skipped ~2035 bytes..  \x00\x00\xff\xff\xff\xff"

The color table or palette that is used to write with is located at offset 0x2053 within the file. This palette is used by the SMC decoder to populate each 4x4 block.

<class atom.ColorTable> 'Color Table'
[2053] <instance be(pint.uint32_t) 'start'> 0x00000000 (0)
[2057] <instance be(pint.uint8_t) 'count'> 0x00 (0)
[2058] <instance be(pint.uint16_t) 'end'> 0x00ff (255)
[205a] <instance dynamic.array(atom.argb,256) 'entries'> atom.argb[256] "\x00\x00\xff\xff\xff\xff\xff   ..skipped ~2028 bytes..  \x00\x00\xff\xff\xff\xff"

Credit

Discovered by Cisco Talos

Timeline

2015-09-14: Initial Contact
2015-10-19: Second Vendor Contact
2015-11-14: Final attempt
2016-01-13: Reported to CERT
2016-04-08: Public Release


Viewing all articles
Browse latest Browse all 1948

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>