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

网友投稿 469 2022-10-03


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,隐式打开一个受保护的组件。

这里就来到了问题解决的关键点,由于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中的写权限

步骤如下:

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 标志。

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可以实现一个NotificiationListenerService,修改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​

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

​2.5 CVE-2020-0294​

​这些不安全的PendingIntent存在安卓系统服务中,对于某些bind服务,系统提供了PendingIntent,跳转到服务的管理界面。

这些PendingIntent可以直接通过系统API ActivityManager.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 自动化分析​

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

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

这个工具目前开源在安卓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]安全架构师​​

​毕业于北京航空航天大学,现工作于OPPO子午互联网安全实验室,擅长Android框架与APP漏洞挖掘,多次获得Google安全致谢


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:#yyds干货盘点#安全CT之环境搭建--靶机搭建(owasp)
下一篇:基于Java实现空间滤波完整代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~