Android Content Provider Security(转)

四大组件之一—content provider安全详解

原帖地址:http://drops.wooyun.org/tips/4314

0x00 科普



内容提供器用来存放和获取数据并使这些数据可以被所有的应用程序访问。它们是应用程序之间共享数据的唯一方法;不包括所有Android软件包都能访问的公共储存区域。Android为常见数据类型(音频,视频,图像,个人联系人信息,等等)装载了很多内容提供器。你可以看到在android.provider包里列举了一些。你还能查询这些提供器包含了什么数据。当然,对某些敏感内容提供器,必须获取对应的权限来读取这些数据。

如果你想公开你自己的数据,你有两个选择:你可以创建你自己的内容提供器(一个ContentProvider子类)或者你可以给已有的提供器添加数据,前提是存在一个控制同样类型数据的内容提供器且你拥有读写权限。

0x01 知识要点



参考:http://developer.android.com/guide/topics/providers/content-providers.html

Content URIs

content URI 是一个标志provider中的数据的URI.Content URI中包含了整个provider的以符号表示的名字(它的authority) 和指向一个表的名字(一个路径).当你调用一个客户端的方法来操作一个provider中的一个表,指向表的content URI是参数之一.

A. 标准前缀表明这个数据被一个内容提供器所控制。它不会被修改。

B. URI的权限部分;它标识这个内容提供器。对于第三方应用程序,这应该是一个全称类名(小写)以确保唯一性。权限在 元素的权限属性中进行声明:

    <provider name=".TransportationProvider"       authorities="com.example.transportationprovider"       . . .  >

C. 用来判断请求数据类型的路径。这可以是0或多个段长。如果内容提供器只暴露了一种数据类型(比如,只有火车),这个分段可以没有。如果提供器暴露若干类型,包括子类型,那它可以是多个分段长-例如,提供"land/bus", "land/train", "sea/ship", 和"sea/submarine"这4个可能的值。

D. 被请求的特定记录的ID,如果有的话。这是被请求记录的_ID数值。如果这个请求不局限于单个记录, 这个分段和尾部的斜线会被忽略:

    content://com.example.transportationprovider/trains

ContentResolver

ContentResolver的方法们提供了对存储数据的基本的"CRUD" (增删改查)功能


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

getIContentProvider() 

      Returns the Binder object for this provider.

  

delete(Uri uri, String selection, String[] selectionArgs) -----abstract

      A request to delete one or more rows.

  

insert(Uri uri, ContentValues values) 

      Implement this to insert a new row.

  

query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 

      Receives a query request from a client in a local process, and returns a Cursor.

  

update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 

      Update a content URI.

  

openFile(Uri uri, String mode) 

      Open a file blob associated with a content URI.

Sql注入

sql语句拼接


1

2

// 通过连接用户输入到列名来构造一个选择条款

String mSelectionClause =  "var = " + mUserInput;

参数化查询


1

2

// 构造一个带有占位符的选择条款

String mSelectionClause =  "var = ?";

权限

下面的 元素请求对用户词典的读权限:

<uses-permission android:name="android.permission.READ_USER_DICTIONARY">

申请某些protectionLevel="dangerous"的权限

<uses-permission android:name="com.huawei.dbank.v7.provider.DBank.READ_DATABASE"/>

<permission android:name="com.huawei.dbank.v7.provider.DBank.READ_DATABASE" android:protectionLevel="dangerous"></permission>

android:protectionLevel

normal:默认值。低风险权限,只要申请了就可以使用,安装时不需要用户确认。

dangerous:像WRITE_SETTING和SEND_SMS等权限是有风险的,因为这些权限能够用来重新配置设备或者导致话费。使用此protectionLevel来标识用户可能关注的一些权限。Android将会在安装程序时,警示用户关于这些权限的需求,具体的行为可能依据Android版本或者所安装的移动设备而有所变化。

signature:这些权限仅授予那些和本程序应用了相同密钥来签名的程序。

signatureOrSystem:与signature类似,除了一点,系统中的程序也需要有资格来访问。这样允许定制Android系统应用也能获得权限,这种保护等级有助于集成系统编译过程。

API

Contentprovider组件在API-17(android4.2)及以上版本由以前的exported属性默认ture改为默认false。

