以用户隐衷平安为核心,用责任兑付信赖,OPPO成立子午互联网安全实验室(ZIWU Cyber Security Lab)。实验室以“爱护用户的平安与隐衷,为品牌注入平安基因”为使命,继续关注并发力于业务平安、红蓝反抗、IoT平安、Android平安、数据和隐衷爱护等畛域。

本篇文章源自OPPO子午互联网安全实验室。

1 不平安PendingIntent的通用利用办法

1.1 不平安PendingIntent的特色

至此,咱们曾经解决了本议题的第一个问题,通过钻研表明,Android零碎中应用的PendingIntent大都 能够被三方App获取。

获取形式包含bind SliceProvider、监听告诉、连贯媒体浏览器服务或者bind包容 窗口小部件的AppWidgetsProvider。

于是,引入议题钻研的第二个关键问题:如果这些PendigIntent不平安,如何利用能力造成平安危害?

首先,咱们须要分别什么样的PendingIntent是不平安的。后面形容的公开破绽案例,均为劫持base Intent为空Intent的播送PendingIntent,阐明如下empty base Intent构建的PendingIntent确定存在平安问题。

Android 12之前的开发者文档也对base Intent为隐式Intent的PendingIntent提出了平安正告,但却没 有明确告知到底存在何种危害。而且在AOSP代码和风行App当中,如下的代码模式宽泛存在。这不禁让 咱们考虑, Implicit base Intent构建的PendingIntent是否真正存在问题?唯有找到一种确定的针对这 种PendingIntent的破绽利用办法,能力真正证实平安问题的存在。

1.2 深刻Intent fillIn改写机制

寻找利用办法之前,须要深刻摸索PendingIntent的改写机制,这决定了其余App取得PendingIntent以 后,如何对base Intent进行改写。这个机制由 Intent.fillIn 函数提供:


在上述代码中,this对象指向以后Intent,other为其余Intent。如果以后Intent中的成员变量为空,则可 以被other中相应的成员变量笼罩。比拟非凡的是Intent中的component和selector成员,即便以后Intent中的component和selector为空,也不能被other所改写,除非PendingIntent
设置了FILL_IN_COMPONENT
或者FILL_IN_SELECTOR标记。

1.3 PendingIntent重定向攻打

因而在获取PendingIntent之后,其base Intent的action、category、data、clidpdata、package、flag、extra等成员都是有可能改写的,而component和selector无奈改写,如图所示。特地地,对于base Intent为隐式Intent的这种状况,action曾经被设置了,因而也无奈被改写,攻击者无奈如后面安 卓零碎broadcastAnyWhere破绽那样,通过劫持PendingIntent、在base Intent中从新增加action,隐式关上一个受爱护的组件。

图 Intent成员

这里就来到了问题解决的关键点,因为package能够指定,回想到以前在Intent Bridge破绽中的利用方 法,咱们能够通过设置intent中的flag来奇妙地解决这个问题。Intent提供了无关长期受权的标记:

  • FLAG_GRANT_READ_URI_PERMISSION:Intent携带此标记时,Intent的接收者将取得Intent所携 带data URI以及clipdata URI中的读权限
  • FLAG_GRANT_WRITE_URI_PERMISSION:Intent携带此标记时,Intent的接收者将取得Intent所携 带data URI以及clipdata URI中的写权限

简言之,歹意App对PendingIntent进行了指向歹意App本人的重定向,通过对PendingIntent base Intent的局部批改(批改包名、受权标记和data/clipdata),使其以受益App的权限关上歹意App本身, 这样歹意App在被关上的霎时即取得对受益App公有数据的读写权限。具体的利用办法如图所示:

图 PendingIntent重定向攻打

步骤如下:
1、受益App通过getActivity构建PendingIntent,在告诉、SliceProvider、窗口小部件中应用,假设其base Intent为隐式Intent;

2、攻打App 通过后面探讨的各种渠道获取受益App的PendingIntent;

3、攻打App批改PendingIntent中的base Intent,因为是隐式Intent,因而action、component和selector都不能批改。但能够做如下批改:

  • 批改data或者clidpdata,使其URI指向受益App的公有ContentProvider;
  • 批改package,指向攻打App;
  • 增加FLAG_GRANT_READ_URI_PERMISSION和FLAG_GRANT_WRITE_URI_PERMISSION 标记。

同时攻打App申明一个Activity反对隐式启动,其Intent-filter与base Intent中的action统一。

