6

Android安全开发之Provider组件安全 | WooYun知识库

 6 years ago
source link:
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Android安全开发之Provider组件安全

作者:[email protected]

0x00 Content Provider组件简介


Content Provider组件是Android应用的重要组件之一,管理对数据的访问,主要用于不同的应用程序之间实现数据共享的功能。Content Provider的数据源不止包括SQLite数据库,还可以是文件数据。通过将数据储存层和应用层分离,Content Provider为各种数据源提供了一个通用的接口。

创建一个自己的Content Provider需要继承自ContentProvider抽象类,需要重写其中的onCreate()query()insert()update()delete()getType()六个抽象方法,这些方法实现对底层数据源的增删改查等操作。还需在AndroidManifest文件注册Content Provider,注册时指定访问权限、exported属性、authority属性值等。

其它APP使用ContentResolver对象来查询和操作Content Provider,此对象具有Content Provider中同名的方法名。这样其他APP接就可以访问Content Provider对应的数据源的底层数据,而无须知道数据的结构或实现。 

如何定位到具体的数据? 

采用Content Uri,一个Content Uri如下所示:

content://com.jaq.providertest.friendsprovider/friends

它的组成一般分为三部分:

  1. content://:作为 content Uri的特殊标识(必须);

  2. 权(authority):用于唯一标识这个Content Provider,外部访问者可以根据这个标识找到它;在AndroidManifest中也配置的有;

  3. 路径(path): 所需要访问数据的路径,根据业务而定。

这些内容就不具体展开详谈了,详见参考【1】【4】。

0x01 风险简介


如果在AndroidManifest文件中将某个Content Provider的exported属性设置为true,则多了一个攻击该APP的攻击点。如果此Content Provider的实现有问题,则可能产生任意数据访问、SQL注入、目录遍历等风险。

1.1 私有权限定义错误导致数据被任意访问

私有权限定义经常发生的风险是:定义了私有权限,但是却根本没有定义私有权限的级别,或者定义的权限级别不够,导致恶意应用只要声明这个权限就能够访问到相应的Content Provider提供的数据,造成数据泄露。

以公开的乌云漏洞WooYun-2014-57590为例:

某网盘客户端使用了自己的私有权限,但是在AndroidManifest中却没有定义私有权限,其它APP只要声明这个权限就能访问此网盘客户端提供的Provider,从而访问到用户数据。

在网盘客户端的AndroidManifest中注册Provider时,声明了访问时需要的读写权限,并且权限为客户端自定义的私有权限:

但是在AndroidManifest中却没有见到私有权限“com.huawei.dbank.v7.provider.DBank.READ_DATABASE”和“com.huawei.dbank.v7.provider.DBank.WRITE_DATABASE”的定义:

反编译客户端后查看到的URI,根据这些可以构造访问到Provider的URI:

编写POC

以查看网盘下载的文件列表为例, 

在POC的AndroidManifest中声明私有权限,权限的保护级别定义为最低级“normal”:

主要代码为:

拿到数据库中保存的下载列表数据:

对应的数据库:

这样任意的恶意应用程序就可以访问到用户网盘的上传、下载记录,网盘里面存的文件列表等隐私信息。

再以公开的乌云漏洞wooyun-2013-039697为例:

定义了私有权限,但是保护等级设置成为了dangerous或者normal,这样的保护等级对于一些应用的Provide重要性相比保护级低了。 

Provider为:

私有权限“com.renren.mobile.android.permission.PERMISSION_ADD_ACCOUNT”的定义为:

反编译客户端,看到AcountProvider对应的实现:

编写POC: 

AndroidManifest中定义和声明权限:

主要代码为:

可看到用户的账户信息,包括uid,手机号,加密后的密码等:

1.2 本地SQL注入

当Content Provider的数据源是SQLite数据库时,如果实现不当,而Provider又是暴露的话,则可能会引发本地SQL注入漏洞。

Content Provider的query( )的方法定义为:

