# Stagefright漏洞公告

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2015-07-31T08:53:00Z
Canonical: https://wepostx.com/topics/936

> 乌云历史资料归档
>
> **原始作者：** 阿里移动安全
> **原始编号：** superkieran-wooyundrops:672
> **原始发布时间：** 2015-07-31 16:53
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

作者: 迅迪 没羽 轩夏 成淼 奋龙 逆巴

# 0x00 什么是Stagefright

StageFright是一个Android中的系统服务，可处理各种多媒体格式，由Natvie C++代码实现，多媒体应用如何与Android Native多媒体进行交互可参考如下图：

![原文图片](/media/2016/06/e0b289161682dcfde9da36fb96f39a03)

而Stagefright所涵盖的模块非常广

```text
|-- stagefright | | | |-- codecs //提供解码器实现 | | | |-- colorconversion //颜色空间转换 | | | |-- foundation //基本数据结构的实现 | | | |-- httplive //m3u8解析 | | | |-- id3 // ID3 TAG解析（一般用于MP3格式的metadata容器） | | | |-- include //基本头文件 | | | |-- matroska //matroska文件解析 | | | |-- mpeg2ts //mpeg2ts文件解析和数据获取一些处理 | | | |-- mp4
```
由于多媒体处理的实时性特征，该库通过Native代码实现，这也是的该库存在内存破坏的问题远远多于Java实现的代码。

# 0x01 谁发现了Stagefright

以色列移动信息安全公司Zimperium研究人员Joshua Drake在7月21号发布的声明，声称会在8月的BlackHat会议上发布细节。

# 0x02 漏洞概要

Android Stagefright框架中发现了多个整数溢出和下溢，不正确整数溢出检查等漏洞，可导致任意代码执行等问题。
攻击者通过发送包含特制媒体文件的MMS或WEB页来触发该漏洞。由于stagefright不只是用来播放媒体文件的，还能自动产生缩略图，或者从视频或音频文件中抽取元数据，如长度、高度、宽度、帧频、频道和其他类似信息。因此接收到恶意彩信的用户只要查看缩略图就可触发该漏洞。
“Stagefright”媒体播放引擎库在Android 2.2中引入，至5.1的所有版本上均存在此漏洞，预计会有95%的Android设备,约有九亿五千万的安卓设备受该漏洞影响.
使用Stagefright库的应用程序以Media权限运行，成功利用漏洞，允许攻击者浏览器媒体库相应的文件，但通过权限提升攻击，可完全控制设备。
该Stagefright漏洞所对应的CVE ID如下：

```text
CVE-2015-1538 CVE-2015-1539 CVE-2015-3824 CVE-2015-3826 CVE-2015-3827 CVE-2015-3828 CVE-2015-3829
```

# 0x03 漏洞分析

根据https://github.com/CyanogenMod/android_frameworks_av/commits/cm-12.1提供的补丁，进行了相关的分析：
4.1 Prevent reading past the end of the buffer in 3GPP
补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/57db9b42418b434751f609ac7e5539367e9f01a6
```
该漏洞产生在以下的chunk中：

![原文图片](/media/2016/06/adc7e936430ec31dd0efc5e3b49a397f)

这是一个堆内存读越界漏洞，parse3GPPMetaData方法中调用mDataSource->readAt( offset, buffer, size)读取size大小的数据到申请的buffer中，然后下面会调用mFileMetaData->setCString()方法进行内存拷贝：

![原文图片](/media/2016/06/20a38583ff46b1e818b460165413cbcc)

我们来看setCString()方法的最终会调用memcpy进行内在拷贝：

```text
#!c++ void MetaData::typed_data::setData(uint32_t type, const void *data, size_t size) { clear(); mType = type; allocateStorage(size); memcpy(storage(), data, size); }
```
由于对memcpy中size的处理不当，导致越界读取了内存数据。
4.2 Prevent integer underflow if size is below 6
补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/9824bfd6eec1daa93cf76b6f4199602fe35f1d9d
```
该漏洞是一个integer underflow漏洞，对于构造的size来说，如果size<6，可导致len16的值变的很大：