4、攻打App调用PendingIntent.send;

5、因为这个PendingIntent代表了受益App的身份和权限,因而将以受益App的名义发送批改后的base Intent,关上攻打App的Activity;

6、在攻打App Activity被关上的霎时,即被受权拜访base Intent中携带的URI,也就取得了对受益App公有ContentProvider的读写权限。

下面受益App的公有ContentProvider,须要携带属性 grantUriPermission=true ,不限于受益App自 己的ContentProvider,也包含受益App有权限拜访的ContentProvider。手机上一个常⻅的具备 grantUriPermission=true 属性的ContentProvider就是代表通讯录的Contacts Provider,只有受 害App具备 READ_CONTACTS 权限,呈现这样一个PendingIntent破绽后将导致通讯录泄露。

这样,咱们通过上述6个步骤,就能够胜利实现对隐式Intent构建PendingIntent的破绽利用,读写受益App的公有数据,这也就解决了本钻研提出的第二个关键问题:通过隐式Intent构建的PendingIntent可蒙受通用的重定向提权攻打,也是不平安的。

因为这里应用了grantUri的技巧,因而并不适用于broadcast PendingIntent,因为播送接收器是不能够 被grantUri的。另外,从Android 5.0当前,Service不能隐式启动,因而也很难看到base Intent为隐式Intent的service PendingIntent。所以,这里的PendingIntent重定向攻打次要实用于Activity PendingIntent。

2 安卓零碎中的实在案例

令人诧异的是,在Android 12之前的AOSP代码以及风行App中,隐式Intent构建的ActivityPendingIntent宽泛存在,以下是咱们发现的典型案例,可能导致手机的敏感信息泄露,甚至以受益app的权限执行任意代码。这些破绽案例均已被厂商所修复。

图 不平安PendingIntent典型案例

2.1 CVE-2020-0188

不平安的PendingIntent存在于AOSP SettingsSliceProvider中,
一旦SettingsSliceProvider被blind,
在返回的Slice中将携带一个不做任何操作的noOpIntentPendingIntent:

攻打App通过bind SettingsSliceProvider获取PendingIntent,批改base Intent并以Settings的权限发送,期待本人的Activity被关上,就能够实现Settings某些公有Content Provider的读写。如图所示:

图 CVE-202-0188 POC

2.2 CVE-2020-0389

不平安的PendingIntent存在于
AOSP SystemUI RecordingService当中,为用户录屏保留胜利后发送的告诉所应用。


歹意App能够实现一个NotificiationListener
Service,批改base Intent,将其clipdata指向ContactsProvider :

因为SystemUI具备READ_CONTACTS权限,因而歹意App 被关上时,即可胜利读取通讯录。

2.3 A-166126300

不平安的PendingIntent存在AOSP BluetoothMediaBrowserService中

歹意App能够连贯BluetoothMediaBrowserService ,通过MediaBrowserCompat.ConnectionCallback 获取PendingIntent。
因为BluetoothMediaBrowserService存在于具备通讯录权限Bluetooth利用中,因而通过PendingIntent重定向攻打可读取通讯录

2.4 某风行App

某具备通讯录权限的风行App实现了窗口小部件,用户点击窗口小部件的按钮实现跳转,但这个跳转是通过隐式Intent构建PendingIntent实现的。

对窗口小部件所属的AppWidgetProvider进行bind,通过反射逐次获取 RemoteViews->mActions->mResponse->mPendingIntent ,最终能够拿到上述不平安的PendingIntent,进而如法炮制,读取通讯录。

2.5 CVE-2020-0294

这些不平安的PendingIntent存在安卓零碎服务中,对于某些bind服务,零碎提供了PendingIntent,跳转到服务的治理界面。

这些PendingIntent能够间接通过零碎APIActivityManager.getRunningServiceControlPanel 取得,前面进行PendingIntent重定向,读取Settings中的爱护ContentProvider。

2.6 危害

上述多个案例均可造成通讯录这类集体敏感信息泄露,但实际上,因为PendingIntent重定向攻打还具备写数据的能力,因而可能造成更大的危害。

例如,很多App都具备热更新性能,个别将dex/jar/apk/so等文件放在本人的公有目录中,如果这些公有目录能够被 grantUriPermission=true 的ContentProvider所援用,就能够利用PendingIntent重定向攻打去改写热更新文件,将攻击者本人的代码注入到其中,实现以受益App的权限执行任意代码。

