四个参数搞定安卓驱动fuzzing!(附DeathFuzzer工具)

原创作者:成王败寇

安卓驱动fuzz之现状:

大家最近有木有发现个现象,新买的安卓手机已经无法进行root了,各大root神器都处于冰冻状态,仅有个别机型可以root成功,什么原因呢?其实主要是现在的硬件性能得到了大幅提升,安卓系统再也不必为安全选项导致的性能损失而担心了。

所以自从安卓5.1之后,基本上native层的安全机制都处于火力全开的状态了。所以现在如果发现了个native层的漏洞,那么怎么利用成了最大问题,想绕开这些安全机制还是很困难的,通常需要好几个漏洞一起配合才能达到目的!这还得说是品相好的漏洞,品相不好的洞就不要提了,最多搞个DOS就差不多了。

但白帽子们并不绝望,至少在安卓的内核层,设备驱动上,并没有发现太多安全机制,再加上某些厂商做的第三方驱动不靠谱,所以还是有很大空间可以发挥。 

安卓驱动的fuzz其实与linux驱动fuzz差不太多,都会使用ioctl或者直接读写的方式进行访问,所不同的是,由于安卓内核的精简性,你会受到很多开发环境上的制约。我们需要先在外部使用NDK(或者其他第三方的toolchain也可以)进行程序开发,然后再把程序通过adb送入安卓系统中run起来。再加上安卓系统芯片平台不同,你可能需要采取不同的编译策略才能正常运行,例如5.0以后需要加PIE选项等等,的确是给fuzz过程造成了不少困扰。

另一个困扰是安卓驱动fuzz工具方面的匮乏。

其实由于ioctl这个接口的精简设计,我们并不需要在程序内部去构造参数与上下文数据来进行fuzz,理论上说可以把所有的fuzz数据都通过外部生成,然后再传入fuzz程序让它跑起来。所以构造fuzz数据与代码开发工作其实是完全可以分开的。

为什么说这个呢,是因为近期在搞Trinity,Trinity移植到安卓后有很多bug不知道你们遇到没?最常见的,-X权限废柴、日志无法写入、fill_arg()报错、socket挂死问题等等,我都一一修复了,但这一切槽点,都抵不过你每次fuzz一个驱动都要为它重新写代码重新编译这个梗让人崩溃,遇到传递复杂数据结构参数的驱动,光是写那个参数配置都要折腾1、2个小时!其实这不是trinity不够smart,说实话Trinity的代码工程架构还算是优美的,作为一个开源软件这已经很让人很满意了。

但trinity忽略了一个重要的易用性问题,作为fuzz工具,应该尽量的把业务活动与写代码的事情分开。通俗的说就是fuzz的数据应该尽量靠外部配置然后传递给fuzz程序,fuzz程序把数据按照配置生成好并传递给fuzz对象,在这方面peach做的就非常出色,peach能够使用xml文件对程序的状态机、参数数据结构、变异方式等做全面的配置,无需每次重新编译你的代码,就可以愉快的跑下去了,但可惜peach不支持安卓。

fuzz测试的理想

基于上述问题和槽点,我写了DeathFuzzer,当然目前还是概念实验阶段,需要和大家一起交流心得和需求。这次发布的是个安卓native层的可执行文件,成熟的形态应该是个apk程序,安装到手机后图形化配置你要fuzz的对象,然后点点、选选、填填就能愉快的fuzzing了。终极形态甚至应该是个专用设备,接上数据线,配置一下,你就可以去看电影了,等看完电影回来,DeathFuzzer就会吐几个0day给你,然后你不得不承认,这个逼装的不错!嘎嘎,好了,让我们回到现实,千里之行始于足下……

DeathFuzzer简介

目前发布的1.0版是个终端命令行版本,能够对安卓手机驱动进行黑盒fuzz,通过write和ioctl来对驱动进行访问,CMD值通过参数给定范围自动变异,CMD对应的arg是程序内部的变异器来完成数据生成和传递的,长度和内容都能够变异,本人已经通过这个程序发现了好多个内核panic!   

