justdan96 / tsMuxer

tsMuxer is a transport stream muxer for remuxing/muxing elementary streams, EVO/VOB/MPG, MKV/MKA, MP4/MOV, TS, M2TS to TS to M2TS. Supported video codecs H.264/AVC, H.265/HEVC, VC-1, MPEG2. Supported audio codecs AAC, AC3 / E-AC3(DD+), DTS/ DTS-HD.
Apache License 2.0
829 stars 140 forks source link

heap buffer overflow is found in movDemuxer::mov_read_trun #841

Closed iwashiira closed 3 months ago

iwashiira commented 3 months ago

Our fuzzer found heap buffer overflow in movDemuxer. in the current master(75c9cb3). PoC is here.

#include "bufferedReaderManager.h"
#include "vod_common.h"
#include "abstractDemuxer.h"
#include "movDemuxer.h"
#include <cstdint>
#include <fs/systemlog.h>

using namespace std;

BufferedReaderManager readManager(2, DEFAULT_FILE_BLOCK_SIZE, DEFAULT_FILE_BLOCK_SIZE + MAX_AV_PACKET_SIZE,
                                  DEFAULT_FILE_BLOCK_SIZE / 2);

int main(int argc, char* argv[]) {

    string fileName = argv[1];
    AbstractDemuxer* demuxer = new MovDemuxer(readManager);

    uint32_t fileBlockSize = demuxer->getFileBlockSize();
    demuxer->openFile(fileName);
    return 0;
}

Following is an output of ASAN. vuln15.mov is in poc15.zip

=================================================================
==29495==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x615000000f00 at pc 0x55555596c667 bp 0x7fffffffd1e0 sp 0x7fffffffd1d0
WRITE of size 4 at 0x615000000f00 thread T0
    #0 0x55555596c666 in MovDemuxer::mov_read_trun(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x418666)
    #1 0x55555596a81b in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41681b)
    #2 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #3 0x55555596a4a3 in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4164a3)
    #4 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #5 0x55555596ee65 in MovDemuxer::mov_read_moof(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41ae65)
    #6 0x55555596a615 in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416615)
    #7 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #8 0x555555967635 in MovDemuxer::readHeaders() (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x413635)
    #9 0x55555596679a in MovDemuxer::openFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41279a)
    #10 0x5555558b6e45 in main (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x362e45)
    #11 0x7ffff6f70d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #12 0x7ffff6f70e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #13 0x5555557cc0d4 in _start (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x2780d4)

0x615000000f00 is located 0 bytes to the right of 512-byte region [0x615000000d00,0x615000000f00)
allocated by thread T0 here:
    #0 0x7ffff767a1e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x55555599271f in __gnu_cxx::new_allocator<MOVStts>::allocate(unsigned long, void const*) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x43e71f)
    #2 0x55555598eb9a in std::allocator_traits<std::allocator<MOVStts> >::allocate(std::allocator<MOVStts>&, unsigned long) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x43ab9a)
    #3 0x55555598a67f in std::_Vector_base<MOVStts, std::allocator<MOVStts> >::_M_allocate(unsigned long) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x43667f)
    #4 0x555555984c59 in void std::vector<MOVStts, std::allocator<MOVStts> >::_M_realloc_insert<>(__gnu_cxx::__normal_iterator<MOVStts*, std::vector<MOVStts, std::allocator<MOVStts> > >) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x430c59)
    #5 0x55555597f506 in MOVStts& std::vector<MOVStts, std::allocator<MOVStts> >::emplace_back<>() (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x42b506)
    #6 0x55555596c5d4 in MovDemuxer::mov_read_trun(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4185d4)
    #7 0x55555596a81b in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41681b)
    #8 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #9 0x55555596a4a3 in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4164a3)
    #10 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #11 0x55555596ee65 in MovDemuxer::mov_read_moof(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41ae65)
    #12 0x55555596a615 in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416615)
    #13 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #14 0x5555559704fd in MovDemuxer::mov_read_stsd(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41c4fd)
    #15 0x55555596a6ce in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4166ce)
    #16 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #17 0x55555596a4a3 in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4164a3)
    #18 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #19 0x55555596a4a3 in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4164a3)
    #20 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #21 0x55555596a4a3 in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4164a3)
    #22 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #23 0x55555596d034 in MovDemuxer::mov_read_trak(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x419034)
    #24 0x55555596a7ac in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x4167ac)
    #25 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #26 0x55555596ebf3 in MovDemuxer::mov_read_moov(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41abf3)
    #27 0x55555596a63a in MovDemuxer::ParseTableEntry(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x41663a)
    #28 0x55555596aefb in MovDemuxer::mov_read_default(MovDemuxer::MOVAtom) (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x416efb)
    #29 0x555555967635 in MovDemuxer::readHeaders() (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x413635)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/vagrant/tsmuxer/for-build/build/tsMuxer/tsmuxer+0x418666) in MovDemuxer::mov_read_trun(MovDemuxer::MOVAtom)
Shadow bytes around the buggy address:
  0x0c2a7fff8190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff81a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2a7fff81b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2a7fff81c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2a7fff81d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c2a7fff81e0:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff81f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff8200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff8210: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff8220: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff8230: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==29495==ABORTING

It is caused by two Bug

https://github.com/justdan96/tsMuxer/blob/75c9cb3514815d07378007d36cc90c3f209e7b36/tsMuxer/movDemuxer.cpp#L1522

a.size is a value calculated based on user input, but it does not take min with the size of stsd, that is, atom.size - ( m_processedBytes - start_pos). When a.size is large, assuming a very large atom exists under stsd, all subsequent input would be subject to ParseEntryTable under mov_read_stsd.

https://github.com/justdan96/tsMuxer/blob/75c9cb3514815d07378007d36cc90c3f209e7b36/tsMuxer/movDemuxer.cpp#L1189-L1191

When calling in the order of mov_read_trun -> mov_read_ctts -> mov_read_trun, the vector of ctts_data is resized in mov_read_ctts but ctts_count remains, so a heap buffer overflow occurs at the following place in the second mov_read_trun.

https://github.com/justdan96/tsMuxer/blob/75c9cb3514815d07378007d36cc90c3f209e7b36/tsMuxer/movDemuxer.cpp#L1100-L1102

The first bug makes it easier for the second bug to ignite.

This heap overflow has the potential to destroy the heap to some extent at will.

Ricerca Security, Inc.

iwashiira commented 3 months ago

This input seems to cause other memory leaks, so we will continue to investigate.

iwashiira commented 3 months ago

The followingsizes also need to be compared with atom.size as well as first bug. https://github.com/justdan96/tsMuxer/blob/75c9cb3514815d07378007d36cc90c3f209e7b36/tsMuxer/movDemuxer.cpp#L1510-L1519

iwashiira commented 3 months ago

this heap buffer overflow is exploitable (reverse shell can be activated).

The ASAN of mov_read_trun has not completely disappeared, but at least the heap buffer overflow has been completely mitigated by PR #851 .