本文发表在NDSS21上,作者是德国亥姆霍兹信息安全中心(CISPA)的Abdallah Dawoud和Sven Bugiel。
自2011年至今,学术界对Android系统的Permission Mapping这一话题的研究从未停止过。但是除了这个话题的开山之作以外,其他工作无一例外使用的都是基于静态分析的技术。本文旨在将近年来日益发展壮大的动态测试工具及其思路,应用到这一领域,以弥补纯静态分析的不足。提出了一个叫Dymamo的动态测试工具,对Android Framework层的api进行Fuzz,从而建立Permission Mapping。基于这一工具得到的结果,作者将其于现有的来自Arcade的最新结果进行比对,从差异中发现各自的不足,并从而帮助其他工作更好的完善各自的工具。
Permission Mapping即权限映射,在本文中是指将Android Framework层提供的系统API以及调用该API时所需要申请的权限建立映射。
Permission Mapping的意义有:
现有的工作基本上都是基于静态分析的,而静态分析尤其固有的缺陷,比如很难处理动态变量的值、IPC等。而目前的Permission Mapping结果几乎完全基于静态分析,这导致结果的不准确性,而对其他依赖于该结果的工作造成影响。因此作者认为有必要用动态测试的方法来重新审视这个结果。
所有已注册的系统服务都能够在ServiceManager类中被找到,作者基于这一事实来提取系统API的入口点。
Binder是安卓系统特有的进程间通信机制,底层原理是使用内核内存贡献来在进程间通信。对于一些比较敏感的底层系统API,安卓系统通过Binder封装后对外提供一些High-Level的API用于调用,在调用时则会进行权限检查。
安卓的权限管理可以分为3类:
本文想要设计一个动态测试工具来为Android Framework层API建立权限映射,主要有以下几个Research Questions:
基于以上的Research Questions,作者设计的工具如下:
它有三个主要组成部分:
对于如何找到系统API的问题(RQ1),作者利用ServiceManager会维护所有注册的系统Service的这一事实,利用Java反射来从ServiceManager中获取所有能够找到的Service的Handle,并将其强转为对应Service的Proxy对象,在这些对象中就能找到这个Service的所有API的方法签名了。
在测试这些API时,作者采用多台设备并行的方式进行,每台设备一次只测试一个API。
对于如何生成输入的问题(RQ2),作者为Java基本类型和Android基本类型预定义了一些输入,其中部分输入由源码静态分析其入参名称得来。而对于复杂类型,作者使用递归的方式完成,通过为其传入基本类型来调用其构造函数从而生成输入。
对于如何衡量覆盖率的问题(RQ3),作者使用了一个叫WALA的工具,来对每个API进行可达性分析,对于每个API可以得到一个有限的方法集合,调用API可以最终到达这些方法。通过Hook这些方法,当其被调用时打印调用栈,如果确实是由该API所触发并且调用者为TS时(用于排除噪声),统计该Trace。最后覆盖率的计算公式为Unique Trace的数量比上集合中的方法数量。
对于如何检测不同类型的权限检测的问题(RQ4),作者预定义了多种测试策略,每种策略旨在发现不同类型的安全检测。工作流程大致如下:
就是循环遍历不同inputs和Strategies,然后遇到安全检查没通过就hook一下尝试绕过。具体的case如下:
对于特定权限检查的情况(图中INTERACT_ACROSS_USERS)会有统一的函数完成(checkPermission函数),通过hook就能知道是否触发了这种检查以及具体的参数类型。
对于inline检查UID的情况,作者通过Hook Binder.getCallingUid函数来不断变更自己的UID,如果发现某一次变更后通过了权限检查,则说明存在inline UID检查。
对于构建反馈通道的问题(RQ5),作者使用了Frida动态Hook框架优点是能够兼容不同的系统,而无需修改安卓源码,能够满足对一些闭源的OEM厂商的测试需求。
最后是如何为Permission Mapping建模的问题(RQ6),作者想要得到下图中List2中的结果作为输出。
作者可以使用RQ4中的方法来得到具体UID值的检查以及具体权限检查的两种情况,但是对于UID是否等于入参的情况,作者通过不断变更入参的方式来检查。
与Arcade的对比结果大致如上图所示