![原文图片](/media/2016/06/b4cc3f91ecd0fc8551b3e9c5b34f5430)

导致接下来的内存越界操作：

![原文图片](/media/2016/06/fa664c15d4c134c581dd59601d321cce)

4.3 Fix integer overflow when handling MPEG4 tx3g atom

补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/889ae4ad7227c395615d03b24a1667caa162c75f
```
该漏洞产生在“tx3g”的chunk中，chunk_size是uint，与size之和溢出，会导致实际分配比size小的内存。后面的memcpy函数将会发生堆溢出：

![原文图片](/media/2016/06/fd3685f2a11db6c1fbafa34d69781f7c)

当mLastTrack->meta->findData(kKeyTextFormatData, &type, &data, &size)函数调用返回为真，size值将不会为0，chunk_size与size都为uint8_t，之和后发生整数溢出，这样导致new一个比size更小的空间，在随后的memcpy将发生堆溢出：

```text
#!c++ bool MetaData::findData(uint32_t key, uint32_t *type, const void **data, size_t *size) const { ssize_t i = mItems.indexOfKey(key); //键值存在 i>0 if (i < 0) { return false; } const typed_data &item = mItems.valueAt(i); item.getData(type, data, size); return true; }
```
接下来new (std::nothrow) uint8_t[size + chunk_size] ,size与chunk_size之和发生整数溢出，值将小于size,此后的memcpy发生堆溢出：

![原文图片](/media/2016/06/94ed1898d449abc2766eb17cdf0e54b3)

4.4 Fix integer underflow in covr MPEG4 processing
补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/b1f29294f1a5831eb52a81d3ee082a9475f6e879
```
从patch代码可知，由于未检测chunk_data_size的长度，导致后面的chunk_data_size – kSkipBytesOfDataBox为负数，

![原文图片](/media/2016/06/a1f6e4a949ccd85a42ae126b2ebe9b16)

向上追溯，chunk_data_size = offset + chunk_size - data_offset；off64_t data_offset = *offset + 8；其中chunk_size为mpeg4格式中box的chunk_size，offset为当前的box的起始位置。由patch代码可知，有这样的不等或成立才能避免该漏洞的出现：

```text
chunk_data_size <= kSkipBytesOfDataBox ⇨ *offset + chunk_size - *offset - 8 <= 16 ⇨ chunk_size - 8 <= 16 ⇨ chunk_size <= 24(0x18)
```
所以当chunk_size的值<=24时会触发漏洞。构造的一个样本（0x08）截图如下：

![原文图片](/media/2016/06/53b0c94de9102846cf393bdf42ed83c4)

4.5 Prevent integer overflow when processing covr MPEG4 atoms
补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/7ff5505d36b1cfd8b03497e0fb5aa24b5b099e45
```
从patch代码可知，由于未对chunk_data_size的长度进行限制，当chunk_data_size>=SIZE_MAX-1时，chunk_data_size＋1>=SIZE_MAX，导致ABuffer分配0长度的内存，后续再进行内存操作就导致堆越界。

![原文图片](/media/2016/06/931f67e0f10168bfc197e74e62f2b766)

4.6 Fix integer overflow during MP4 atom processing
补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/3854030bf70cb78ec0afbf90d0e7d8e1cf8f9904
```
从代码分析可知，要构造出满足条的POC样本，需要chunk_size=1，然后unint64来存储chunk_size。对于该漏洞POC的构造，我们假设：mNumSampleToChunkOffsets = 0xFFFFFFFF/0xC 可得，mNumSampleToChunkOffsets = 0x15555555
我们构造如下样本：

![原文图片](/media/2016/06/8100d455e7c86d188efced46e7563351)