Now, let's go !一起看看这个程序怎么玩!

首先,DeathFuzzer是个非常简单的小程序!一共就4个参数,你填完4个参数剩下的就是等着看了。直接不加参数运行就会显示usage。

DeathFuzzer使用方法: ./DeathFuzzer [驱动文件路径] [测试要使用的用户权限] [CMD最小值] [CMD最大值]

我来逐一说一下这几个参数的含义:

[驱动文件路径]:就是要fuzz的驱动的绝对路径,大部分是一些字符设备啥的,就像下面这些玩意,例如/dev/usf1

crw-rw---- root     usb       10,  45 2014-05-19 17:16 usb_accessory  crw------- root     root     237,   0 2014-05-19 17:16 usb_ext_chg  crw-rw---- system   mtp       10,  47 2014-05-19 17:16 usb_mtp_gadget  crw------- system   root      10,  65 2014-05-19 17:16 usf1  crw-rw---- system   camera    81,   6 2014-05-19 17:16 v4l-subdev0

[测试用户权限切换]:注意这个用户切换功能需要有root权限才能生效!有些驱动仅允许root和某个用户属组访问,那么你最好切换到这个非root的用户属组来进行fuzz,这样一旦出现问题你没准还能搞个提权的0day啥的。

[CMD最小值] [CMD最大值]:既然我们对驱动的fuzz是纯黑盒的(其实很多驱动代码都是公开的,你可以直接参照代码指定这个范围),那么我们需要手动的去指定个CMD的范围,然后通过驱动的反馈来猜测这个范围是否准确(是否有点像盲注?),制定了最小值和最大值,那么DeathFuzzer的CMD就会在这个范围内进行变异。

上面的说明balabala的没什么意思,还是举个栗子吃吧,例如我们要fuzz下面这个uhid驱动,

crw-rw---- system   net_bt_stack  10,  41 2014-05-19 17:16 uhid

这个uhid文件在/dev目录下,net_bt_stack对其有访问权限,那么我们的程序参数应该是这样配置的。

./DeathFuzzer    /dev/uhid    net_bt_stack    0x1    0xff

或者是这样的,

./DeathFuzzer    /dev/uhid    root    0x3f    0x4f

fuzz过程中会在程序目录中生成一个Fuzzlog.txt文件,这个文件中记录着每一次fuzz的参数内容,方便对bug进行回溯。

fuzz日志如下图,记录着fuzz时间,cmd值,每个[]换行后下面的乱码就是ioctl和wirte传递的内容,日志是二进制文件,最好使用UE或者010edit来查看,然后配合tombstones和dmesg就可以定位bug的原因了。

    四个参数搞定安卓驱动fuzzing!(附DeathFuzzer工具)

好了,DeathFuzzer的介绍到此结束了,以下为使用方法,祝大家玩的开心!程序下载地址在文章结尾处。

使用方法:(前提是要先在系统中安装安卓SDK,然后把SDK中的platform-tools目录加入环境变量)

首先第一步把DeathFuzzer 用 adb push 传进手机。

    四个参数搞定安卓驱动fuzzing!(附DeathFuzzer工具)

第二步,adb shell进入手机的终端控制台,cd进入/data/local/tmp目录。

    四个参数搞定安卓驱动fuzzing!(附DeathFuzzer工具)

第三步,使用chmod给DeathFuzzer可执行权限,并且加参数进行fuzz。

    四个参数搞定安卓驱动fuzzing!(附DeathFuzzer工具)

然后就等着看手机是否出现崩溃、重启等问题,出现以后使用adb pull 把DeathFuzzer的日志取出来,配合tombstones和dmesg就可以定位bug的原因了。

    四个参数搞定安卓驱动fuzzing!(附DeathFuzzer工具)

DeathFuzzer下载链接: http://pan.baidu.com/s/1pKonMv5 密码: vbhm

*作者:成王败寇,本文属FreeBuf原创奖励计划文章,未经许可禁止转载