高防服务器

PendingIntent重定向:一种针对安卓系统和流行App的通用提权方法——BlackHat EU 2021议题详解 (下)

以用户隐私安全为中心,用责任兑付信任,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数智技术]公众号

[温馨提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。]

[图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]