0x00 ContentProvider安全简介
1、漏洞场景
ContentProvider组件是Android应用的重要组件之一,管理对数据的访问,主要用于不同的应用程序之间实现数据共享的功能。Content Provider的数据源不止包括SQLite数据库,还可以是文件数据。
当导出的provider组件的权限声明不当时或者接口方法实现不当, 则可能产生任意数据访问、SQL注入、目录遍历等风险。
2、漏洞分类
- 信息泄露
- 目录遍历
- SQL注入
0x01 信息泄露
1、漏洞原理
-
content uri是一个标志provider中的数据的URI。content uri中包含了整个provider的以符号表示的名字(authority)和指向一个表的名字(路径)。
当调用一个客户端的方法来操作一个provider的表,指向表的content uri是参数之一。
content://:作为 content Uri的特殊标识(必须);
权(authority):用于唯一标识这个Content Provider,外部访问者可以根据这个标识找到它;在AndroidManifest中也配置的有;
路径(path): 所需要访问数据的路径,根据业务而定。
如果对Content Provider的权限没有做好控制, 比如定义了私有权限,但是却根本没有定义私有权限的级别;或者定义的权限级别不够, 就有可能导致恶意的程序通过这种方式读取APP的敏感数据。
2、检测方法
查看 AndroidManifest中provider声明的保护权限,而不是只看Provider组件使用的私有权限。
3、防护
- minSdkVersion不低于9
- 不向外部app提供数据的私有content provider显示设置exported=”false”,避免组件暴露(编译api小于17时更应注意此点)
- 内部app通过content provid交换数据时,设置protectionLevel=”signature”验证签名
- 公开的content provider确保不存储敏感数据
0x02 目录遍历
1、漏洞原理
对外暴露的Content Provider组件实现了openFile()
接口,没有对所访问的目标文件Uri进行有效判断,如没有过滤限制如"../"
。
2、检测方法
- Content Provider组件暴露(exported)
- 实现
openFile()
接口,没有对URI进行过滤
3、相关设置
- ContentProvider.openFile(Uri uri, String mode)
4、漏洞危害
可造成任意可读文件的访问,导致数据泄漏 。
5、修复方案
- 将不必要导出的Content Provider组件设置为不导出(android:exported=“false”)
- 移除没有必要的openFile()接口
- 对访问的目标文件的路径进行有效判断
0x03 SQL注入
1、漏洞原理
暴露(exported)的Provider组件,如果在query()
中使用拼接字符串组成SQL语句的形式去查询数据库,未采用参数化查询的方式,容易发生SQL注入攻击。
2、相关知识
-
query(Uri uri, String[ ] projection, String selection, String[ ] selectionArgs, String sortOrder)
返回Cursor或null。
- insert(),delete(),update()方法
3、检测方法
(1)先检索到ContentProvider组件的子类,判断Provider是否对外暴露
(2)再查看子类是否调用query方法。如果调用,找到projection
、selection
参数对应的寄存器名称v1,再判断v1的赋值来源是否为拼接字符串。
4、漏洞危害
数据库信息泄露。
5、修复方案
- 不必要导出的Provider组件,建议显示设置组件的
“android:exported”
属性为false
; - 使用
selectionArgs
进行参数化查询。
0x04 测试方法
1、查找导出的contentprovider组件
反编译查看清单文件,定位contentprovider是否导出,是否配置权限,确定authority
drozer:
run app.provider.info -a cn.etouch.ecalendar
2、反编译查找path
,关键字addURI
、hook api
3、确定authority和path后根据业务编写POC
adb shell:
adb shell content query --uri <URI> [--user <USER_ID>] [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]
content query --uri content://settings/secure --projection name:value --where "name='new_setting'" --sort "name ASC"
adb shell content insert --uri content://settings/secure --bind name:s:new_setting --bind value:s:new_value
adb shell content update --uri content://settings/secure --bind value:s:newer_value --where "name='new_setting'"
adb shell content delete --uri content://settings/secure --where "name='new_setting'"
<!--content query -–uri content://com.yulong.android.ntfcationmanager.provider/ntfpkgperm -->
drozer:
run app.provider.query content://telephony/carriers/preferapn --vertical
0x05 安全建议
minSdkVersion
不低于9
- 不向外部app提供的数据的私有content provider,设置
exported=“false”
避免组件暴露 - 使用参数化查询避免sql注入
- 内部app通过contentprovider交换数据应设置
protectionLevel=“signature”
验证签名 - 公开的contentprovider确保不存储敏感数据
- 使用
openfile()
前应url.decode()
- 提供
asset
文件时注意权限保护
0x06 参考
https://tea9.xyz/post/962818054.html
https://www.freebuf.com/articles/terminal/105857.html