IntentFuzzer阅读笔记

论文IntentFuzzer: Detecting Capability Leaks of Android Applications阅读笔记

IntentFuzzer: Detecting Capability Leaks of Android Applications

目标是检测Android上的权限泄露问题,比如组件C具有权限P,另一个应用A可能通过构造特定的intent来调用组件C,从而达到使用权限P的目标。
一个典型的场景就是C有权限P且exported=true,但是在响应intent的时候没有鉴别是不是外来的,导致泄露的权限P。

文章使用了若干启发式搜索方法来构造intent,同时修改system代码检测部分API并生成反馈,形成了一种基于的反馈引导的fuzz方法。

1 Intro

回顾了之前的方法,介绍了Android的权限泄露问题(Capibility Leak):
Capability leak is such a vulnerability that an application exposes some permissions, by which other applications without these permissions can access protected resource.

2 Background

2.1 Permission Model

Google的设计规则:App默认情况下不能获取危险的权限,手机用户需要在应用安装的时候授予权限。

2.2 Inter Component Communication

ICC就是指intent机制嘛。

还有就是androidmanifest.xml中可以设置activity、service为exported=false来使得这个activity拒绝响应app之外的intent,未设置时默认是true。

这篇文章主要关注这些exported=true,可以响应外来intent的组件。

2.3 Capability Leaks

Capability Leak, 也称 Permission Re-Delegation

一个例子:正常应用A有权限P,A有一个对外暴露(exported=true)的组件C,而且C没有做好intent的安全检查,那么恶意应用M可能在无授权的情况下向C发送构造的intent从而使用P权限。

其实这里只要C简单的判断一下intent的发送者是不是App自身的组件就可以避免权限泄露了,但是广大的开发者不以为意。

3 System Design

本研究动态地生成合适的intent并发送到目标组件,然后检查是否有权限泄露。
对于intent的生成,会从manifest中提取信息构建基本框架,然后通过修改system的API函数来进行反馈,修正intent的具体字段。

3.1 Fuzz Strategy

进行了一系列的讨论,把研究目标缩小到Started Service、Broadcast Receiver和explicit intent:

  1. 作者认为Activity虽然也有提权攻击和页面欺诈钓鱼的情况,但是因为activity一般带界面且直接与用户交互,遇到问题时用户自己可以关掉activity来终止代码的运行,所以并不是非常严重。(存疑)
  2. 作者把service分为started service和bound service两种,其中bound service不接受外来intent,所以不考虑。
  3. 作者把intent分为explicit intent和implicit intent两种(显式和隐式),会使用显式intent来fuzz。
  4. 作者把capability leak分为两种,一种是组件有意对外exported但是没有合理地检查intent的发送方权限;另一种是组件疏忽对外暴露。这两种情况下,组件都会接收显式intent。

3.2 Permission Leak Detection

前面说到未授权M通过带授权A的组件C执行了权限P,如何确定P权限被执行了?

IntentFuzzer会在设备上植入一个不申请任何权限的Agent,然后修改Android系统代码,实时检查权限P是否被申请。(权限在app安装的时候授予,但是在运行时会即时进行permission check)

3.3 Intent Construction

对于前面提到的Started Services,其入口函数onStart-Command(),对于Broadcast Receiver,其入口函数是onReceive()。

对于intent涉及到的相关结构,其构造方法如下:

  1. Action:
    对于那些有意exported来接收外来显式intent的组件,它们会在manifest中通过intent-filter来定义可以响应的action类型,枚举这些预定的action来测试对应组件即可;
    对于那些疏忽exported意外地可以接受外来显式intent的组件,它们本身并不会在manifest中定义intent-filter,因为它们本来应该只响应app内部intent的。它们可能会检查action的值,然后决定运行后续的代码,如下面的代码示例。对于这些action的值,Google本身预定义并推荐使用了一系列的值,当然app本身可以定义自己的值,不过它们往往会是packagePath.ActioType的模式,所以本研究会从dex的变量池中选出符合这种模式的字符串加上Google预定义的值,作为可能的action键值。

    1
    2
    3
    4
    5
    6
    7
    public void onReceive(Context context, Intent intent) {
    SmsManager smsManager = SmsManager.getDefault();
    String action = "com.example.test.action.SEND_SMS";
    if (action.equals(intent.getAction())) {
    smsManager.sendTextMessage("10086", null, "test",null, null);
    }
    }
  2. Data:
    可以从intent-filter关于data属性的定义推测data的类型,具体可以从scheme://host:port/path这个模式来推测。研究中预先准备了一些data,如果有合适的intent-filter,就会使用对应的data来进行测试。

  3. Extras:
    Extras就是一系列包含Java原语的键值对,并不在intent-filter中定义,但是会在目标组件的代码中反应出来。
    如下面示例代码,可以通过提取getStringExtra(‘name’)这样的API来判断目标组件会从intent中提取哪些extra。
    具体来说,IntentFuzzer又一次修改的系统源码中关于getXXXExtra()这里函数,通过log返回它的调用情况。
    在一次测试中,如果目标组件尝试从intent中提取类型为String键名为sms的extra数据但是没有成功,那么log中会包含相关的feedback,告诉intentfuzzer在下一次测试中,为测试intent加上这样的extra数据。
    这样一来会测试到更为深层的代码逻辑。

    1
    2
    3
    4
    5
    6
    7
    8
    public int onStartCommand(Intent intent, int flags, int startId) {
    SmsManager smsManager = SmsManager.getDefault();
    String smsContent = intent.getStringExtra("sms");
    if (smsContent != null && smsContent != "") {
    smsManager.sendTextMessage("10086", null, smsContent, null, null);
    }
    ...
    }
  4. Category:
    显式intent一般不考虑category,相关匹配机制参考:https://blog.csdn.net/iispring/article/details/48481793

  5. Flags:
    flags会指示系统如何运行目标组件,不需要考虑。

3.4 General Fuzzing Steps

对于exported组件:

  1. 枚举每个intent-filter中的Action,循环2-5
  2. 如果intent-filter有Data,才构建Data数组
  3. 初始化Extra键值对集合为空集E
  4. 构造并发送一个包含Action,Data,E-extra的intent
  5. 等待几秒,看看是否触发了permissionCheck和getXXXExtra的API。如果获取了一个新的Extra数据,向E中添加这样的键值对,回到4,否则退出当前循环。

对于没有intent-filter的组件,也即那些可能因为没有设置而被默认暴露的组件:

  1. 构建隐含Action(即常量池+预设值),对于每一个隐含Action,执行2-4
  2. 初始化Extra为空集E
  3. 构造并发送一个包含Action,E-extra的intent
  4. 等待几秒,看看是否触发了permissionCheck和getXXXExtra的API。如果获取了一个新的Extra数据,向E中添加这样的键值对,回到3,否则退出当前循环。

4 Implementation

4.1 Architecture

在drozer的框架上构建的,并且编写的drozer module来实现IntentFuzzer console。

4.2 System Modification

拦截checkPermission(String permision, int pid, int uid)函数,向logcat中输出permission和uid就知道当前是那个应用在使用什么权限。

拦截getXXXExtra(String name, ...)这一类函数,就指导当前应用的组件在尝试从intent中获取那些extra数据。

5 Evaluation

5.1 Experiment Design

2183 Google Play Apps, SAMSUNG Galaxy Nexus, Android 4.2.2

closed-source ROMs in Redmi Android4.2.2 & Lenovo K860i 4.2.1

image-20220303134511786

image-20220303134523059

5.2 Case Study

有一些实际的case分析,增加了文章的可信度。

Welcome to my other publishing channels