Contentprovider无法在android2.2(API-8)申明为私有。

<!-- *** POINT 1 *** Do not (Cannot) implement Private Content Provider in Android 2.2 (API Level 8) or earlier. -->
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" />

关键方法

  • public void addURI (String authority, String path, int code)
  • public static String decode (String s)
  • public ContentResolver getContentResolver()
  • public static Uri parse(String uriString)
  • public ParcelFileDescriptor openFile (Uri uri, String mode)
  • public final Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs, String sortOrder)
  • public final int update(Uri uri, ContentValues values, String where,String[] selectionArgs)
  • public final int delete(Uri url, String where, String[] selectionArgs)
  • public final Uri insert(Uri url, ContentValues values)

0x02 content provider 分类



这个老外分的特别细,个人认为就分private、public、in-house差不多够用。

0x03 安全建议


  1. minSdkVersion不低于9
  2. 不向外部app提供的数据的私有content provider设置exported=“false”避免组件暴露(编译api小于17时更应注意此点)
  3. 使用参数化查询避免注入
  4. 内部app通过content provid交换数据设置protectionLevel=“signature”验证签名
  5. 公开的content provider确保不存储敏感数据
  6. Uri.decode() before use ContentProvider.openFile()
  7. 提供asset文件时注意权限保护

0x04 测试方法



1、反编译查看AndroidManifest.xml(drozer扫描)文件定位content provider是否导出,是否配置权限,确定authority


1

2

drozer:

run app.provider.info -a cn.etouch.ecalendar

2、反编译查找path,关键字addURI、hook api 动态监测推荐使用zjdroid

3、确定authority和path后根据业务编写POC、使用drozer、使用小工具Content Provider Helper、adb shell // 没有对应权限会提示错误


1

2

3

4

5

6

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‘"


1

2

drozer:

run app.provider.query content://telephony/carriers/preferapn --vertical

0x05 案例



案例1:直接暴露

案例2:需权限访问

案例3:openFile文件遍历

Override openFile method

错误写法1:


1

2

3

4

5

6

private static String IMAGE_DIRECTORY = localFile.getAbsolutePath();

public ParcelFileDescriptor openFile(Uri paramUri, String paramString)

    throws FileNotFoundException {

  File file = new File(IMAGE_DIRECTORY, paramUri.getLastPathSegment());

  return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);

}

错误写法2:URI.parse()


1

2

3

4

5

6

private static String IMAGE_DIRECTORY = localFile.getAbsolutePath();

public ParcelFileDescriptor openFile(Uri paramUri, String paramString)

    throws FileNotFoundException {

    File file = new File(IMAGE_DIRECTORY, Uri.parse(paramUri.getLastPathSegment()).getLastPathSegment());

    return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);

}

POC1:


1

2

3

4

5

6

7

String target = "content://com.example.android.sdk.imageprovider/data/" + "..%2F..%2F..%2Fdata%2Fdata%2Fcom.example.android.app%2Fshared_prefs%2FExample.xml";

  

ContentResolver cr = this.getContentResolver();

FileInputStream fis = (FileInputStream)cr.openInputStream(Uri.parse(target));

  

byte[] buff = new byte[fis.available()];

in.read(buff);

POC2:double encode


1

2

3

4

5

6

7

String target = "content://com.example.android.sdk.imageprovider/data/" + "%252E%252E%252F%252E%252E%252F%252E%252E%252Fdata%252Fdata%252Fcom.example.android.app%252Fshared_prefs%252FExample.xml";

  

ContentResolver cr = this.getContentResolver();

FileInputStream fis = (FileInputStream)cr.openInputStream(Uri.parse(target));

  

byte[] buff = new byte[fis.available()];

in.read(buff);

解决方法Uri.decode()


1

2

3

4

5

6

7

8

9

10

private static String IMAGE_DIRECTORY = localFile.getAbsolutePath();

  public ParcelFileDescriptor openFile(Uri paramUri, String paramString)

      throws FileNotFoundException {

    String decodedUriString = Uri.decode(paramUri.toString());

    File file = new File(IMAGE_DIRECTORY, Uri.parse(decodedUriString).getLastPathSegment());

    if (file.getCanonicalPath().indexOf(localFile.getCanonicalPath()) != 0) {

      throw new IllegalArgumentException();

    }

    return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);

  }