其中参数:

  • uri: 为content Uri,要查询的数据库;

  • projection:为要查询的列名;

  • selectionselectionArgs:要指定查询条件;

  • sortOrder:查询结果如何排序。

query() 与 SQL 查询对比如下:

如果query( )中使用的是拼接字符串组成SQL语句的形式去查询底层的SQLite数据库时,容易发生SQL注入。

以乌云公开漏洞wooyun-2016-0175294为例:

客户端的com.sohu.sohuvideo.provider.PlayHistoryProviderexported属性为“true”:

反编译客户端,追踪PlayHistoryProvider的实现,发现是用拼接字符串形式构造原始的SQL查询语句:

使用drozer工具,证明漏洞:

对外暴露的Content Provider实现了openFile()接口,因此其他有相应调用该Content Provider权限的应用即可调用Content Provider的openFile()接口进行文件数据访问。但是如果没有进行Content Provider访问权限控制和对访问的目标文件的Uri进行有效判断,攻击者利用文件目录遍历可访问任意可读文件,更有甚者可以往手机设备可写目录中写入任意数据。

例子1 

以乌云公开漏洞wooyun-2013-044407为例: 

此APP实现中定义了一个可以访问本地文件的Content Provider组件,为com.ganji.android.jobs.html5.LocalFileContentProvider,因为使用了minSdkServison=“8”targetSdkVersion=”13”,即此Content Provider采用默认的导出配置,即android:exported=”true”

该Provider实现了openFile()接口:

通过此接口可以访问内部存储app_webview目录下的数据,由于后台未能对目标文件地址进行有效判断,可以通过”../”实现目录遍历,实现对任意私有数据的访问。

例子2

某社交应用客户端,使用了的minSDKVersion为8,定义了私有权限,并且android:protectionLevel设为了signature

有一个对外暴露的Content Provider,即com.facebook.lite.photo.MediaContentProvider,此Provider没有设置访问权限,而另外一个Provider是设置了访问权限的:

MediaContentProvider中实现了openFile()接口,没有对传入的URI进行限制和过滤:

此接口本来只想让用户访问照片信息的,但是却可以突破限制,读取其他文件: 

POC:

读取到其他文件的内容为:

另外看到Openfile()接口的实现中,如果要访问的文件不存在,就会创建此文件,还有可能的风险就是在应用的目录中写入任意文件。

0x02 阿里聚安全开发者建议


在进行APP设计时,要清楚哪些Provider的数据是用户隐私数据或者其他重要数据,考虑是否要提供给外部应用使用,如果不需要提供,则在AndroidManifes文件中将其exported属性显式的设为“false”,这样就会减少了很大一部分的攻击面。

人工排查肯定比较麻烦,建议开发者使用阿里聚安全提供的安全扫描服务,在APP上线前进行自动化的安全扫描,尽早发现并规避这样的风险。

注意:

由于Android组件Content Provider无法在Android 2.2(即API Level 8)系统上设为不导出,因此建议声明最低SDK版本为8以上版本(这已经是好几年前的SDK了,现在一般都会大于此版本); 

由于API level 在17以下的所有应用的“android:exported”属性默认值都为true,因此如果应用的Content Provider不必要导出,建议显式设置注册的Content Provider组件的“android:exported”属性为false; 

如果必须要有数据提供给外部应用使用,则做好设计,做好权限控制,明确什么样的外部应用可以使用,如对于本公司的应用在权限定义时用相同签名即可,合作方的应用检查其签名;不过还是尽量不提供用户隐私敏感信息。

对于必须暴露的Provider,如第二部分遇到的风险解决办法如下:

2.1 正确的定义私有权限

在AndroidManifest中定义私有权限的语法为:

