來源:

作者: ele7enxxh

weibo: http://weibo.com/ele7enxxh

前言

模糊測試是一種自動向程序傳遞輸入數據并監控其輸出的自動化測試技術。通過這種技術,安全人員可以測試程序的可靠性以及識別潛在的安全漏洞。

我們(360成都安全響應中心)將對Stagefright Media Framework進行模糊測試。它是Android系統上用于解析多媒體文件的邏輯算法庫,其中包含了大量的安全漏洞,攻擊者通過構造特殊的多媒體文件導致拒絕服務或特權升級甚至遠程執行代碼。

我們將要使用的模糊測試工具為Micha? Zalewski開發的一款最為流行的基于代碼覆蓋率的開源測試工具:AFL(American Fuzzy Lop)。 借助于其高效的策略,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的主要流程圖如下圖所示。

1

方案B的主要流程圖如下圖所示。

2

顯而易見,相比于方案A,方案B更加簡潔,其效率也更好(通常來說,PC的性能遠高于任何Android手機或者Android模擬器);另一方面,由于stagefright本身的復雜性,其實現也更加困難。

在后續的文章中,我們將一步一步向你介紹如何實現方案B。通過它,我們已經發現了兩個漏洞。

細節

移植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 DriversAndroid Binder IPC Driver

3

轉到Device Drivers->Staging drivers->Android,選中Enable the Anonymous Shared Memory Subsystem

4

現在你可以開始編譯安裝內核了,執行下面的命令。

$ 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的工作屏幕。

5

建議

在這一節,我們將給你一些額外的建議,以幫助你更快的發現程序中的漏洞。

  • 使用盡可能小但覆蓋全面的測試樣本集;
  • 對于你想要進行模糊測試的模塊,盡可能的編譯為靜態模塊而不是動態模塊;
  • 不要對你不敢興趣的模塊進行插樁;
  • 使用并行模糊測試(-M選項和-S選項),更多介紹請參考AFL源碼目錄中的 docs/parallel_fuzzing.txt;
  • ASAN需要大量的內存,因此你應該提高-m選項的值。

待辦事項

本文還有許多可以改進的地方,但是我們不會在stagefright花費過多的精力了。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/245/