0x06 参考



https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=111509535

http://www.jssec.org/dl/android_securecoding_en.pdf

http://developer.android.com/intl/zh-cn/reference/android/content/ContentProvider.html

0x07 相关阅读

http://zone.wooyun.org/content/15097

http://drops.wooyun.org/tips/2997

时间: 2024-09-30 15:37:32

Android Content Provider Security(转)的相关文章

Android Content Provider的启动过程源代码分析

本文参考Android应用程序组件Content Provider的启动过程源代码分析http://blog.csdn.net/luoshengyang/article/details/6963418和<Android系统源代码情景分析>,作者罗升阳. 0.总图流程图如下: 1.MainActivity进程向ActivityServiceManager主线程发送GET_CONTENT_PORVIDER_TRANSACTION 如下图: 如图:第一步 ~/Android/frameworks/b

Android Content Provider在应用程序之间共享数据的原理分析

本文参考Android应用程序组件Content Provider在应用程序之间共享数据的原理分析http://blog.csdn.net/luoshengyang/article/details/6967204和<Android系统源代码情景分析>,作者罗升阳. 0.总图流程图如下: 总体类图: 1.MainActivity进程向AriticlesProvider进程发送IContentProvider.QUERY_TRANSACTION 如图:第一步 ~/Android/framework

android content provider 中的URL解析总是出问题?求指导!!!

java.lang.IllegalArgumentException: Unknown URL content:// 不管是自己写或者用别的的代码在我的eclipse中都是报这个错误 很怪,我的URL地址绝对没有写错,是不是和使用版本有关系?我的google提供的eclipse,sdk用的2.3.3 android content provider 中的URL解析总是出问题?求指导!!!

Android Content Provider Guides

Android Content Provider Guides Content Providers管理对结构化数据集的访问.它们包装数据,并且提供一种定义数据安全的机制. Content providers是不同进程间数据连接的标准接口. 要获取content provider中的数据,需要运用你的应用中的 Context中的ContentResolver对象作为一个client来和provider交互. 这个provider对象是一个实现了ContentProvider接口的类的对象.Prov

一个典型的Android问题--exported Android content provider引发的隐私泄露问题【中】

YS android手机APP对外开放多余的content provider,可任意增.删.改和查images数据库表格,导致隐私泄露 问题描述:          YS android手机APP使用SQLITE数据库做数据存储,在android系统上可以通过content provider实现对SQLITE数据库的操作,通过drozer查看发现YS APP对外开放了content provider(经确认是不需要开放的),通过测试发现该provider对应images数据表,里面存放了用户名和

Android Content Provider简介

Content Provider是Android的四大组件之一,与Activity和Service相同,使用之前需要注册: Android系统中存在大量的应用,当不同的应用程序之间需要共享数据时,可以使用Content Provider来实现,因为它为存储和读取数据提供了统一的接口: (1)Android系统内置的许多数据都是使用Content Provider,然后供开发者调用,如音频,视频,图片,通讯录等: (2)当一个程序需要把自己的数据暴露给其他程序使用时,该程序就可以通过提供Conte

[Android学习系列17]Content Provider的一些事

参考: android Content Provider详解一 android Content Provider详解二 android Content Provider详解三 android Content Provider详解四 android Content Provider详解五 android Content Provider详解六 android Content Provider详解七-实现ContentProvider类 android Content Provider详解八-实现C

Android开发- 数据库和Content Provider

SQLiteOpenHelper SQLiteOpenHelper是一个抽象类,用来实现创建.打开和升级数据库的最佳实践模式. private static class HoardDBOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "myDatabase.db"; private static final String DATABASE_TABLE = "Gol

内容提供者基础 Content Provider Basics——翻译自developer.android.com

#内容提供者基础 Content Provider Basics content provicer 管理着中心数据仓库的访问.一个provider是Android的应用的一部分,它可以提供数据工作的UI. 然而,content provider基本都是被其他的应用访问,使用一个provider客户端对象来访问provider.provider和provider client一同创立了一个持续的标准的数据接口,它可以提供进程内通信以及安全数据访问. 这个主题讲解下面内容的基础部分: - conte