其中android:protectionLevel的可选值分别表示:

  • normal:默认值,低风险权限,在安装的时候,系统会自动授予权限给 application。

  • dangerous:高风险权限,如发短信,打电话,读写通讯录。使用此protectionLevel来标识用户可能关注的一些权限。Android将会在安装程序时,警示用户关于这些权限的需求,具体的行为可能依据Android版本或者所安装的移动设备而有所变化。

  • signature: 签名权限,在其他 app 引用声明的权限的时候,需要保证两个 app 的签名一致。这样系统就会自动授予权限给第三方 app,而不提示给用户。

  • signatureOrSystem:除了具有相同签名的APP可以访问外,Android系统中的程序有权限访问。

大部分开放的Provider,是提供给本公司的其他应用使用的,一般的话一个公司打包签名APP的签名证书都应该是一致的,这种情况下,Provider的android:protectionLevel应为设为“signature”。

2.2 防止本地SQL注入

注意:一定不要使用拼接来组装SQL语句。 

如果Content Provider的数据源是SQLite数据库,如果使用拼接字符串的形式组成原始SQL语句执行,则会导致SQL注入。 

如下的选择子句:

如果执行此操作,则会允许用户将恶意 SQL 串连到 SQL 语句上。 

例如,用户可以为 mUserInput 输入“nothing; DROP TABLE ** ;”,这会生成选择子句

#!sql
var = nothing; DROP TABLE **;

由于选择子句是作为SQL语句处理,因此这可能会导致提供程序擦除基础 SQLite 数据库中的所有表(除非提供程序设置为可捕获 SQL 注入尝试)。

使用参数化查询:

要避免此问题,可使用一个“ ? ” 作为可替换参数的选择子句以及一个单独的选择参数数组。 

执行此操作时,用户输入直接受查询约束,而不解释为 SQL 语句的一部分。 

由于用户输入未作为 SQL 处理,因此无法注入恶意 SQL。

请使用此选择子句,而不要使用串连来包括用户输入:

#!java
String mSelectionClause = “var = ?”;

按如下所示设置选择参数数组:

#!java
String[] selectionArgs = {“”};

按如下所示将值置于选择参数数组中:

#!java
selectionArgs[0] = mUserInput;

还可调用SQLiteDatabase类中的参数化查询query()方法:

3.3 防止目录遍历

1、去除Content Provider中没有必要的openFile()接口。 

2、过滤限制跨域访问,对访问的目标文件的路径进行有效判断: 

使用Uri.decode()先对Content Query Uri进行解码后,再过滤如可通过“../”实现任意可读文件的访问的Uri字符串,如:

2.4 通过检测签名来授权合作方应用访问

如果必须给合作方的APP提供Provider的访问权限,而合作方的APP签名证书又于自己公司的不同,可将合作方的APP的签名哈希值预埋在提供Provider的APP中,提供Provider的APP要检查请求访问此Provider的APP的签名,签名匹配通过才让访问。

0x03 参考


【1】《内容提供程序基础知识》https://developer.android.com/guide/topics/providers/content-provider-basics.html  

【2】《Android app端的sql注入》http://zone.wooyun.org/content/15097

【3】《Android - Content Providers》 http://www.tutorialspoint.com/android/android_content_providers.htm  

【4】 http://www.compiletimeerror.com/2013/12/content-provider-in-android.html

【5】 https://developer.android.com/guide/topics/manifest/permission-element.html?hl=zh-cn

【6】 https://developer.android.com/guide/topics/manifest/permission-element.html

【7】  WooYun: 人人客户端权限问题导致隐私泄露  

【8】  WooYun: 华为网盘content provider组件可能泄漏用户信息  

【9】 《Android Content Provider Security》http://drops.wooyun.org/tips/4314

【10】  WooYun: 搜狐app注入泄露观看历史  

【11】《Android Content Provider Security》http://drops.wooyun.org/tips/4314

【12】  WooYun: 赶集网Android客户端Content Provider组件任意文件读取漏洞  

【13】  WooYun: 58同城Android客户端远程文件写入漏洞  

【14】 《Content Provider文件目录遍历漏洞浅析》,https://jaq.alibaba.com/blog.htm?id=61 

【15】 https://github.com/programa-stic/security-advisories/tree/master/FacebookLite


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK