Android Fuzz 漏洞挖掘初探

1 简介

最近因为某些原因,主要看了几乎能找到的安卓相关的fuzz脚本。当然时间原因具体实际测试的并不是特别多,下面就发现的一些问题,以及个人想法分享一下。

2 实际应用过程中的收获

2.1 binder fuzz的基础

  (1) binder 机制
  Android的Binder机制 

Binder其实也不是Android提出来的一套新的进程间通信机制,它是基于OpenBinder来实现的。Binder是一种进程间通信机制,它是一种类似于COM和CORBA分布式组件架构,提供远程过程调用(RPC)功能。
那么何为Binder?
直观来说,Binder是Android中的一个类,它继承了IBinder接口;
从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有;
从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等)和相应ManagerService的桥梁;
从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你Bind Service的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
在Android系统的Binder机制中,由系统组件组成,分别是Client、Server、Service Manager和Binder驱动程序,其中Client、Server和Service Manager运行在用户空间,Binder驱动程序运行内核空间,如图1所示。Binder就是一种把这四个组件粘合在一起的粘结剂,其中核心组件便是Binder驱动程序了,Service Manager提供了辅助管理的功能,Client和Server正是在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。Service Manager和Binder驱动已经在Android平台中实现好,开发者只要按照规范实现自己的Client和Server组件就可以了。

Android Fuzz 漏洞挖掘初探_第1张图片

(2) Aidl机制
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
AIDL IPC机制是面向接口的,像COM或CORBA一样,但是更加轻量级。它是使用代理类在客户端和服务端传递数据。只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service,以及想在你的service处理多线程。如果不需要进行不同应用程序间的并发通信(IPC),或者你想进行IPC,但不需要处理多线程的。使用AIDL前,必须要理解如何绑定service。
AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。

2.2 binder 的接口

(1)系统保留测试接口
 Android给我们留下了“测试后门”。在shell中,通过service指令可以直接对系统服务进行测试,并支持对所有aidl文件中定义的方法的测试。
直接adb shell service list 列出系统服务名称,如图二所示:
Android Fuzz 漏洞挖掘初探_第2张图片

测试命令 :service call SERVICE CODE 就是对aidl文件中定义的方法的测试。其中,SERVICE就是对应的service名,code就是在aidl文件中定义的方法,其数值根据定义的方法递增,从1开始。方法中的参数是直接给的null 值。测试脚本如下图三:

图3 测试脚本

(2)java 反射调用接口
上述方式可以直接用python写个脚本本地测试。第二种方法是编写本地App,通过调用binder来对系统服务进行测试采用第二种,更加有利于学习Android系统服务及binder通信机制的相关知识。我也分别尝试了两种方式,比如在第一种脚本测试的过程更暴力一点,code参数直接盲测的,data数据直接给的null值。本地app的测试更温和一点,code 直接可以反射出来,data 也重新按照格式构造了。
fuzz的切入点
为了更好的挖掘漏洞,选择fuzz接口需要满足这几个要求:
1)这个接口是开放的,是可以被低权限进程调用的
2)这个接口距离fuzz目标(系统服务)比较接近,中间路径最好透传,这样比较容易分析异常
3)从简原则
根据上面的分析,BpBinder中的transact函数就是一个很好的fuzz接口,但这个函数在底层无法直接调用。
底层transact方法介绍
在c层中,BBinder::transact中会调用onTransact,这个onTransact才是真正处理业务的。需要注意的是,因为我们的binder实体在本质上都是继承于BBinder的,而且我们一般都会重载onTransact()函数,所以onTransact()实际上调用的是具体binder实体的onTransact()成员函数。也就是说,onTransact的具体实现一般在上层的binder实体,而不在BBinder。BBinder没有实现一个默认的onTransact()成员函数,所以在远程通信时,BBinder::transact()调用的onTransact()其实是Bnxxx或者BnInterface的某个子类的onTransact()成员函数,举个例子,BnMediaRecorder中实现了一个onTransact函数,通过switch-case,根据不同code进行分发处理。
我们从BpBinder往上层找,很容易发现,Java层IBinder的transact函数最终调用到BpBinder,且参数是原封不动的“透传”到底层,考虑到java层的可视化和扩展性,可以选择IBinder的公有方法transact作为fuzz接口。
transact的四个参数介绍。我们可以构造这四个参数进行测试。
code是int类型,指定了服务方法号
data是parcel类型,是发送的数据,满足binder协议规则,下面会有详述
reply也是parcel类型,是通信结束后返回的数据
flag是标记位,0为普通RPC,需要等待,调用发起后处于阻塞状态直到接收到返回,1为one-way RPC,表示“不需要等待回复的”事务,一般为无返回值的单向调用。
根据上面分析情况,参考别人脚本写了部分测试,如下图4:

Android Fuzz 漏洞挖掘初探_第3张图片

2.3 实际测试

在实际测试过程中,直接fuzz出来的有一个本地拒绝服务漏洞、以及UI服务的一些影响系统可用的bug。比如下面的漏洞,在华为手机测试出来的,最新版本已经修复了adb 命令: service call package 100 即可触发漏洞
Bug信息,如下图5:
Android Fuzz 漏洞挖掘初探_第4张图片

漏洞位置如下图6:
根据bug信息,找到pm包的代码,可以定位到漏洞的真正原因,没有对packageName校验null值造成的本地拒绝服务。
com.android.server.pm.PackageManagerService.clearExternalStorageDataSync

Android Fuzz 漏洞挖掘初探_第5张图片

2.4 扩展总结

这算是第一次真正的自己尝试去挖漏洞,收获还是挺大的,从了解fuzz 基础,到参考别人脚本去实现某些测试,这个过程也遇到了不小的难题。比如在尝试进行文件fuzz的时候,对各种文件格式了解不够详细,在生成畸形文件测试的时候就无从下手。继而,在安卓驱动fuzz部分也是进行了尝试,自己去写了一些脚本,写的过程中发现在构造参数的过程构造不出合适数据,造成fuzz 脚本没有真正发挥作用。这些问题,最终都要解决。
最后,最近一段时间会花大量时间在漏洞挖掘这块,如果有感兴趣的小伙伴也希望能一起多交流。

3 参考链接

文章:
https://blog.csdn.net/omnispace/article/details/54341584
https://blog.csdn.net/u010651541/article/details/54980839
https://www.jb51.net/hack/540592.html
脚本:
https://github.com/Venscor/AndroidSystemServiceFuuzzer
https://github.com/imcczy/SSFuzzing

你可能感兴趣的:(漏洞相关)