PendingIntent劫持问题分析

admin 2022年10月7日23:26:33评论203 views字数 3650阅读12分10秒阅读模式

概述:

笔者对PendingIntent劫持问题进行深入分析,从系统源码出发,了解PendingIntent会被劫持的原因,并给出了可行的防护建议。

近期遇到一个PendingIntent劫持的问题,一个三方应用可以拦截系统应用发送的通知,并从通知中劫持PendingIntent,实现发送自己的恶意调用的目的。本篇就借此讨论PendingIntent劫持是什么、为什么以及怎么做,来记录并分享一下如何应对该问题。


01
什么是PendingIntent

1.1 理论

PendingIntent是一个Android原生提供的调用机制,可以将我们想要发送的Intent延迟发送,甚至是在当前进程已经退出情况下仍然具备当前进程的权限,实现对目标的调用。这种保留权限的滞后发送,为开发带来了很多便利,但同时也引入了一定的风险。下面是Android官网对于PendingIntent的一段描述:

PendingIntent劫持问题分析

大意是说,当我们将PendingIntent给了另一个应用时,相当于把我们的权限给了它,让它完成指定操作。需要注意的是,至少在大多数情况下,我们应该将目标组件信息显式填写,来保证接受方是我们想要的,并防止PendingIntent被滥用。由此可知,PendingIntent的劫持往往是没有显式指定组件信息导致的。


1.2 实践

仅仅有理论显然不够直观,我们写个简单的Demo测试一下。最近遇到了一个通过拦截通知实现提权调用的漏洞,我们写两个应用来测试。一个系统应用负责发送通知;另一个是恶意应用,只有普通应用权限,但是具有通知使用权,对系统发出的通知进行拦截。


1.2.1 系统应用

系统应用构造比较简单,首先是给予应用系统权限:

PendingIntent劫持问题分析


然后我们构造一块可以发送通知的代码:

PendingIntent劫持问题分析

需要注意的是,这个通知我们要违背Android的建议,对于PendingIntent封装的Intent对象,不显式设置任何内容,直接传入一个空Intent对象。


1.2.2 恶意应用

恶意应用只需要配置一个继承NotificationListenerService的服务,在该服务中实现相关回调接口用于管理通知。

NotificationListenerService服务是Android原生提供的,一个允许三方对所有通知进行管理的回调接口。

下面是该应用对于服务的配置信息:

PendingIntent劫持问题分析


然后是重写关键的回调函数,我们选择实现onNotificationRemoved函数,即在通知被移除时触发响应:

PendingIntent劫持问题分析


我们在收到通知被移除的回调后,直接从通知中读取PendingIntent,然后发送我们自己构造的Intent。

前面有提及恶意应用需要通知使用权,并不需要像多数权限一样走申请路线,而是直接在系统的设置中配置。对于本身就为用户提供通知管理功能的应用来说,完全可以主动跳转到设置界面,请用户点击按钮开通,代码如下:

PendingIntent劫持问题分析

以上就完成了Demo的编写实践,下面我们看下效果。


1.3 效果

将两个应用都安装在手机上,首先启动恶意应用,并授予通知使用权限:

PendingIntent劫持问题分析


启动系统应用,并发送通知:

PendingIntent劫持问题分析


然后移除通知:

PendingIntent劫持问题分析


最终效果如下:

PendingIntent劫持问题分析PendingIntent劫持问题分析

由此看出,效果是符合预期的。我们现在已经是知其然,下一步自然是要知其所以然。


02
PendingIntent背后的原理

要分析背后的原理是要阅读Android的系统源码的,本节我们以Android 10的源码为例,进行简要分析。再者,Android有四大组件,PendingIntent对每种类型都有相关调用接口,我们没有必要一一分析,以上面实践的Activity为例分析即可。


2.1 确定目标

从前面的过程可以看到,系统应用是有设置自己的Intent的,为何PendingIntent被拦截后去发送恶意应用的Intent了,这里我们聚焦在两个点。

  • Intent存储:系统应用开始设置的Intent去哪了?

  • Intent篡改:恶意应用新增的Intent为何会产生影响?


2.2 Intent存储

我们从案例的getActivity开始分析,其调用链路如下:

PendingIntent劫持问题分析


