Bootstrap

攻防世界XCTF-MOBILE入门9题解题报告

说实话,这几天被逆向的恐怖思维,深深的吓着了,真的要抱腿腿了,叫我失眠了好几晚,我觉得逆向分析是CTF中最难的,求腿腿指点迷津啊,我决定不闷头自己研究了。

第一题:app1

解题报告:在MUMU模拟器中安装运行

通过dex2jar和jd-gui,逆向出class文件,然后直接进Main函数

在BuildConfig.class文件中可以轻松的拿到解密的关键字段

通过简单的Python编程,成功拿到flag

第二题:app2

解题报告:在MUMU模拟器中安装运行

在JEB中打开,JEB真的没有排面啊

进入SecondActivity类中,寻找关键方法onCreate()

使用IDA打开Lib库中的.so文件,找到关键函数doRawData的实现

大概的意思就是使用AES对咱们的字符串进行加密,使用的密钥是thisisatestkey==,恰好使得结果等于VEIzd/V2UPYNdn/bxH3Xig==就可以了。

输入aimage/tencent结果发现还是腾讯等你哟 Waiting for you,被戏耍了,并不是正确的flag

于是通过dex2jar和jd-gui,逆向出class文件,发现第一个FileDataActivity类,里面也有一个奇怪的加密字符串

将上面的加密结果改成9YuQ2dk8CSaCe7DTAmaqAA== ,再次运行,成功拿到flag

第三题:app3

解题报告:

下载附件,发现是.ab文件,需要转换为.tar文件

解压.tar这个宝藏文件,得到了一个apk安装包

把apk拖进jeb,进入主程序,发现可疑处

第一步:分析这个类A

第二步:分析这个类B

解密得到关键密码:ae56f99

查看一下加密的版本3.4.0

去找一下3.4.0版本,然后编译安装一下sqlcipher,make不成功

https://github.com/sqlcipher/sqlcipher/releases

于是用windows版本的3.0.1编译好的可执行程序,只要大版本一样就行了

https://github.com/CovenantEyes/sqlcipher-windows/releases

sqlite> PRAGMA key = "ae56f99";
sqlite> ATTACH DATABASE "ailx10.db" AS plaintext KEY "";
sqlite> SELECT sqlcipher_export("plaintext");
sqlite> DETACH DATABASE plaintext;

最后,解密这个Base64编码就搞定了

第四题:easy-apk

解题报告:

安装运行,看不出来啥

扔进JEB里面,看上去逻辑很简单的亚子。

核心逻辑就是怎么逆向计算Base64New

发现这个JEB反编译出来或的操作很难读啊,只好转到dex2jar来试一试

反编译出来的结果让我心碎,一毛一样的亚,菜就是原罪,只好硬着皮头逆向运算了=。=

这个或运算太骚了吧,这玩意咋逆运算啊?失眠了。这题最难的地方就是异或怎么处理,最后来一个逐项暴力破解版,大约5秒,效果极佳。这是Base64的通用做法,记好哟~

最后一部分的=号暴力破解:大约1秒,凑一起就完事了。

最后我花了一个草图,实际上这题就是Base64换了一个表,通过不停的或运算,实际上还是那一堆数字,0101并没有发生任何改变,因此直接写一个Base64的逆过程就完事了。

逆向核心代码:

package c4;

public class Base64New {
    private static char[] Base64ByteToStr = null;
    private static final int RANGE = 255;
    private static byte[] StrToBase64Byte;

    static {
        Base64New.Base64ByteToStr = new char[]{'v', 'w', 'x', 'r', 's', 't', 'u', 'o', 'p', 'q', '3', '4', '5', '6', '7', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'y', 'z', '0', '1', '2', 'P', 'Q', 'R', 'S', 'T', 'K', 'L', 'M', 'N', 'O', 'Z', 'a', 'b', 'c', 'd', 'U', 'V', 'W', 'X', 'Y', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', '8', '9', '+', '/'};
        Base64New.StrToBase64Byte = new byte[128];
    }

    public Base64New() {
        super();
    }

    public byte getIndex(char x)
    {
        byte index = -1;
        String talbe = new String(Base64New.Base64ByteToStr);
        if(x != '=') {
            index = (byte) talbe.indexOf(x);
        }
        else {
            index = 0;
        }
        return index;
    }

    public void Base64Decode() {
        String enflag = "5rFf7E2K6rqN7Hpiyush7E6S5fJg6rsi5NBf6NGT5rs=";
        String flag = "";
        String flag_temp = "";
        for(int i = 0;i < enflag.length();i+=4)
        {
            String enf = enflag.substring(i,i+4);
            byte flag1 = (byte)(((getIndex(enf.charAt(0)) & 255) << 2 | ((getIndex(enf.charAt(1)) & 255) >>> 4)));
            byte flag2 = (byte)(((getIndex(enf.charAt(1)) & 255) << 4 | ((getIndex(enf.charAt(2)) & 255) >>> 2)));
            byte flag3 = (byte)(((getIndex(enf.charAt(2)) & 255) << 6 | ((getIndex(enf.charAt(3)) & 255))));

            flag_temp = "" + (char)flag1 + (char)flag2 + (char)flag3;
            flag += flag_temp;
        }
        System.out.println(flag);
        return;
    }

    public String Base64Encode(byte[] arg9) {
        int v7 = 3;
        StringBuilder v3 = new StringBuilder();
        int v1;
        for(v1 = 0; v1 <= arg9.length - 1; v1 += 3) {
            byte[] v0 = new byte[4];
            byte v4 = 0;
            int v2;
            for(v2 = 0; v2 <= 2; ++v2) {
                if(v1 + v2 <= arg9.length - 1) {
                    v0[v2] = (byte)((arg9[v1 + v2] & 255) >>> (v2 * 2 + 2) | v4);
                    v4 = ((byte)(((arg9[v1 + v2] & 255) << (2 - v2) * 2 + 2 & 255) >>> 2));
                }
                else {
                    v0[v2] = v4;
                    v4 = 64;
                }
            }

            v0[v7] = v4;
            for(v2 = 0; v2 <= v7; ++v2) {
                if(v0[v2] <= 63) {
                    v3.append(Base64New.Base64ByteToStr[v0[v2]]);
                }
                else {
                    v3.append('=');
                }
            }
        }
        return v3.toString();
    }
}

第五题:easy-java

解题报告:

拖进JEB中找到核心逻辑,这个a方法是关键

进入a方法里面,发现调用的是b方法,可以看到提交的字符格式了吧。然后就是重头戏了,有两个类a和b,经过一些列的计算,最后结果等于wigwrkaugala就可以了。

flag{      }

整体思路:这是一个错误思路,读者可以直接忽略,为了记录我的愚蠢的。