其中chunk_size 为1，large_chunk_size为0x100000007, mNumSampleToChunkOffsets为0x15555555。
加载该样本，运行截图如下：

![原文图片](/media/2016/06/82100f4e73cb73dc537ee6927c838d07)

4.7 Fix integer underflow in ESDS processing
补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/e586b3e891e7c598449d40a9c44c70fd6663d064
```
从patch代码可知，由于未对size的大小进行检测，后续会进行多次－2操作，导致size为负数，导致堆下溢出。

![原文图片](/media/2016/06/3641f514ffb9ab6b917d5e143e77d9c8)

要构造poc需进入ESDS.cpp查看详细代码：

![原文图片](/media/2016/06/3e8421b2eb4cf5d23e9475ff190524d4)

首先获取偏移的值，并进行一系列运算，当more＝true时停止，并返回data_size，然后开始解析ESDS。

![原文图片](/media/2016/06/54a56d24c6e9409fd6c11d57a2273f92)

从代码可以看出来当3个标志位都为1时，才会进行size－2操作，因此构造的poc必须满足3个标志位，0xE0以上数值就满足要求。因此将size修改为5，标志位修改为0xE3就能触发漏洞的畸形样本截图如下：

![原文图片](/media/2016/06/014f9cf0b397370c28f1bf5d082e2c62)

4.8 Fix several ineffective integer overflow checks
补丁链接：

```text
https://github.com/CyanogenMod/android_frameworks_av/commit/16c78bb6608dd5abbf3a1fc1cd98e8fc94cfb241
```
此漏洞有3处patch，涉及到3个chunk分别是“stts”、“ctts”、“stss”。是由于几个uint32型数据相乘，再赋值给uint64可能会导致溢出：

![原文图片](/media/2016/06/e5cfc45de47c1ea0098e852a112aedc0)

以“stts”chunk为例来说一下poc的构造： 代码分析，我可得“stts”chunk的结构头如下：

![原文图片](/media/2016/06/44ec0335f879a0c71b28b5f86505d690)

第4个4字节的值即为mTimeToSampleCount，我们假设存在这样一个等式：mTimeToSampleCount * 2 * 4 = 0xFFFFFFFF+0x1可得，mTimeToSampleCount＝0x20000000 我们以mTimeToSampleCount＝0x20000000构造的一个POC如下：

![原文图片](/media/2016/06/bfaee31d5e7db26188c23f2e96ac6bc1)

运行结果：

![原文图片](/media/2016/06/dfe9cfc367a30a6495a2963e7069a194)

chunk“ctts”、“stss”也可以通过类似的方法构造出POC。

# 0x04 触发途径

- 可通过发送嵌入恶意视频文件的彩信

- 构建嵌入恶意视频的WEB页，诱使使用Stagefright库的浏览器或应用打开

- 构建恶意视频文件，诱使链接Stagefright库的应用打开

# 0x05 受影响厂商

```text
Amazon Barnes and Noble Google HTC Huawei Technologies Kyocera Communications LG Electronics Motorola, Inc. Samsung Mobile Sony Corporation
```
等

# 0x06 受影响应用：

由于Stagefright是一个底层的多媒体处理库，因此调用该库的应用都受此漏洞影响，我们随机检测国内主流的几个应用做，发现都存在此问题：
6.1 绝大多数视频APP都受影响，以乐视视频为例

```text
- 受影响版本：Android/5.9.3 - 点击特制构建的视频文件，选择“乐视视频”播放：
```

![原文图片](/media/2016/06/884aba0b4afd95d24624d315cf5ef2d3)

- 查看手机端，乐视视频播放文件出错：

![原文图片](/media/2016/06/28a5ffb4fba7a7492383f834141e2429)

-查看日志信息，可以看到libstagefright.so的crash信息，在MPEG4Extractor::parseChunk(off64_t *offset, int depth) 方法中解析文件出错，受影响代码可以参考：

```text
https://android.googlesource.com/platform/frameworks/av/+/android-5.1.1_r8/media/libstagefright/MPEG4Extractor.cpp：
```

![原文图片](/media/2016/06/bf90ac3a3c49f911a08277aa9339cf1e)

6.2 某手机浏览器

```text
- 版本： Android/6.0.1.1560 - 测试： 使用某手机浏览器的二维码功能，扫描生成的视频PoC文件， 在浏览器弹出的提示窗口中选择“直接打开”：
```

![原文图片](/media/2016/06/f98361e6f765984e1ba37b7c2d8112f4)

-查看手机端，播放视频文件出错：

![原文图片](/media/2016/06/e7a026ccdad9ec657033b8a7e77b2852)

-查看日志信息，可以看到libstagefright.so的crash信息，在MPEG4Extractor::parseChunk(off64_t *offset, int depth) 方法中解析文件出错。

![原文图片](/media/2016/06/936ab200a25027b94cf5bb5de7891f94)

6.3某SNS通讯工具

```text
- 版本： Android/6.2.2 - 发送特殊构建的视频文件时，点击播放会弹出“播放失败”窗口，如图：
```

![原文图片](/media/2016/06/ffa3ee3d151a95e6eee8dbc9cebfe9b7)

- 在后台接收手机的错误信息，发现了libstagefright.so的crash信息：

![原文图片](/media/2016/06/9dcae4a18a66699fb65601ba33607b3a)

可以看到解析视频文件时发生崩溃，通过视频发送或SNS形式传播，可大范围的影响用户。

# 0x07，缓解方案

- root安卓设备，禁用Stagefright,(会导致大量应用不可用，系统无法正常使用)

- 谨慎打开莫名的mp4文件或者陌生人发送的彩信

- 使用谷歌的Hangouts App用户请将彩信的媒体文件自动下载功能禁用

- 使用谷歌的Messenger客户端(安卓5.0以上版本的系统默认短信客户端)请关闭自动获取MMS消息功能

- 三星Galaxy S6中，按照以下步骤去禁用系统默认短信客户端中的自动获取彩信功能： 短信app-更多-设置-更多设置-多媒体消息-自动获取

- 安装阿里钱盾等安全软件，以便于防范病毒木马对该漏洞的利用

# 0x08 厂商解决方案

Google已经发布Android 5.1.1_r5修复该漏洞，注意不是所有Android 5.1.1 (Lollipop)手机应用了该补丁，需要安装patchlevel r5补丁：

```text
https://android.googlesource.com/platform/frameworks/av/+/0e4e5a8%5E!/ https://android.googlesource.com/platform/frameworks/av/+/5c134e6%5E!/ https://android.googlesource.com/platform/frameworks/av/+/030d8d0%5E!/
```
CyanogenMod中的cm12.1 branch已经修复该漏洞：

```text
https://github.com/CyanogenMod/android_frameworks_av/commits/cm-12.1
```
积极联系通过厂商OTA进行更新

# 0x09 参考链接

```text
- http://blog.zimperium.com/experts-found-a-unicorn-in-the-heart-of-android/ - http://www.kb.cert.org/vuls/id/924951 - http://www.forbes.com/sites/thomasbrewster/2015/07/27/android-text-attacks/ - http://www.zdnet.com/article/stagefright-just-how-scary-is-it-for-android-users/ - http://arstechnica.com/security/2015/07/950-million-android-phones-can-be-hijacked-by-malicious-text-messages/ - https://android.googlesource.com/platform/frameworks/av/+/0e4e5a8%5E!/ - https://android.googlesource.com/platform/frameworks/av/+/5c134e6%5E!/ - https://android.googlesource.com/platform/frameworks/av/+/030d8d0%5E!/ - http://source.android.com/devices/media.html - https://www.duosecurity.com/blog/exploit-mitigations-in-android-jelly-bean-4-1
```

## Replies