程序通过AMS的binder发起调用,将Intent数据在最终PendingIntentRecord.Key类型中进行解析,并将数据存储在系统服务进程中,然后逐步封装,返回出来的PendingIntent是持有了对应Binder的指针,本身是不包含Intent数据的。


其中最关键的PendingIntentRecord.Key类的构造函数如下:

PendingIntent劫持问题分析

该函数记录了初始Intent的所有数据,在后面对Intent进行篡改时也是以此为基础的。其中对我们后续分析比较重要的:一个是type,是PendingIntent创建时,根据调用接口指定,用于描述Intent是用于调用Activity还是Broadcast等其他类型;再一个是requestIntent,记录Intent数组的最后一个,我们调用的接口只有一个Intent,就是被记录再这里;最后一个是allIntents,负责记录完整的Intent数组。

现在我们知道,系统应用开始设置的Intent对象被被存储在了系统服务进程中,PendingIntent可以通过内部封装的binder对象找到该Intent。


2.3 Intent篡改

PendingIntent将Intent发出,一般都是走的send方法,我们还是像之前一样,从我们使用的接口开始,画出调用链路:

PendingIntent劫持问题分析PendingIntent劫持问题分析


这里从ActivityTaskManagerService.LocalService的startActivityInPackage方法暂不分析了,因为后面进入了Activity的启动流程。在本流程中,我们需要关注sendInner和fillIn两个函数。其中sendInner负责最终Intent发送前的数据处理和调用分发;而fillIn则负责对原始的Intent进行篡改。

我们首先看sendInner函数:

PendingIntent劫持问题分析


可以看到函数中会先取出之前在系统服务进程中存储的Intent对象,若PendingIntent创建时,未指定FLAG_IMMUTABLE,则对其内含Intent执行fillIn方法,进行Intent篡改。后面则是使用篡改后的Intent去发出Activity调用请求,其中涉及到的key.type、key.requestIntent、key.allIntents,都在上一小节Intent存储中有提到。让我们看看最核心的函数fillIn,了解一下Intent的篡改策略:

PendingIntent劫持问题分析


该函数中涉及的可篡改项较多,主要有三种类型,我们分别选出一个代表。如action数据,只要原Intent未设置,或者已经设置了相关flag,就可以篡改;如component,只有原Intent设置了允许篡改的flag才可以篡改;如extras,无论原Intent是否存在设置,都可以新增内容,但是不能修改和删除原有内容。具体情况整理如下:

PendingIntent劫持问题分析


对于组件信息只要我们不主动使用FILL_IN相关的flag,恶意应用是不能篡改的,即在主动设置了组件信息的情况下,能保证Intent的接收者一定是我们的目标应用或组件。再者如action、data和extras经常在接受方具有影响二次分发或程序走向的作用,如果接受方有使用,一定要在创建PendingIntent时主动占位,避免被他人利用。

回答一下本小节的目标问题,系统应用开始设置的Intent内容会被篡改,是因为系统主动调用了fillIn函数,来使用新Intent对原Intent进行补充。


03
如何使用PendingIntent

根据前面的流程,我们已经了解到了PendingIntent劫持是什么,以及为什么会发生。由此我们可以对于使用PendingIntent,提出以下开发建议:

  • 如非必须允许PendingIntent接收者篡改信息,创建PendingIntent时一定要增加FLAG_IMMUTABLE为flag信息;

  • 使用PendingIntent时,对于封装的Intent必须明确、显式的指定组件信息;

  • 建议在接受方有使用如data、action或extras内容进行流程控制时,主动使用默认内容占位;

  • 非必要不建议设置FILL_IN相关flag。


END


参考文献:

[1] Android官方文档:

https://developer.android.com/reference/android/app/PendingIntent

[2] Android通知使用权(NotificationListenerService)的使用:

https://www.jb51.net/article/116920.htm


往期推荐:





vivo鲁京辉:数据安全与隐私保护是消费者的基本权利,是企业的“铁律”


vivo“千镜杯”作品提交通道已开启!大赛持续报名中,20万元奖金等你来战!


浅析GDPR中的个人数据访问权


2022vivo“千镜杯”正式开赛,为守护用户安全而战!


PendingIntent劫持问题分析
关注我们,了解更多安全内容

原文始发于微信公众号(vivo千镜):PendingIntent劫持问题分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月7日23:26:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PendingIntent劫持问题分析http://cn-sec.com/archives/1333239.html

发表评论

匿名网友 填写信息