自己动手写 drozer 模块

0x01 前言及TOC

drozer 是一个 android 渗透与测试比较出名的一个框架,其源码托管在 GitHub。我们可以利用其进行一些自动化测试工作,以及测试一些拒绝式服务,写一些 exploit 等。

TOC:

  • 前言
  • 安装与配置 drozer
  • 安装模块
  • 动手写一些模块
  • drozer module
  • 自动化测试脚本思考
  • 后记

0x02 安装与配置 drozer

mac10.11 系统:
安装配置好 python,然后使用下面的命令,或者 pip 安装也可以。

1
2
sudo easy_install --allow-hosts pypi.python.org protobuf==2.4.1
sudo easy_install twisted==10.2.0

遇到了如下的问题:

1
error: Setup script exited with error: command 'clang' failed with exit status 1

然后在github上的仓库上寻找方案。其中ISSUE#155叙述了这个问题。但是官网的2.3.4并没有修复依赖。

于是应该clone这个仓库进行安装。然后修复更新的是develop分支,就是clone这个分支的事情了。

1
2
sudo easy_install pyopenssl==0.15
git clone https://github.com/mwrlabs/drozer.git -b develop

然后sudo python setup.py install即可

并且**/usr/local/lib/python2.7/site-packages/drozer-2.3.4-py2.7.egg/drozer/lib/aapt**这个需要配置好755权限。

1
sudo chmod 755 /usr/local/lib/python2.7/site-packages/drozer-2.3.4-py2.7.egg/drozer/lib/aapt

配置drozer,需要在android端也安装好对应的agent

连接上android设备,并打开调试,允许安装未知来源的应用。

然后adb install drozer.apk,或者在官网下载apk包,传到android设备上安装。

之后打开drozer应用,并且设备通过USB线连接上,并设置好端口转发:

1
adb forward tcp:31415 tcp:31415

然后启动drozer应用上的嵌入式服务,Embedded Server,然后按一下Embedded Server滑块,再将Disabled滑块拖到右边。

然后计算机设备上就可以通过下面这条命令连接到drozer console了。

1
drozer console connect

可以进行一些常见的命令:

1
2
3
4
枚举已安装的包:
run app.package.list
查看application信息:
run app.package.info -a application_name

0x03 安装模块

打开drozer console,执行以下命令:

1
2
3
module repository create [path-to-your-module-dir]
module install [pach-to-your-module-dir]/[module-name](模块代码所在路径)
run [module-name]

其中为pach-to-your-module-dir存放编写的模块的目录的路径。

0x04 动手写一些模块

官方文档里说明了需要书写的一些属性:

name、description、examples、author、date、license、path

如果增加参数可使用add_arguments()**方法,其利用argparse**的原理。

模块一:

枚举所有的可导出的activity、content provider、service、broadcast receiver:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
from drozer.modules import common, Module


class Info(Module, common.Filters, common.PackageManager):
name = "Get App Info"
description = ""
examples = ""
author = "Dubu qingfeng"
date = "2016-06-06"
license = "BSD (3-clause)"
path = ["ex", "app"]
permissions = ["com.mwr.dz.permissions.GET_CONTEXT"]

def add_arguments(self, parser):
parser.add_argument("-p", "--package", default=None, help="The Package Name")

def execute(self, arguments):
if arguments.package is None:
for package in self.packageManager().getPackages(common.PackageManager.GET_ACTIVITIES):
self.stdout.write("Package: %s\n" % package.packageName)
self.__get_activities(arguments, package)
self.__get_services(arguments, package)
self.__get_receivers(arguments, package)
self.__get_providers(arguments, package)

else:
package = self.packageManager().getPackageInfo(arguments.package, common.PackageManager.GET_ACTIVITIES)
self.stdout.write("Package: %s\n" % package.packageName)
self.__get_activities(arguments, package)
self.__get_services(arguments, package)
self.__get_receivers(arguments, package)
self.__get_providers(arguments, package)

def __get_providers(self, arguments, package):
exported_providers = self.match_filter(package.providers, 'exported', True)
if len(exported_providers) > 0:
for provider in exported_providers:
for authority in provider.authority.split(";"):
self.__print_provider(provider, authority, " ")
else:
self.stdout.write(" No exported providers.\n\n")

def __print_provider(self, provider, authority, prefix):
self.stdout.write("%sAuthority: %s\n" % (prefix, authority))
self.stdout.write("%s Read Permission: %s\n" % (prefix, provider.readPermission))
self.stdout.write("%s Write Permission: %s\n" % (prefix, provider.writePermission))
self.stdout.write("%s Content Provider: %s\n" % (prefix, provider.name))
self.stdout.write("%s Multiprocess Allowed: %s\n" % (prefix, provider.multiprocess))
self.stdout.write("%s Grant Uri Permissions: %s\n" % (prefix, provider.grantUriPermissions))
if provider.uriPermissionPatterns is not None:
self.stdout.write("%s Uri Permission Patterns:\n" % prefix)
for pattern in provider.uriPermissionPatterns:
self.stdout.write("%s Path: %s\n" % (prefix, pattern.getPath()))
self.stdout.write("%s Type: %s\n" % (prefix, Info.PatternMatcherTypes[int(pattern.getType())]))
if provider.pathPermissions is not None:
self.stdout.write("%s Path Permissions:\n" % prefix)
for permission in provider.pathPermissions:
self.stdout.write("%s Path: %s\n" % (prefix, permission.getPath()))
self.stdout.write("%s Type: %s\n" % (prefix, Info.PatternMatcherTypes[int(permission.getType())]))
self.stdout.write("%s Read Permission: %s\n" % (prefix, permission.getReadPermission()))
self.stdout.write("%s Write Permission: %s\n" % (prefix, permission.getWritePermission()))

