Content Provider(内容提供器)主要用于在不同的应用程序之间实现数据共享。它为应用程序存取数据提供统一的外部接口,使不同应用之间得以共享数据。
Android 7.0之后无法直接将一个 File Uri 共享给另一个程序进行,因此产生了FileProvider。它是 ContentProvider 的子类,可以通过创建一个 Content URI 并赋予临时的文件访问权限来代替 File URI 实现文件共享。简单来说就是将自身内部文件暴露给其他应用,并授予临时的文件读写权限。
总的来说,Content Provider 用来实现数据共享的,FileProvider是用来实现文件共享的。如果使用不当则会产生各种危害,下面将一一进行分析。
下图将Content Provider 中的漏洞大致分为三大类,分别是信息泄露、文件读写、目录遍历。
3.1 信息泄露
• SQL注入
漏洞原理不赘述,要注意的是对查询数据做到参数化查询。
• 权限控制不当
该问题可分为两种,一种是组件导出且没有设置任何权限,可以直接查询并返回敏感数据;
另一种是设置了读权限,却暴露了写权限,仍然可以通过数据写转数据读,实现数据读取。
• 有权限保护,但是可被授权
当Provider的android:grantUriPermissions属性为true时,就意味着该Provider是可以被授权访问的,如果目标应用中存在授权漏洞,那么该Provider中的信息就一览无余了。
3.2 文件读写
• Content Provider实现openFile()接口
Content Provider 中通过 openFile() 方法实现文件数据的共享。
其他应用访问目标应用的文件数据时,就会调用到目标应用Content Provider的openFile方法。
例如:
context.getContentResolver().openInputStream(Uri.parse(uri)); //读文件
context.getContentResolver().openOutputStream(Uri.parse(uri),"w"); //写文件
我们可以用以下方式来构造我们要访问的文件的uri。
content://authorities/Absolute_path
如果目标应用的Content Provider可以被其他应用访问,且实现了openFile()方法,那么就可以轻而易举的达成文件读写。再配合目录遍历的漏洞就可以实现任意文件读写啦!
• 导出的FileProvider
此类情况比较少,因为FileProvider默认是不导出的,必须通过授权的方式来访问它。但不乏有一些开发同学为了方便将Fielprovider设置为导出。这样其他应用就可以直接访问该FileProvider所分享的文件。
错误代码如下:
• 目标应用授权过程中的参数可控
FileProvider是通过授权的方式来访问的,那么如果授权过程中的参数可控,就可以让目标应用给任意其他应用授权,从而访问FileProvider所分享的文件。重点关注以下几个地方:
① grantUriPermission接口的参数
② startService和startActivity等接口的Intent
③ setResult中的Intent参数
3.3 目录遍历
目录遍历是任意文件读写的关键。如果没有目录遍历,就只能访问FileProvider内共享的文件,那危害就没有那么大了。
• FileProvider路径配置过于宽泛
FileProvider会在xml中定义要分享的文件路径,各个tag对应的路径如下:
如果xml中添加了root-path这个标签,且该标签的path值为空或者"."或者"/",那么相当于把所有自己可以访问的文件分享了出去。
错误代码如下图所示:
现如今这类问题还是蛮多的,因为该类问题单独存在的话无法利用,所以很多开发同学都不在意这点。但是一但出现文件读写的漏洞,再配合此类问题,危害就很大了。
我们可以用以下方式来构造我们要访问的文件的uri。
content://authorities/root-path/Absolute_path
• FileProvider路径限制失效
路径限制指的是xml中写的要分享的文件夹。那么为何路径限制会失效呢?接着往下看。
FileProvider中有一个非常关键的方法getFileForUri,该方法是将Uri转换成文件路径的。下面是android为我们提供的getFileForUri方法。
可以看到,获取到文件路径的过程可谓煞费苦心,做了充足的检测来防止其他应用访问共享文件夹以外的文件。
但是存在自定义FileProvider的情况,有时候开发同学会覆写getFileForUri方法。如果考虑没有这么周全的话那就漏洞百出了,上面的步骤缺一不可,少一步都是有问题的。
类似的错误代码如下:
我们可以用以下方式来构造我们要访问的文件的uri。
content://authorities/Absolute_path
4.1 CVE-2021-25410
该漏洞是由于三星手机系统的CallBGProvider导出,且权限设置为normal,可被任意三方应用调用。它实现了openFile接口,且存在目录遍历漏洞,导致任意文件读取。
问题代码:
问题在于getLastPathSegment()会自动将uri解码,比如..%2F会解码成../。然后拿到文件路径之后,没有过滤../,也没有对文件路径的标准格式进行限制,导致目录遍历。
4.2 CVE-2021-20722
该漏洞是因为system应用 FactoryCameraFB中存在导出activity,其中setResult方法中的Intent参数可控,可以给任意应用授予Uri的读写权限。同时com.sec.imsservice中存在FileProvider路径设置宽泛的问题,导致目录遍历。两个问题组合利用就可以读写任意系统文件。
问题代码:
授权漏洞:
setResult直接返回外部传进来的Intent,导致授权。
FileProvider路径宽泛:
root-path 为".",导致目录遍历。
References:
https://blog.oversecured.com/Two-weeks-of-securing-Samsung-devices-Part-2