记一次APP测试的爬坑经历

0x01 闪退

开始在接到任务的时候,由于是第一次接触APP测试,俺兴高采烈的将其装进咱的夜神模拟器里面,准备学习一番。结果,轻触APP,它轻轻地来了,却又轻轻地走了(对没错,它无脑闪退。。。),我当时的心情是这样的:!@#¥@%¥#@%&#%&🤮🤮。

随后各位大佬告诉我,可以更换真机、模拟器、安卓版本各种尝试。

在经过一系列的测试后,将夜神模拟器的版本换为 Android 7 成功解决闪退问题😃😃。

0x02 抓包

为了抓取APP的数据包,我将burp的证书装入我的模拟器中。但是,却一直抓不到,在做了一定功课了解后,知道了可以采用 Xposed + JustTrustMe 来突破 SSL PINNING

image

但是!但是!但是!模拟器在未装 JustTrustMe 时候无法抓包,而在装上以后,整个网络环境,不,可,用。打扰了~

image

还好,感谢雄哥给的 JustTrustMePlus (只令某一个APP强制信任证书)。

image
image

再用 Burp 进行抓包的时候,就能成功抓取到APP的数据包了。

嗯~ o( ̄▽ ̄)o,舒服了...

0x03 传输加解密

再次抓包时,发现传输过程存在加解密。

image

起初,使用阿雄教的方法,用 Xserver 去动态 hook 加解密(函数这个模块需要知道其加解密函数),可是却没有任何反应。

image

无能为力的我,便去求同事帮忙逆向一下,却是无果 /(ㄒoㄒ)/~~。

最后,在老大的指导下,请出了 Inspecakge

Inspeckage:是一个用于提供帮助Android应用程序动态分析的工具。通过对Android API的函数使用hook技术,帮助用户了解应用程序在运行时的行为。Gayhub地址:https://github.com/ac-pm/Inspeckage

操作如下:

1、勾选需要调试的APP

image

2、本机进行端口转发

adb connect 127.0.0.1:62001
adb forward tcp:8008 tcp:8008
image

Tips:
62001是夜神模拟器在本机的默认端口
而关于模拟器多开的问题,端口计算公式如下:

nox_i = 62024+i
例如:
nox_1 = 62025
nox_2 = 62026
nox_3 = 62027

当然,也可以通过命令行查看端口

image

3、打开Inspeckage

image

将上方的 OFF 勾选为 ON 就能成功 hook 函数了

4、配合Burp分析加解密

在抓取数据包后,我发现,POST的数据使用 0x1d 作为分隔符将其分为三段

image

多抓了几个数据包后,综合分析出,BurpSuite截获的POST数据包被 0x1d 字符分成了三段M1,M2M,M3,其中:

M2的动态生成过程对应 Inspeckage 中的 3,其使用了 AES CBC 模式进行加解密,且 IV 初始偏移量 为一个固定值(Inspecakge中能看到)。

M3可以看到通过X算法加密前,恰好为第二段的密钥(第三段的密钥是每次请求都会动态生成的,我并没有解密出第三段的加密方法,只能每次使用Inspeckage查看密钥,如果有大佬了解的,请不吝赐教)

image

而M1,使用了密钥+明文再经过一次 MD5 散列的处理,在后端做篡改的校验

image

流程图如下:

image.png
image.png

5、编写小脚本

分析出结果后,便能根据思路写一个脚本出来简化操作了

解密测试:

image

修改参数再加密的测试(此处进行越权测试):

image

可以顺利开始测试了,舒服了~~~~

0x04 后续思考

在后续进行测试的时候,由于每次请求都需要把密钥和密钥解密前的密文输入程序,导致整个测试流程较为繁琐,进度较慢。(由于不会写Burp插件,手法比较笨)

于是回想了下整个加解密流程,发现关键是:

1、密钥 Key1 是本地通过代码随机生成的,经过加密流程生成 PostData

2、服务器端经过代码解密出Key2 ,不和客户端生成的 Key1 做校验,只要能成功解密出数据就行。

也就是说,我们可以将 Key2 写为固定值,然后每次只需要输入需要加密的数据就行了。当然,解密过程还是需要我们输入 Key1 的。

于是我取了某次在 Inspeckage 中取到的 KeyX(Key) 写为定值,修改了原本的代码,简化了操作。