def __get_receivers(self, arguments, package):
exported_receivers = self.match_filter(package.receivers, 'exported', True)
if len(exported_receivers) > 0:
for receiver in exported_receivers:
self.__print_receiver(receiver, " ")
else:
self.stdout.write(" No exported receivers.\n\n")

def __print_receiver(self, receiver, prefix):
self.stdout.write("%s%s\n" % (prefix, receiver.name))
self.stdout.write("%s Permission: %s\n" % (prefix, receiver.permission))

def __get_services(self, arguments, package):
exported_services = self.match_filter(package.services, "exported", True)
if len(exported_services) > 0:
for service in exported_services:
self.__print_service(service, " ")
else:
self.stdout.write(" No exported services.\n\n")

def __print_service(self, service, prefix):
self.stdout.write("%s%s\n" % (prefix, service.name))
self.stdout.write("%s Permission: %s\n" % (prefix, service.permission))

def __get_activities(self, arguments, package):
exported_activities = self.match_filter(package.activities, 'exported', True)
if len(exported_activities) > 0:
for activity in exported_activities:
self.__print_activity(package, activity, " ")
else:
self.stdout.write(" No exported activities.\n\n")

def __print_activity(self, package, activity, prefix):
self.stdout.write("%s%s\n" % (prefix, activity.name))
if activity._has_property("parentActivityName") and activity.parentActivityName is not None:
self.stdout.write("%s Parent Activity: %s\n" % (prefix, activity.parentActivityName))
self.stdout.write("%s Permission: %s\n" % (prefix, activity.permission))
if activity.targetActivity is not None:
self.stdout.write("%s Target Activity: %s\n" % (prefix, activity.targetActivity))

在模块一的基础上实现自动启动可导出的activity,以测试是否产生拒绝式服务。

1
2
3
4
5
6
7
8
9
10
try:
intent = self.new("android.content.Intent")
comp = (package.packageName, activity.name)
com = self.new("android.content.ComponentName", *comp)
intent.setComponent(com)
intent.setFlags(0x10000000)
self.getContext().startActivity(intent)
except Exception:
self.stderr.write("%s need some premission." % activity.name)

0x05 drozer module

QA:
1.drozer 模块存放在哪,从哪寻找那些模块?

用户自定义的模块,在当前目录下面会生成如下图所示的结构,当删除这个目录后,模块也被删除。并且 drozer 会在模块目录,存在一个名为 .drozer_repository 的文件。

并且 drozer 的文件中说明了寻找模块的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def __locate(self):
"""
Search the module paths for Python modules, which may contain drozer
Modules, and build a collection of Python modules to load.
"""

modules = {}

for path in self.__paths():
for dirpath, _dirnames, filenames in os.walk(path):
for filename in filenames:
module_path = os.path.join(dirpath[len(path) + len(os.path.sep):], filename)
module_name, ext = os.path.splitext(module_path)

if ext in [".py", ".pyc", ".pyo"]:
namespace = ".".join(module_name.split(os.path.sep))
filepath = os.path.join(path, module_path)

module = filepath[len(path)+1:filepath.rindex(".")].replace(os.path.sep, ".")

if os.path.abspath(self.__module_paths) in path:
modules[namespace] = "drozer.modules." + module
else:
modules[namespace] = module

return modules

0x06 自动化测试脚本思考

主要就是爬虫下载apk,然后自动安装apk,然后drozer去分析利用。

爬虫下载apk的思路,曾经利用scrapy去下载一些apk网站上的排行apk。托管在了Coding

如何自动安装apk呢?利用adb install -r xxx.apk

所以是爬虫下载apk,然后分开不同的目录,再利用脚本adb安装到设备上,并将包名输出到一个文件里,然后模块里在读取文件,然后进行检查package,或者拒绝服务的检测。

0x07 后记

drozer 是利用 protobuf 协议作为通信的,如果这个协议出现了问题,又会怎么样呢?这是以后思考的方向吧。

当然 drozer 的可利用范围是比较广的,可以测试 SQL 注入,以及各种组件的漏洞,或者配合 nc 进行 shell 的获取。以后再整理一些利用思路,或者一些 exploit 的编写。

0x08 参考链接

自己动手开发Drozer插件之AutoAttack

Author

admin

Posted on

2016-06-08

Updated on

2016-06-09

Licensed under

Comments