[CVE-2021-25413] [Samsung] [Contacts] SetProfilePhotoActivity导出存在任意私有组件启动漏洞可获取ContentProvider数据

Date
Version
Description
Author

2022.11.20

1.0

完整的漏洞分析与利用

wnagzihxa1n

0x00 漏洞概述

组件SetProfilePhotoActivity导出,通过合理构造Intent参数可以调用方法startActivityForResult(),方法startActivityForResult()使用的Intent参数是由内部构造的,其会将外部可控的URI赋值到启动Intent内部的ClipData字段,并且标志位设置为读写权限,漏洞点在于该构造出来的Intent是隐式Intent,未指定具体的接收组件,所以只需要制定一个高优先级满足ACTION配置的Activity,即可实现访问ContentProvider数据

0x01 触发条件

上线日期
应用名
包名
版本号
MD5
下载链接

Contacts

com.samsung.android.app.contacts

12.1.10.30

60579c925977ca29b889d32085a0c350

0x02 PoC

0x03 前置知识

0x04 Root Cause Analysis

组件com.samsung.android.contacts.editor.SetProfilePhotoActivity导出

<activity 
        android:configChanges="keyboardHidden|orientation|screenSize" 
        android:hardwareAccelerated="false" 
        android:icon="@mipmap/ic_launcher_contacts" 
        android:label="@string/share_my_profile" 
        android:name="com.samsung.android.contacts.editor.SetProfilePhotoActivity" 
        android:taskAffinity="" 
        android:theme="@style/BackgroundOnlyTheme">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <data android:mimeType="image/*"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
    <intent-filter>
        <action android:name="com.samsung.contacts.action.SET_AS_PROFILE_PICTURE"/>
        <data android:mimeType="image/*"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

SetProfilePhotoActivityonCreate()方法里,[1]调用方法F8()处理传入Intent的字段,[2]调用方法H8()进入异步任务

方法F8()也有一个判断,简单构造即可绕过,[1]调用方法E8()

方法E8()取出传入Intent的两个字段"temp_photo_uri""cropped_photo_uri"保存到__intent_tmp_photo_uri____intent_cropped_photo_uri__

方法H8()先在[1]调用方法B8()进行判断,我们不能让其进入,同样 可以构造参数使其不进入,然后[2]调用异步任务进行处理

异步任务SetProfilePhotoActivity.a有两个具体实现的方法doInBackground()onPostExecute()

doInBackground()的逻辑不影响本漏洞的分析,但是它有一个小知识点会影响人工分析

方法a()调用方法savePhotoFromUriToUri()

[1]获取传入Intent的ClipData,如果不为空则调用[2][3],反之如果为空,则会进入[5]关闭当前Activity,[4]可以通过构造传入Intent来绕过

那此处就有一个问题,一个Activity调用了异步任务,在异步任务的生命周期里,调用者Activity被结束(比如调用方法finish()),异步任务会继续执行吗?

答案是:会继续执行下去

在方法onPostExecute()里,[1]调用方法c()

此处即是漏洞关键点,[1]构造一个Intent,其中setProfilePhotoActivity.__intent_tmp_photo_uri__外部可控,[2][3][4]对Intent的类型字段进行配置,用于筛选能处理这些数据类型的Activity,[5]调用方法AbstractPhotoViewUtils.c()[6]调用方法AbstractPhotoViewUtils.b()对Intent添加字段,其中[5]会添加一个外部可控的字段,[7]是一个简单判断,[8]调用方法startActivityForResult()打开构造好的Intent

接下来依次分析,首先是方法c(),可以看到其中"output"字段和剪贴板数据是外部可控的,[2]调用方法setFlags()设置标志位,3表示Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,描述接收该Intent可以获取指定URI的读写权限,[3]添加ClipData数据,[4]补充一些其它字段

根据AOSP开源代码注释

  • https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/content/Intent.java#6602

如果同时设置了Intent的URI和ClipData,那么会同时给接收者赋予标志位所描述的权限

方法b()添加的数据不影响漏洞

由于SetProfilePhotoActivity继承ContactsActivity,所以调用方法startActivityForResult()的时候会调用回父类的startActivityForResult()

从以上Intent构造过程来看,这个Intent并没有指定具体的接收组件,也就是说它是一个隐式Intent,只要满足条件的Activity都能够接收到,加上它的标志位是读写,所以定制一个高优先级且满足ACTION设置的Activity,就可以拦截到这个Intent并拥有其传递出来的权限

逻辑调用图

0x05 调试与利用

关于异步任务与Activity生命周期的问题可以写个应用验证,在方法doInBackground()里关闭Activity,观察异步任务是否会继续执行方法onPostExecute()

从日志输出去我们可以确认,当Activity被关闭之后,后续的方法onPostExecute()依旧会正常执行下去

Oversecured实验室的PoC如下

作为startActivityForResult()的接收者,获取剪贴板数据进行读取,漏洞分析的时候有解释,剪贴板包含的URI也会被授予标志位所描述的权限

Manifest里要将PickerActivity配置成高优先级,可以优先响应到Intent

0x06 漏洞研究

0x07 References

《Two weeks of securing Samsung devices: Part 2》

  • https://blog.oversecured.com/Two-weeks-of-securing-Samsung-devices-Part-2/

附录:调试过程记录

Last updated