[CVE-2021-25413] [Samsung] [Contacts] SetProfilePhotoActivity导出存在任意私有组件启动漏洞可获取ContentProvider数据
2022.11.20
1.0
完整的漏洞分析与利用
wnagzihxa1n
0x00 漏洞概述
组件SetProfilePhotoActivity导出,通过合理构造Intent参数可以调用方法startActivityForResult(),方法startActivityForResult()使用的Intent参数是由内部构造的,其会将外部可控的URI赋值到启动Intent内部的ClipData字段,并且标志位设置为读写权限,漏洞点在于该构造出来的Intent是隐式Intent,未指定具体的接收组件,所以只需要制定一个高优先级满足ACTION配置的Activity,即可实现访问ContentProvider数据
0x01 触发条件
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>在SetProfilePhotoActivity的onCreate()方法里,[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