package com.encrypt;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder;
import org.apache.commons.codec.digest.DigestUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class AesCBC {

    //IV
    private static String InitV="XXXXXXXXXXXXXXXX";

    public void setKey(String key) {
        this.key = key;
    }
    public void setE(String e) {
        E = e;
    }
    public void setD(String d) {
        D = d;
    }
    public String getKey() {
        return key;
    }
    public String getE() {
        return E;
    }
    public String getD() {
        return D;
    }

    private String key="";
    private String E="";
    private String D="";

    /**
     * FUNCTION: ENCRYPT
     * */
    public String encrypt() throws Exception{
        Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec sks=new SecretKeySpec(getKey().getBytes(),"AES");
        IvParameterSpec iv=new IvParameterSpec(InitV.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE,sks,iv);
        byte[] ctext=cipher.doFinal(getE().getBytes());
        return new BASE64Encoder().encode(ctext);
    }

    /**
     * FUNCTION: DECRYPT
     * */
    public String decrypt() throws Exception{
        Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec sks=new SecretKeySpec(getKey().getBytes(),"AES");
        IvParameterSpec iv=new IvParameterSpec(InitV.getBytes());
        cipher.init(Cipher.DECRYPT_MODE,sks,iv);
        byte[] ptext=cipher.doFinal(new BASE64Decoder().decodeBuffer(getD()));
        return new String(ptext);
    }


    public static void main(String[] args) throws Exception {
        //开始
        System.out.println("--------------------~Strat~--------------------");
        System.out.println("***********************************************");
        AesCBC ac=new AesCBC();
        Scanner sc = new Scanner(System.in);

        while(true){
            System.out.print("Please Choice Mode【D(ecrypt)/E(ncrpty)】: ");
            String mode=sc.nextLine().toUpperCase().trim();

            if(mode.equals("D")){
                //-------解密-------
                //输入key
                System.out.println("--------------------AESKey~--------------------");
                System.out.print("Key: ");
                String key1=sc.nextLine().trim();
                ac.setKey(key1);
                System.out.print("CipherText: ");
                String D=sc.nextLine().trim();
                ac.setD(D);
                System.out.println("\n--------------------Decrypt~--------------------");
                String ptext=ac.decrypt();
                System.out.println("Decrypt Result: "+ptext);
                System.out.println("\n--------------------Finished--------------------\n\n");
            }else if(mode.equals("E")){
                //-------加密-------
                //key为定值
                System.out.println("--------------------AESKey~--------------------");
                String K="(HqttsSdHpJHTwkF7 , WUy7AghAGVmCHcdC78jW+wTbCi2SvJ7n3Ig6Mmbi+Qdkn5TL79ISZ8XnIA03KRDhtZmPltbJSCQaIw8TbkkzY7wK/SpUmK0+wZV4feYDf+4RIAHCQyA+bWXx1dvdJT00toNyrQSCuORsCh2VMusmJ6XhyI1MrYNDY3m+1poNqes=)";
                System.out.println("HqttsSdHpJHTwkF7\n");
                String str="";
                //正则匹配括号里的,并用逗号分割
                Pattern pattern = Pattern.compile("(?<=\\()[^\\)]+");
                Matcher matcher = pattern.matcher(K);
                while(matcher.find()){
                    str=matcher.group();
                }
                List<String> keys = Arrays.asList(str.split(" , "));
                String key1=keys.get(0);
                String key2=keys.get(1);
                ac.setKey(key1);
                System.out.print("PlainText: ");
                String E=sc.nextLine().trim();
                ac.setE(E);
                System.out.println("\n--------------------Encrypt~--------------------");
                String ctext=ac.encrypt();
                String hashStr=ac.getKey()+ac.getE();
                String hashedStr=DigestUtils.md5Hex(hashStr);
                char sp=29;
                System.out.println("BURP Result: "+ hashedStr+sp+ctext+sp+key2);
                System.out.println("\n--------------------Finished--------------------\n\n");
            }else if(mode.equals("0")){
                System.out.println("\n***********************************************");
                System.out.println("--------------------the End--------------------");
                System.exit(0);
            }

        }
    }
}

0x05 总结

通过本次APP的测试,总的来说是艰辛却收获了很多,但最后就结果来讲有两点不太完美的地方:

1、对于M3并未成功破解,否则可以写出更加精简的代码

2、由于不会写Burp插件,所以操作过程还是比较繁琐(下次一定学着写💪💪)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351