Android安全评估工具drozer

关于Android 安全评估工具drozer的基本使用。

1.环境配置

需要在PC端安装drozer console,然后在手机端安装drozer Agent(一个APP)。

2.运行一个drozer会话

  1. 在手机端的App中打开drozer Server
  2. 在PC端使用ADB进行端口转发——adb forward tcp:31415 tcp:31415
  3. 在PC端运行命令,连接drozer console——drozer console connect

接下来就可以利用drozer对手机上的App进行安全测试啦!

3.drozer框架的基本使用

前言

使用list命令可以列出当前drozer工具中可用的所有模块。

(1)枚举已安装的包及相关信息-app.package.info

  1. 枚举已安装的包——run app.package.list
  2. 根据app的名称过滤app——run app.package.list -f [app名]
  3. 获取Android设备中所有包的相关信息,包括权限、配置、组ID、共享库等——run app.package.info


  1. 提取某个具体包的相关信息——run app.package.info --package [包名]run app.package.info -a [包名]
  2. 根据包的权限寻找包——run app.package.info -p [权限标识]*(如run app.package.info -p android.permission.INTERNET)*

(2)枚举activity-app.activity.info

  1. 列出Android设备上所有导出的activity——run app.activity.info

  1. 列出所有名称中含有[activity名]的activity——run app.activity.info --filter [activity名]或者run app.activity.info -f [activity名]
  2. 搜索指定包中的activity——run app.activity.info --package [package名]或者run app.activity.info -a [package名]

(3)枚举content provider-app.provider.info

  1. 返回如下图所示的关于app中content provider的信息——run app.provider.info


  1. 根据包的名称进行搜索——run app.provider.info -a [包名]
  2. 根据权限进行搜索——run app.provider.info -p [权限标识]

(4)枚举service-app.service.info

  • run app.service.info
  • run app.service.info -a [包名]
  • run app.service.info -p [权限标识]
  • run app.service.info -f [过滤字符串]
  • run app.service.info -u/–unexported(选择列出未导出的service)
  • run app.service.info –help(了解其他一些关于参数和选项的信息)

(5)枚举broadcast receiver-app.broadcast.info

  • run app.broadcast.info
  • run app.broadcast.info -a [包名]
  • run app.broadcast.info -f [过滤字符串]
  • run app.broadcast.info -u
  • run app.broadcast.info -i/–show-intent-filters(选择在输出的信息中是否包含“intent filter”)

(6)确定app的受攻击面

  1. 统计出指定包中所有导出的组件——run app.package.attacksurface [包名]

(7)运行activity

  1. 首先用以下命令找到要运行的activity并获取其基本信息——run app.activity.info --package [package name]
  2. 然后使用以下命令启动activity——run app.activity.start --action [intent action] --category [intent category] --component [package name] [component name]——其中,[Intent action]是由目标 activity设置的 intent filter的 action属性;[Intent category]由目标 actIvity设置的 intent filter的 category属性。
  3. 举例如下图。

4.drozer框架进阶-编写drozer模块

(1)安装drozer模块的两种方法

两种方法都需要先利用命令module repository create [/path/to/repository]在本地创建一个drozer的repository目录。

方法一

按照python包管理的方式,在本地repository目录下创建目录exp(注意这个目录名称需要和自定义模块脚本里path项的第一项值一致),新建int.py空白文件,然后将Python模块源码放入exp目录即可。

方法二

通过drozer console中的命令module install 安装。

(2)一个驱动枚举模块

接下来对上图中的代码进行一些补充说明。

  1. 关于execute方法接收的两个参数;

  1. 关于代码build = self.new("android.os.Build")

(3)一个app证书枚举器


5.编写dex插件

除了利用drozer以python代码形式提供的API,用户还可以用java代码编写dex插件。drozer的modules/common目录下包含了多个dex插件的源码,有兴趣的可以自己查看。

drozer模块的编写及模块动态加载问题研究

6.drozer模块的reload及动态加载问题

7.利用drozer实现Intent Fuzzing

Android(五)Drozer上的Intent Fuzzing

核心功能代码实现如下——

