Content Provider攻防
什么是Content Provider?
按照Google为Android设计的安全模型,应用的数据属于私有数据,故默认情况下,应用无法访问其他应用的私有数据。但当应用需要与其他应用共享数据时,Content Provider就扮演着应用间数据共享桥梁的角色。Content Providers使用标准的insert(),query(),update(), delete()等方法来操作应用的数据,每个Content Provider都对应一个以”content://”开头的特定URI,任何应用都可以通过这个URI操作Content Provider 应用的数据库。
漏洞
反编译 获取 AndroidManifest.xml文件中注册的content provider 并检查所有用到了相关URI的smali文件。
<provider
android:authorities="me.pengtao.contentprovidertest"
android:name=".provider.TestProvider"
android:exported="true">
</provider>
我们在AndroidManifest.xml文件中发现其中注册了一个content provider ,并且该content provider 是暴露的(android:exported=”true”),这意味着所有应用都可以访问这个content provider
1、 使用adb命令
要使用adb来访问content provider,测试应用要先安装在一台供测试的设备上。
首先获得一个adb shell (cmd: # adb shell),并使用下面的命令来读取content provider.比如我现在要去的读取一个在MyProvider.smali中发现的URI:
Content –query –uri content://com.isi.contentprovider.MyProvider/udetails
不出意外的话,我们就能看到储存在应用数据库中的内容了
2、使用一个恶意应用发起查询
我们甚至能自己写一个简单的恶意应用来读取content provider。以下一段读取收件箱的示例代码:
Uri uri = Contacts.People.CONTENT_URI;
String[] projection = {Contacts.People._ID, Contacts.People.PRIMARY_PHONE_ID, Contacts.PeopleColumns.NAME, Contacts.PeopleColumns.TIMES_CONTACTED};
String selection = Contacts.PeopleColumns.NAME + " like ?";
String[] selectionArgs = {"%li,%"};
String sortOrder = Contacts.PeopleColumns.NAME+" ASC";
ContentResolver cr = getContentResolver();
Cursor phonecursor = cr.query(phoneuri, phoneprojection, null, null, null);
3、使用Mercury框架(译者注:以改名为drozer)
使用mercury框架,整个攻击过程将更加简单和高效。
预防
1、 设置android:exported 属性为false:
2、 通过设置自定义权限来限制对content provider的访问
我们可以通过自定义权限来对content provider的访问进行权限控制.这在开发者想对具有特定权限的应用开放访问的情况下很有用。
Content Provider的其他安全问题
SQL注入:如果安全控制不当,Content Provider 会造成客户端的SQL注入,与传统的SQL注入攻击方法类似。
目录遍历:如果Content Provider的实现存在问题,可能还会造成目录遍历。这与WEB中的目录遍历类似,允许攻击者遍历并访问本地文件系统。可通过该漏洞读取设备中的敏感文件。
<provider
android:authorities="me.pengtao.contentprovidertest"
android:name=".provider.TestProvider"
android:readPermission="me.pengtao.READ"
android:exported="true">
</provider>
则在其他应用中可以使用以下权限来对TestProvider进行访问。
<uses-permission android:name="me.pengtao.READ"/>
对不同的数据表有不同的权限操作,要如何做呢?Android为这种场景提供了provider的子标签
<path-permission>
,path-permission包括了以下几个标签。
<path-permission android:path="string"
android:pathPrefix="string"
android:pathPattern="string"
android:permission="string"
android:readPermission="string"
android:writePermission="string" />
android:exported 设置此provider是否可以被其他应用使用。
android:readPermission 该provider的读权限的标识
android:writePermission 该provider的写权限标识
android:permission provider读写权限标识
android:grantUriPermissions 临时权限标识,
true时,意味着该provider下所有数据均可被临时使用;
false时,则反之,但可以通过设置<grant-uri-permission>标签来指定哪些路径可以被临时使用。
这么说可能还是不容易理解,
我们举个例子,
比如你开发了一个邮箱应用,其中含有附件需要第三方应用打开,
但第三方应用又没有向你申请该附件的读权限,
但如果你设置了此标签,则可以在start第三方应用时,
传入FLAG_GRANT_READ_URI_PERMISSION或FLAG_GRANT_WRITE_URI_PERMISSION来让第三方应用临时具有读写该数据的权限。
原文