Frida主动调用爆破密码

Frida主动调用爆破密码

0x00 案例下载地址

asktaosec/AndroidApplicationSecurity

0x01 案例分析

1 APP功能分析

安装运行目标APP,经分析,该APP启动后展现的是一个登录界面,用户在输入框中输入PIN,再点击VERIFY PIN进行验证,并提示验证结果:

2 需要达到的目的

在平时的APP渗透测试过程当中,如果遇到一个登录入口,首先想到的可能是通过抓取登录操作向服务器传输的数据包,通过对数据包中的密码字段进行爆破。但在这个案例中,遗憾的是APP并未向服务器发起网络请求,而是通过客户端本身对用户的输入进行判断并返回正确的结果。因此,接下来就是学习如何在这种情况通过frida对密码进行暴力破解,得到正确的返回结果。

3 反编译分析目标APP

3.1 使用jadx反编译目标APP

3.2 搜索特定字符串

当在app中点击按钮的时候,app会弹出响应的验证结果提示:“Unfortunately,not the right PIN 😦” ,在jadx反编译代码中搜索字符串,目的是尽可能定位到离关键位置近的地方,没有结果。

换个工具,使用androidkiller反编译apk,并搜索提示的字符串,如下:

复制字符串资源对应的name:dialog_failure 到jadx反编译得到的源码中进行检索,结果如下:


3.3 静态代码分析

以下为通过提示字符传定位到的一个函数:

public void verifyPasswordClick(View view) {
        if (!Verifier.verifyPassword(this, this.txPassword.getText().toString())) {
            Toast.makeText(this, R.string.dialog_failure, 1).show();
        } else {
            showSuccessDialog();
        }
    }

阅读代码可知,函数的内部是一个if...else的条件判断语句,当if条件为真时,表示我们输入的PIN错误,返回验证失败的提示。反之,则表示验证成功。

因此,关键的验证逻辑可以判断出应该在Verifier.verifyPassword()方法中,跟踪此方法,查看内部实现的代码逻辑,如下:

package org.teamsik.ahe17.qualification;

import android.content.Context;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Verifier {
    private Verifier() {
    }

    public static boolean verifyPassword(Context context, String input) {
        if (input.length() != 4) {
            return false;
        }
        byte[] v = encodePassword(input);
        byte[] p = "09042ec2c2c08c4cbece042681caf1d13984f24a".getBytes();
        if (v.length != p.length) {
            return false;
        }
        for (int i = 0; i < v.length; i++) {
            if (v[i] != p[i]) {
                return false;
            }
        }
        return true;
    }

    private static byte[] encodePassword(String input) {
        byte[] SALT = {95, 35, 83, 73, 75, 35, 95};
        try {
            StringBuilder sb = new StringBuilder();
            sb.append((char) SALT[0]);
            sb.append((char) SALT[1]);
            for (int i = 0; i < input.length(); i++) {
                sb.append((char) input.getBytes("iso-8859-1")[i]);
                sb.append((char) SALT[i + 2]);
            }
            sb.append((char) SALT[6]);
            byte[] bArr = new byte[0];
            return SHA1(sb.toString()).getBytes("iso-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static String convertToHex(byte[] data) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < data.length; i++) {
            int halfbyte = (data[i] >>> 4) & 15;
            int two_halfs = 0;
            while (true) {
                if (halfbyte < 0 || halfbyte > 9) {
                    buf.append((char) ((halfbyte - 10) + 97));
                } else {
                    buf.append((char) (halfbyte + 48));
                }
                halfbyte = data[i] & 15;
                int two_halfs2 = two_halfs + 1;
                if (two_halfs >= 1) {
                    break;
                }
                two_halfs = two_halfs2;
            }
        }
        return buf.toString();
    }

    private static String SHA1(String text) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] bArr = new byte[40];
            md.update(text.getBytes("iso-8859-1"), 0, text.length());
            return convertToHex(md.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e2) {
            e2.printStackTrace();
        }
        return null;
    }
}

通过分析,我们可以知道verifyPassword的实现功能如下:

  1. 判断PIN码的长度是否为4位,不等于4位则验证失败。
  2. 将用户输入的4位PIN码经encodePassword()函数转换后与“09042ec2c2c08c4cbece042681caf1d13984f24a”进行比对,如果相同,则表示输入正确。

0x03 Frida主动调用实现密码爆破

既然我们知道了verifyPassword()函数的实现功能,也不难得出,当我们如果输入正确的PIN的话,经encodePassword()处理过后得到的结果也一定是和“09042ec2c2c08c4cbece042681caf1d13984f24a”相同的字符串,因此,接下来就直接通过frida 主动调用encodePassword()来暴力破解得到结果并与“09042ec2c2c08c4cbece042681caf1d13984f24a”进行比较。

1 实现代码

frida -U org.teamsik.ahe17.qualification.easy -l brutefroce.js
function main(){
	console.log("Entering the Script!"); /*打印日志,用来确定是否进入main函数开始执行*/
	
	Java.perform(function x(){
        console.log("Inside java perform");
        var Verifier = Java.use("org.teamsik.ahe17.qualification.Verifier");
        var stringClass = Java.use("java.lang.String");
        var p = stringClass.$new("09042ec2c2c08c4cbece042681caf1d13984f24a");
        var pSign = p.getBytes();
        for (var i = 0; i < 10000; i++){
            var v = "";
            if (i < 10){
                v = "000" + stringClass.$new(String(i));
            }else if (i>=10&&i<100) {
                v = "00" + stringClass.$new(String(i));
            }else if (i>+100&&i<1000) {
                v = "0" + stringClass.$new(String(i));
            }else{
                v = stringClass.$new(String(i));
            }

            var vSign = Verifier.encodePassword(v);

            if (parseInt(stringClass.$new(pSign))== parseInt(stringClass.$new(vSign)) ) {
                console.log("yes: " + v)
                break
            }
            console.log("not :" + v)
        }

	})

}

setImmediate(main)

2 密码爆破效果

posted @ 2020-09-30 08:59  AskTa0  阅读(956)  评论(0编辑  收藏  举报