对于CVE-2020-0188和CVE-2020-0294这类源于零碎uid的PendingIntent,因为在UriGrantsManagerService当中进行了限度,因而在原生零碎中的危害很无限,只能读取特定的几个Content Provider。

然而因为Android零碎的定制化,上述限度可能在OEM厂商中被突破,造成更大的危害。

Google对安卓零碎中这类破绽的修复,起初是将base Intent设置为显式Intent,指定明确的组件。起初均应用FLAG_IMMUTABLE修复,当应用这个flag时,PendingIntent的base Intent将无奈通过Intent.fillIn 函数改写,例如

3 自动化剖析

基于对不平安PendingIntent特色的把握,咱们编写了一个自动化扫描工具PendingIntentScan,该工具基于Soot[4]这一Java动态剖析框架对apk进行数据流动态剖析,其体系结构如图所示。

图 PendingIntentScan原理

首先,应用Soot将apk的字节码转换为Jimple模式的IR,而后搜查一系列生成PendingIntent的API,并挑选出没有应用FLAG_IMMUTABLE的:

而后,通过Soot提供的ForwardFlowAnalysis对PendingIntent的Intent参数进行查看,查看是否调用下列函数。如果都没有应用,则认为PendingIntent是不平安的:

这个工具目前开源在
https://github.com/h0rd7/Pend...,能够迅速发现apk中存在的不平安PendingIntent,成果如下。

4 安卓12平安变更

针对咱们的研究成果,Google 安卓平安团队对AOSP代码进行了全面排查,简直修复了所有的不平安PendingIntent。大部分的修复应用了PendingIntent.FLAG_IMMUTABLE,小局部的修复将base Intent设置为显式Intent。

而在Android 12大版本中,安卓系统对PendingIntent的行为进行了重大平安变更,引入了一个新的flag:PendingIntent.FLAG_MUTABLE,示意base Intent能够改写。这与原有的FLAG_IMMUTABLE独特形容PendingIntent 的可变性。

对于Target S+的App,Android零碎要求开发者必须明确指定PendingIntent的可变性,FLAG_IMMUTABLE和FLAG_MUTABLE必须应用其一,否则零碎会抛出异样。这就要求开发者对本人PendingIntent的应用有清晰的了解,晓得PendingIntent是否会在未来被改写。

Google也对开发者提出了具体的平安编码倡议:

  • 尽可能应用FLAG_IMMUTABLE来生成不可改写的PendingIntent;
  • 如果应用FLAG_MUTABLE来生成可改写的PendingIntent,base Intent肯定要应用显式Intent,明确指定Intent的组件。

同时AndroidStuido IDE中也引入了一个新的lint查看插件PendingIntentMutableFlagDetector,用于查看PendingIntent是否应用了FLAG_IMMUTABLE。

5 论断

本议题解决了PendingIntent的获取问题,明确了不平安PendingIntent的特色,提出了无关不平安PendingIntent的重定向攻打利用办法,从而揭示了安卓零碎和风行app无关PendingIntent应用的一种通用平安⻛险。Google针对议题形容的破绽均已进行了修复,并在Android 12中引入了缓解此问题的重大平安变更,对开发者提出了具体的平安编码倡议。

开发者在应用FLAG_IMMUTABLE构建PendingIntent时应分外小心,除了要应用显式Intent以外,还要保障 base Intent其余没有填充的字段不会造成平安影响。例如上面存在问题的代码源于一个实在app的案例。这个PendingIntent 曾经设置了显式Intent,在告诉中应用,用于启动外部不导出的MainActivity

在MainActivity中,
能够对EXTRA_REDIRECT_INTENT 进行解决,最初调用startActivity:

这样,劫持PendingIntent依然能够设置EXTRA_REDIRECT_INTENT,通过startActivity去关上利用的任意爱护组件。

因而,每一个没有应用FLAG_IMMUTABLE的PendingIntent均应该认真审查,这是咱们对开发者的最初平安忠告。

6、参考

[1]http://retme.net/index.php/20...

[2]https://www.slideshare.net/Ca...

[3]https://mp.weixin.qq.com/s/SA...

[4] http://soot-oss.github.io/soot/

[5]https://developer.android.com...

作者简介

heeeeen 平安架构师

毕业于北京航空航天大学,现工作于OPPO子午互联网安全实验室,善于Android框架与APP破绽开掘,屡次取得Google平安致谢

获取更多精彩内容,请扫码关注[OPPO数智技术]公众号