def execute(self, arguments):  
    if arguments.package != None:  
        package = self.packageManager().getPackageInfo(arguments.package, common.PackageManager.GET_ACTIVITIES | common.PackageManager.GET_RECEIVERS | common.PackageManager.GET_PROVIDERS | common.PackageManager.GET_SERVICES)  

        application = package.applicationInfo 
        activities = self.match_filter(package.activities, 'exported', True)  //获取导出的四大组件
        receivers = self.match_filter(package.receivers, 'exported', True)  
        providers = self.match_filter(package.providers, 'exported', True)  
        services = self.match_filter(package.services, 'exported', True)  
        attack_actions = []             //这里是用于存放后续扩展测试所用的测试用例action的

        self.stdout.write("Attack Surface:\n")  
        self.stdout.write("  %d activities exported\n" % len(activities))  
        self.stdout.write("  %d broadcast receivers exported\n" % len(receivers))  
        self.stdout.write("  %d content providers exported\n" % len(providers))  
        self.stdout.write("  %d services exported\n" % len(services)) 

        if (application.flags & application.FLAG_DEBUGGABLE) != 0:           //判断应用程序是否可调试
            self.stdout.write("    is debuggable\n")  

        if package.sharedUserId != None:                                     //判断应用程序是否含有sharedUserID
            self.stdout.write("    Shared UID (%s)\n" % package.sharedUserId)  

        actions=[activities,receivers,services]  
        action_str=['activity','receiver','service']  
        i=-1  
        try:  
            for action in actions:  
                self.stdout.write("[color yellow] ================== empty action test ===============[/color]\n")
                i+=1  
                if len(action) > 0:  
                    for tmp in action:  
                        try:  
                            if len(tmp.name) > 0:  
                                self.stdout.write("[color green] [+]%s name:%s[/color]\n" % (action_str[i],tmp.name))  
                                self.attack(component=tmp, package=arguments.package, flags=action_str[i])    //调用attack方法,构造intent数据并执行模糊测试
                        except Exception, e:  
                            self.stdout.write("    [color blue] error-->%s name:%s[/color]\n" % (action_str,tmp.name))  
                            self.stdout.write("    [color blue] errorcontent:%s[/color]\n" % e)                                  continue 
        except:  
            self.stdout.write(" error") 
        self.stdout.write("    [color blue]activity has no action[/color]\n")

        if len(attack_actions) > 0:                   //这里是根据用户自定义的action数据,构造intent测试数据,然后测试activity的
            self.stdout.write("[color yellow] ============ empty activity test ================ [/color]\n")
            for attack_action in attack_actions:
                try:
                    self.stdout.write("  [color green][+]action name: %s[/color]\n" % (attack_action))
                    intent = self.new("android.content.intent")
                    intent.setAction(attack_action)
                    intent.setFlags(0x10000000)
                    self.getContext().startActivity(intent)
                except Exception:
                    self.stdout.write("    [color blue]action %s start failure...[/color]\n" % (attack_action))
        else:
            self.stdout.write("    [color blue]activity has no action[/color]\n")
    else:  
        self.stdout.write("No package specified\n")

 //根据传入参数构造intent格式,并发送给对应组件实现模糊测试
 def attack(self,component,package,flags): 
    act=None 
    cat=None 
    data=None 
    comp=(package,component.name) 
    extr=None 
    flgs=None 

    if(flags=='activity'): 
        flgs =['ACTIVITY_NEW_TASK'] 
    intent = android.Intent(action=act,component=comp,category=cat,data_uri=None, extras=extr, flags=flgs, mimetype=None) 

    if intent.isValid(): 
        if(flags=='activity'): 
            self.getContext().startActivity(intent.buildIn(self))
        if(flags=='service'): 
            self.getContext().startService(intent.buildIn(self)) 
        if(flags == 'receiver'): 
            self.getContext().sendBroadcast(intent.buildIn(self)) 
    else: 
        self.stderr.write("[-] Invalid Intent!\n")

初步以空intent为例,给所有app的未导出组件发送空intent,同时可以监控logcat,如程序对Intent.getXXXExtra()获取的空数据处理时没有进行异常捕获,则app会直接crash,然后可以进一步挖掘是否可以权限提升等其他攻击。后续还可以添加intent权限构造、反馈跟踪等功能。

8.报错及解决

报错

在安装drozer时,为了使用方便,将其安装目录添加到了环境变量中。但在使用drozer的时候报错如下图所示。

解决

在命令行中使用drozer时还是应该进入其安装目录,然后使用相关命令。

unknown module: ‘app.package.list’

9.参考链接

利用drozer进行Android渗透测试
开源项目drozer的源码
drozer模块的编写及模块动态加载问题研究