Update Aug 28, 2015: Typos in the final table: CVE-2015-3864 does not concern covr but tx3g. CVE-2015-3828 does not occur for yrrc.
Detecting the PoCs published by Zimperium is not difficult: you can fingerprint the PoCs, for example.
Detecting variants of the PoCs, i.e., MP4s that use one of the discovered vulnerabilities, is far more difficult. I'll explain why in a moment.
First, apart from here (in Chinese), there hasn't been so much in the way of technical details. Getting into the guts of StageFright really had me sweating. I'm not even sure I understand everything yet.
What's an ATOM?
An MPEG-4 is made of several units called 'atoms' or 'boxes'. Those boxes begin with a header, as detailed below: a size, and a box type. The box types consist of a four character code (FourCC) such as 'covr', 'esds', etc. It's while reading those boxes that Android's mediaserver sometimes encounters vulnerabilities.
Box header format
Box types affected by StageFright
Box Type Description albm Album title and track number for the media auth Author of the media covr Album cover artwork ctss Composition Time To Sample mapping esds Elemetary Stream Description gnre genre of the media perf performer or artist stsc Sample To Chunk mapping stss List of Sync Samples stts Time To Sample mapping tx3g Text metadata yrrc Recording year for the media
All of them don't crash
The first error I made was to assume all PoCs would make the Android mediaserver crash. Several PoCs (number 1, 5, 7 and 8) do not crash a number of emulators/devices running Android 4.4.2 or 5.1.1.
This does not mean, however, that the issue is not there.
PoCs that crash Android's mediaserver
PoC filename CVE-2015-.... Description Crash? sf-001.mp4 1538 stsc integer overflow No sf-002.mp4 1538 ctts integer overflow Yes sf-003.mp4 1538 stts integer overflow Yes sf-004.mp4 1538 stss integer overflow Yes sf-005.mp4 1539 esds integer underflow No sf-006.mp4 3827 covr integer underflow Yes sf-007.mp4 3826 3gpp buffer overread No sf-008.mp4 3828 3gpp integer underflow No sf-009.mp4 3824 tx3g integer overflow Yes sf-010.mp4 3829 covr integer overflow Yes
It's not because it crashes (in StageFright) that it's a "StageFright" vulnerability.
During our investigations, we were surprised to see libstagefright crash in unexpected situations with a modified sf-003.mp4.
sf-003.mp4 demonstrates an integer overflow while reading a stts box. Let's first explain when we expect the overflow to occur by analyzing the corresponding patch:
stts integer overflow patch
- uint64_t allocSize = numEntries * 2 * sizeof(uint32_t);
+ uint64_t allocSize = numEntries * 2 * (uint64_t)sizeof(uint32_t);
As sizeof(uint32_t) is 4, an integer overflow would occur if
allocSize = numEntries * 2 * 4 >= 0xFFFFFFFF + 1
i.e numEntries >= (0xFFFFFFFF + 1) / 8 = 0x20000000
So, in other terms, any MP4 file with a 'stts' box containing numEntries >= 0x20000000 will trigger the issue. An 'stts' box is a box that "defines time-to-sample mapping for a sample table". It is structured as below:
numEntries in Android's code corresponds to the Count field. So, this means that if bytes 5,6,7,8 after 'stts' are greater than or equal to 20 00 00 00, the overflow occurs.
Crash inside libstagefright caused by stts integer overflow
F/libc ( 1482): Fatal signal 11 (SIGSEGV) at 0x10958a14 (code=1), thread 1490 (Binder_2)
I/DEBUG ( 1011): backtrace:
I/DEBUG ( 1011): #00 pc 0007df3a /system/lib/libstagefright.so (android::SampleTable::setTimeToSampleParams(long long, unsigned int)+133)
I/DEBUG ( 1011): #01 pc 000630fb /system/lib/libstagefright.so (android::MPEG4Extractor::parseChunk(long long*, int)+3262)
Yet, as I said, we were surprised to see libstagefright crash with lesser values such as 0x1f ff ff ff!
Have a look at the crash log though.
Crash inside libstagefright caused by allocation
F/libc ( 1791): Fatal signal 6 (SIGABRT) at 0x000006ff (code=-6), thread 1799 (Binder_3)
/DEBUG ( 55): backtrace:
I/DEBUG ( 55): #00 pc 00021e20 /system/lib/libc.so (tgkill+12)
I/DEBUG ( 55): #01 pc 00012ea9 /system/lib/libc.so (pthread_kill+48)
I/DEBUG ( 55): #02 pc 000130bd /system/lib/libc.so (raise+10)
I/DEBUG ( 55): #03 pc 00011df3 /system/lib/libc.so
I/DEBUG ( 55): #04 pc 000216d4 /system/lib/libc.so (abort+4)
I/DEBUG ( 55): #05 pc 00000911 /system/lib/libstdc++.so (operator new(unsigned int)+8)
I/DEBUG ( 55): #06 pc 0007df0f /system/lib/libstagefright.so (android::SampleTable::setTimeToSampleParams(long long, unsigned int)+90)
I/DEBUG ( 55): #07 pc 000630fb /system/lib/libstagefright.so (android::MPEG4Extractor::parseChunk(long long*, int)+3262)
It is different:
This is a Fatal signal 6 (SIGABRT), not a SIGSEGV
The crash occurs when allocating a buffer. Specifically, it crashes on line number 337 in the file SampleTable.cpp:
mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
So what's that? It's a bug. From an end user point of view, it can be seen as a denial of service, as the mediaserver crashes. But it's not an integer overflow you can use to write the memory with a custom exploit.
How can I edit or parse MP4 files?
- 010 Editor : This is the solution I like the best. There's an MP4 template too, although it has difficulties on several PoCs.
- mp4file (apt-get install mp4v2-utils) : Quite good, and helpful to understand the MP4 format, but will fail on several PoCs.
$ mp4file --dump sf-007.mp4
"sf-007.mp4": Dumping meta-information...
"sf-007.mp4": type ftyp (ftyp)
"sf-007.mp4": majorBrand = mp42
"sf-007.mp4": minorVersion = 0 (0x00000000)
"sf-007.mp4": <table entries suppressed>
"sf-007.mp4": type mdat (mdat)
- mp4 parser : If you are using Windows (or want to use Wine).
3GPP integer underflow (CVE-2015-3828)
This article did not really explain when the issue occurs, so I will.
This is an integer underflow when parsing 3GPP Metadata. 3GPP Metadata correspond to boxes 'titl' (title), 'auth' (author), 'gnre' (genre), 'perf' (performers) and 'albm' (album).
The patch shows that, in parse3GPPMetaData, an underflow occurred if size < 6
Patch in parse3GPPMetaData
+ if (size < 6)
+ return ERROR_MALFORMED;
Beware: size here is not the box size, but the 3GPP Metadata size (chunk_data_size).
Calling parse3GPPMetaData (see line 2185)
status_t err = parse3GPPMetaData(data_offset, chunk_data_size, depth);
Compared to the chunk data size, the box size is chunk_data_size + 4 (box size) + 4 (box type).
So, the underflow occurs if the box size < 6 + 8 = 14 (0x0E). Indeed, the PoC sf-008.mp4 shows an 'albm' box with a size of 0x0D.
Note that if the box uses an extended size form, the condition where the underflow occurs is slightly changed, because the box size is chunk_data_size + 4 (extended size indicator) + 4 (box type) + 8 (extended size).
ESDS integer underflow (CVE-2015-1539)
This is a vulnerability I investigated for quite a long time because I couldn't find proper documentation. In case it can help you, I think I worked out the format of the 'esds' box.
The 'esds' atom refers to 'elementary stream descriptors'.
Its format is detailed this book.
So, we can work out the format of an esds box is:
- box size (4 bytes)
- box type (4 bytes): 'esds'
- ESDS version (1 byte): reserved to 0
- ESDS flags (3 bytes): reserved to 0
- ES_ID (2 bytes): elementary stream ID.
- ESD tag: (1 byte)
- ESD size: several bytes, last byte has high bit set
- streamDependanceFlag (1 bit): get it by doing & 0x80
- URL_Flag (1 bit): get it by doing & 0x40
- OCR_stream flag (1 bit): do & 0x20
- dependsOn_ES_ID (2 bytes): only if streamDependanceFlag
- URLLength (1 byte): only if URL_Flag
- URLString (1 byte): only if URL_Flag
- OCR_ES_ID (2 bytes): only if OCR_stream
Summarizing StageFright vulnerabilities
StageFright PoCs and issues they cause
CVE Description Hex 1538 stsc integer overflow
mNumSampleToChunkOffsets are in dark blue and cause the
1538 ctts integer overflow
numEntries are in dark blue and cause the overflow
1538 stts integer overflow
mTimeToSampleCount is in dark blue and causes the overflow
1538 stss integer overflow
mNumSyncSamples are in dark blue and causes the overflow
1539 esds integer underflow
Box type is in yellow, ESD size is in violet, ES_ID is in light green,
flags are in red.
The combination of the size and flags cause the underflow
3827 covr integer underflow
The box size is the 4 bytes before the 'covr' box type and causes the
3826 titl, albm, perf, auth, gnre buffer overread
The 3GPP string is in dark blue.
The format for 3GPP metadata fields can be found here (page 31)
3828 titl, albm, perf, auth, gnre integer underflow
The box size are the 4 bytes before the 'albm' box type .
3824 tx3g integer overflow
The box sizes are in red. Their sum causes an integer overflow in the
3829 covr integer overflow
The box size is set to 1 (orange) which means there is an extended
box size (in red) - leading to an integer overflow in the code
3864 tx3g integer overflow
An integer overflow actually occurs whenever an extended box size is used with chunk_size > 0x1ffffffff
Thanks to Neo Tan, Ruchna Nigam, Roland Dela Paz for their contribution to this work.
-- the Crypto Girl