  • 首先用第一个参数(flag),调用B类的a方法,将结果传递给A类的a方法,写入v3中
  • 然后用B类的b方法对25取余数,得到v6
  • 如果v6大于等于1,并且大于v1,那么v1++,否则v0++
  • 往复循环,处理完整个flag

B类的a方法:B类的b中包含flag的话,找到下标数字,然后在B类的a中到找到相同的数字,输出移动了几次。比如字母a,在B类的b中的下标是0,在B类的a中0的位置是10,那么输出10

A类的a方法:A类的a中找到这个参数的下标,然后输出A类的b中的该下标的字母。比如10在A类的a的下标是14,那么输出A类的b[14],也就是输出字母n

然后我以为我把所有的字母从明文到密文的转换,搞成一个转换字典,然后根据密文去反查明文,岂不是美滋滋,事实证明这个思路走不通。因为明文aa映射到密码并不是xx,而是xy,导致了这个思路破碎,只能硬着皮头反逻辑,这个没有经过老师点拨训练,真的很痛苦。

偷个懒,来一次暴力破解,

flag如果是4位,需要尝试45万次

flag如果是8位,需要尝试2000亿次

额,实际flag是12位,暴力美学,一点都不美丽了,弃坑,CTF没有暴力破解。

第二次解题思路:读者继续从这里开始。

先搞懂正向计算过程,再去分析逆向计算过程。

  • 正向计算0层架构:调用B的a方法,再调用A的a方法
  • B的a方法:参数在B的b中索引,在B的a中索引,再调用B的c方法
  • B的c方法:B的a数组,B的b数组循环移动一位,123变成231
  • A的a方法:参数在A的a中索引,再调用A的b中索引值

逆向过程如下:

  • A的a方法:参数在A的b中索引,在A的a中索引值
  • B的a方法:参数在B的a中索引值,在B的b中索引值,再调用B的c方法
  • B的c方法:和正向操作一样,保持操作的表是一样的

那么现在思路清晰了,就很简单了:

其中A的a方法的逆运算如下:

B的a方法逆运算如下:

在这里插入图片描述

第六题:easy-jni

解题报告:

仍进JEB中,发现问题的关键是:

  • new a() 这个A类的a()方法,对输入进行处理
  • native中的ncheack()方法,检测是否相等

关键问题1:对类A对a方法进行分析

关键问题2:解压apk包,把lib下的.so文件拖进IDA32中,对库函数分析

正向思路整理:

  • 对输入的flag进行Base64换表计算B64Encode
  • 对输入的B64Encode进行变换得到加密的flag

逆向思路整理:

  • 对加密的flag进行逆向变换得到B64Encode
  • 对B64Encode进行Decode计算得到flag

编程就非常简单了:

第一步:交换操作

第二步:Base64Decode操作

第七题:easy-so

解题报告:

扔进JEB中,发现只要经过cyberpeace.CheckString,计算结果等于1就拿到flag

而最关键的cyberpeace.CheckString在lib库中,将apk解压,把里面的.so库文件拖到IDA中,发现逻辑非常简单,和上面一题的交换部分一样。

直接利用上一题的代码改改,就拿到flag,有点送分的意思。

第八题:Ph0en1x-100

解题报告:

仍进JEB中,需要注意3个地方,一个一个分析

第一个注意的地方:getSecret

发现等号两边都要经过这个消息摘要函数的计算,那么只要比较输入值相等就可以了。

第二个注意的地方:getFlag

第三个注意的地方:encrypt

最后,很容易的写出逆向代码,直接拿到flag

第九题:RememberOther

解题报告:

扔进JEB中看看里面的逻辑:

进入checkSN,拿到flag有2种选择,要么什么也不要输入,要么输入的用户名经过消息摘要算法等于注册码,所以我们什么也不输入就能拿到flag

在App里面点击注册,一串md5一闪而过,在配置文件里面,咱们可以找到它。

找一个在线MD5解密网站,扔进去拿到flag:

结合令人无语的脑洞,末尾加一个“ANDROID”字符串,拼成最终的flag

YOU_KNOW_ANDROID

至此,基础题目都做完了,撒花花~

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

;