在 Linux 上使用 AFL 对 Stagefright 进行模糊测试
前言
模糊测试是一种自动向程序传递输入数据并监控其输出的自动化测试技术。通过这种技术,安全人员可以测试程序的可靠性以及识别潜在的安全漏洞。
我们(360成都安全响应中心)将对 进行模糊测试。它是 Android 系统上用于解析多媒体文件的逻辑算法库,其中包含了大量的安全漏洞,攻击者通过构造特殊的多媒体文件导致拒绝服务或特权升级甚至远程执行代码。
我们将要使用的模糊测试工具为 Michał Zalewski 开发的一款最为流行的基于代码覆盖率的开源测试工具:。 借助于其高效的策略,AFL已经在真实产品中发现了大量的漏洞。
在本文中,我们将指导你如何在 Linux 上使用 AFL 对 stagefright 进行模糊测试,从而更高效的复现已知漏洞或发掘新漏洞。 另外,本文不仅适用于 stagefright,其中的一些经验同样适用于其它由 C/C++ 编写的 Android 本地程序。
要求
在本节中,我们将首先向你介绍本文接下来使用的环境要求以及软件版本。为了避免出现其他未遇见的错误,我们建议你和我们保持完全一致。
操作系统:Ubuntu 16.10 64bit, 不建议使用32位系统;
AFL版本:2.39b,最新的总是更好的;
AOSP版本:7.1.1_r25,如果你使用的是其他版本,你可能无法直接使用补丁文件;
llvm 和 clang 版本:3.8。
我们假设你已经完成了下载并且编译 AOSP 的工作。另外,如果你想要使用 ASAN,我们建议你编译 AOSP 为 x86 版本。
概述
官方 AFL 只支持在 Linux 上进行模糊测试,而 stagefright 是在 Android 多媒体框架下工作的,因此我们无法直接使用 AFL 对 stagefright 进行模糊测试。为了解决这个问题,我们提出了下面两种方案。
方案A:将 AFL 移植到 Android 上,从而在 Android 模拟器或者真实的 Android 设备上进行模糊测试;
方案B:将 stagefright 移植到 Linux 上,从而直接使用官方 AFL 对其进行模糊测试。
其中,我们已经实现了方案 A–android-afl,并且公布了源代码,你可以从得到更多信息。
方案 A 的主要流程图如下图所示。
方案 B 的主要流程图如下图所示。
显而易见,相比于方案A,方案 B 更加简洁,其效率也更好(通常来说,PC的性能远高于任何 Android 手机或者 Android 模拟器);另一方面,由于 stagefright 本身的复杂性,其实现也更加困难。
在后续的文章中,我们将一步一步向你介绍如何实现方案B。通过它,我们已经发现了两个漏洞。
:mediaserver 的拒绝服务漏洞;
:mediaserver 的拒绝服务漏洞。
细节
移植 stagefright 到 Linux
显而易见,我们首先要让 stagefright 在Linux 上正常工作。
移植binder和ashmem
stagefright 需要通过 ashmem 驱动来共享内存,然而默认情况下 Linux 内核并不包含ashmem 驱动。幸运的是,我们可以通过修改 Linux 内核配置,并重新编译安装新内核,从而激活 ashmem 驱动。
我们也许还有更好的解决方案,例如:使用 shm 代替 ashmem 或者完全去掉 ashmem 相关的代码;
注意,本文并未使用 binder 驱动,这里移植 binder 只是顺便而已。
使用以下命令下载内核源码。
$ sudo apt install linux-source
转到你要保存内核源码的目录并提取压缩文件。
$ cd kernel$ tar jxvf /usr/src/linux/linux-source-4.8.0.tar.bz2
$ cd linux-source-4.8.0
拷贝旧的.config文件到源码根目录并开始配置。
$ cp -vi /boot/config-`uname -r` .config
$ make oldconfig
接着使用下面的命令来激活ashmem驱动。
$ make menuconfig
转到 Device Drivers->Android,选中 Andoid Drivers 和 Android Binder IPC Driver。
转到 Device Drivers->Staging drivers->Android,选中 Enable the Anonymous Shared Memory Subsystem。
现在你可以开始编译安装内核了,执行下面的命令。
$ make -j16
$ sudo make modules_install
$ sudo make install
你还需要配置 udev 规则,从而使得任何用户均可访问 binder 和 ashmem。
$ echo -e "KERNEL==\"binder\", MODE=\"0666\"\nKERNEL==\"ashmem\", MODE=\"0666\"" | sudo tee /etc/udev/rules.d/android.rules
最后,重启你的电脑以启用新内核。
修改Stagefright源码
注意,变量 ANDROID_BUILD_TOP 为 AOSP 的根目录,ANDROID_PRODUCT_OUT 为 AOSP 的输出目录。
在这一节,你需要对 stagefright 源码(包括 libstagefright 和 stagefright 命令行工具)进行改动,原因主要为以下两点。
平台性:stagefright 使用了 binder 驱动进行进程间通信,然而默认情况下 Linux 内核并不包含 binder 驱动(实际上,我们可以通过修改 Linux 内核配置,并重新编译安装新内核,从而激活 binder 驱动);
依赖性:stagefright 命令行工具无法独立的对多媒体文件进行解析,它依赖于其他服务进程(如:servicemanager,mediaserver 等)。
我们将不会阐述解决上诉两个问题的具体细节,你可以直接使用我们提供的适用于7.1.1_r25版本的补丁文件。如果你使用的版本和我们不同,你可能需要参照补丁文件,手动修改代码。
点击下载补丁文件 stagefright.diff,转到 $ANDROID_BUILD_TOP/aosp/master/frameworks/av 目录并应用补丁。
$ cd $ANDROID_BUILD_TOP/frameworks/av $ git apply stagefright.diff
编译
编译好x86版本的AOSP后,转到stagefright源码目录,并编译。
$ cd $ANDROID_BUILD_TOP/frameworks/av/cmds/stagefright $ mm -j16
编译结束后,你可以在$ANDROID_PRODUCT_OUT/system/bin目录找到stagefright可执行程序。
配置运行环境
为了让系统能正确找到加载器以及依赖库的位置,你需要做以下软连接。
$ sudo ln -s $ANDROID_PRODUCT_OUT/system /system
拷贝解码器配置文件到/etc目录。
$ sudo cp $ANDROID_PRODUCT_OUT/system/etc/media_codecs_google_audio.xml /etc $ sudo cp $ANDROID_PRODUCT_OUT/system/etc/media_codecs_google_telephony.xml /etc $ sudo cp $ANDROID_PRODUCT_OUT/system/etc/media_codecs_google_video.xml /etc $ sudo cp $ANDROID_PRODUCT_OUT/system/etc/media_codecs.xml /etc
另外,如果需要在后续使用ASAN,你还需要做以下软连接。
$ ln -s $ANDROID_PRODUCT_OUT/system/bin/linker $ANDROID_PRODUCT_OUT/system/bin/linker_asan $ ln -s $ANDROID_PRODUCT_OUT/obj/lib/libclang_rt.asan-i686-android.so $ANDROID_PRODUCT_OUT/system/lib/libclang_rt.asan-i686-android.so
测试运行
现在,你可以尝试在Linux上运行stagefright了。例如,解析一个MP4文件,运行结果如下。
$ /system/bin/stagefright Disco.240p.mp4 thumbnailTime: 0 us (0.00 secs) AVC video profile 66 and level 13 format changed. ...................$ avg. 180.73 fps avg. time to decode one buffer 5485.86 usecs decoded a total of 304 frame(s).
很好,你已经完成了最为困难也最为重要的工作!
移植AFL
首先,你需要从官网下载最新的AFL源码并解压。
$ wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz $ tar zxf afl-latest.tgz
接着,对AFL源码进行修改以修复下面几个错误。
error: undefined reference to '__fprintf_chk'
error: undefined reference to 'shmat'
error: undefined reference 'afl-area_prev'
同样,我们直接给出适用于2.39b版本(此时的最新版本)的AFL的补丁文件。如果你使用的版本和我们不同,你可能需要参照补丁文件,手动修改代码。
从下载补丁文件afl-2.39b.diff到你的电脑,转到AFL源码根目录并安装补丁。
$ cd afl-2.39b $ patch -p2 < afl-2.39b.diff
使用以下命令编译安装AFL。
$ make clean all $ cd llvm_mode $ EXTRA_CFLAGS="-target i686--linux-android -U_FORTIFY_SOURCE" make clean all $ cd ../ $ sudo make install
使用AFL和ASAN进行重编译
首先,进入你想要进行模糊测试的模块目录。
$ cd MODULE_PATH
其次,在其Android.mk文件中添加以下代码。
LOCAL_CLANG := true export AFL_CC := /usr/bin/clang LOCAL_CC := afl-clang-fast export AFL_CXX := /usr/bin/clang++ LOCAL_CXX := afl-clang-fast++
注意,由于 unsupported reloc 这个错误,我们不推荐使用 afl-gcc/afl-g++。另一方面,根据 AFL 官方的资料,afl-clang-fast/afl-clang-fast++ 也是更高效的。
接着,如果你想使用ASAN,你需要添加下面一行代码
LOCAL_SANITIZE := address
或者
LOCAL_SANITIZE := integer
最后,重新编译stagefright。
$ mm -j16
对于复杂的模块来说,你需要重复上面步骤数次,以对多个感兴趣的模块进行插桩。例如,你也许想要对以下模块进行插桩。
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/omx
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/yuv
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/colorconversion
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/codecs/aacenc
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/matroska
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/filters
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/webm
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/mpeg2ts
$ANDROID_BUILD_TOP/frameworks/av/media/libstagefright/id3
…more…
恭喜你,所有准备工作都已经完成了,让我们开始模糊测试吧!
模糊测试
首先,你需要为AFL创建两个目录,一个为in,用于存放预先准备的输入样本;另一个为out,用于存放AFL模糊测试过程中生产的一些有用信息以及自动生成的会让程序挂起或者崩溃的样本。
$ mkdir in $ mkdir out $ cp -r testcase/* in
其次,你需要以root用户修改/proc/sys/kernel/core_pattern,以修复Pipe at the beginning of ‘core_pattern’这个错误。
$ sudo -s $ echo core >/proc/sys/kernel/core_pattern
接着,你还需要设置CPU的工作模式为performance,以此来提高AFL的效率。
$ sudo -s $ cd /sys/devices/system/cpu$ echo performance | tee cpu*/cpufreq/scaling_governor
如果使用了ASAN,你可能需要执行以下命令。
$ export ASAN_OPTIONS=abort_on_error=1:detect_leaks=0:symbolize=0:allocator_may_return_null=1
最后,执行以下命令开始模糊测试。
$ afl-fuzz -m 4096 -t 10000 -i in -o out -- /system/bin/stagefright @@
如果一切顺利,你将看到类似的AFL的工作屏幕。
建议
在这一节,我们将给你一些额外的建议,以帮助你更快的发现程序中的漏洞。
使用尽可能小但覆盖全面的测试样本集;
对于你想要进行模糊测试的模块,尽可能的编译为静态模块而不是动态模块;
不要对你不敢兴趣的模块进行插桩;
使用并行模糊测试(-M选项和-S选项),更多介绍请参考AFL源码目录中的 docs/parallel_fuzzing.txt;
ASAN需要大量的内存,因此你应该提高-m选项的值。
待办事项
本文还有许多可以改进的地方,但是我们不会在stagefright花费过多的精力了。
声明:转载请注明作者及出处, 并附上原文链接。
热 门 阅 读:
......
更多优秀文章点击左下角“关注原文”查看!
看雪论坛:http://bbs.pediy.com/
微信公众号 ID:ikanxue
微博:看雪安全
投稿、合作:www.kanxue.com