[2022HWS硬件安全冬令营 X DASCTF Jan][CRYPTO] Accelerate your time

[CRYPTO] Accelerate your time


flag{80d0169d22da3c35}

Android 逆向分析

  1. 拿到apk首先解压反编译dex,此步骤省略。

    image

    其登录流程很简单,也可以从源码轻易的读出来:首先验证用户名和密码,接下来验证时间。首先对时间进行md5编码,之后加上用户名密码再进行一次编码然后对产生的第二个信息摘要进行判断。首先要解决登陆的账户问题。(笔者用大量的实验证实了乱填账户密码是不对的)

  2. 首先破解账户和密码
    然后与不出所料我试了好长时间差点开始穷举的时候,我看到了data模块。其中含有一个关键的,看上去很可疑的一段代码:

    image

    public final Result<LoggedInUser> login(String paramString1, String paramString2, String paramString3)
      {
        Intrinsics.checkParameterIsNotNull(paramString1, "username");
        Intrinsics.checkParameterIsNotNull(paramString2, "password");
        Intrinsics.checkParameterIsNotNull(paramString3, "trandmark");
        //...
        if (Intrinsics.areEqual(paramString1, paramString3))
        {
          paramString3 = new int[7];
          int i = 0;
          int k;
          for (int j = 0; ; j++)
          {
            k = i;
            if (j > 6)
              break;
            paramString3[j] = (paramString1.charAt(j) ^ paramString2.charAt(j));
          }
          while (k <= 6)
          {
            if (new int[] { 6, 28, 1, 19, 27, 5, 29 }[k] != paramString3[k])
              break;
            if (k == 6)
                //return success..
    

    随即可以先把这部分逆向出来。这段代码的逻辑很简单,就是一个简单的异或加密。只是这里的trandmark字串的值要从反编译的包中找到,是Android。注意到满足success的返回值代码段上的if构成的断言,这暗示我们用户名就是Android,原因是areEqual(paramString1, paramString3),即trandmarkusername的值相同。

    写一个小脚本就可以获得password:

    int main(int argc, char** argv)
    {
    	int code[] = { 6, 28, 1, 19, 27, 5, 29 };
    	char trandmark[] = { "Android" };
    	for (int i = 0; i < 7; i++)
    	{
    		printf("%d | %c\n", code[i] ^ trandmark[i], code[i] ^ trandmark[i]);
    		/* 输出
    		*	71 | G
    			114 | r
    			101 | e
    			97 | a
    			116 | t
    			108 | l
    			121 | y
    		*/
    	}
    	return 0;
    }
    

    那么知道了password字段的值是Greatly。实验表明这个登录凭据是被接受的,因此这里我们猜对了。(事实上笔者没有那么幸运,我只是把整个com.flag.reverse.c的源码都大致看了一遍,找到了调用栈,这才顺藤摸瓜解出来了)

  3. 暴力穷举时间。这里的时间是通过两次md5加密生成的,换句话说,由于可能加了盐,因此碰撞失效。观察关键代码:

    private final void updateUiWithUser(LoggedInUserView paramLoggedInUserView)
      {
        Intrinsics.checkExpressionValueIsNotNull(getString(2131558465), "getString(R.string.welcome)");
        paramLoggedInUserView.getDisplayName();
        paramLoggedInUserView = new StringBuilder();
        paramLoggedInUserView.append(String.valueOf(this.hour));
        paramLoggedInUserView.append(String.valueOf(this.minute));
        paramLoggedInUserView.append(String.valueOf(this.second));
        paramLoggedInUserView = LoginActivityKt.encodeMD5(paramLoggedInUserView.toString());
        StringBuilder localStringBuilder = new StringBuilder();
        localStringBuilder.append("flag{");
        localStringBuilder.append(paramLoggedInUserView);
        localStringBuilder.append("}");
        localStringBuilder.append((EditText)_$_findCachedViewById(R.id.username));
        localStringBuilder.append((EditText)_$_findCachedViewById(R.id.password));
        if (Intrinsics.areEqual(LoginActivityKt.encodeMD5(localStringBuilder.toString()), getString(2131558446)))
          Toast.makeText(getApplicationContext(), (CharSequence)"Congulations, You got the secert code", 1).show();
        else
          Toast.makeText(getApplicationContext(), (CharSequence)"Yeah, you are logged in but the code is still hidden under the mist", 1).show();
      }
    

    前面首先通过控件Calender获取当前的时间,并且不补零,24小时制生成一个时间拼接字符串计算md5。然后使用

        localStringBuilder.append("flag{");
        localStringBuilder.append(paramLoggedInUserView);
        localStringBuilder.append("}");
        localStringBuilder.append((EditText)_$_findCachedViewById(R.id.username));
        localStringBuilder.append((EditText)_$_findCachedViewById(R.id.password));
    

    进行拼接。这里前三行很好懂,后两行事实上进行了一定的强制转换。_$_findCachedViewById可以说是一个取代findById的语法糖,他获取一个id并且返回一个View。这里的EditText强制转换读取了这个控件里的值,并且接到字符串的尾部,像flag{xxx}AndroidGreatly一样

    因此知道了基本的操作,又知道了md5,由于穷举的成本只有时间,也就是24\*60\*60 = 145440次,因此是可以接受的,甚至可以加一个好看的格式化。脚本如下:

    import hashlib
    def md5value(key):
        input_name = hashlib.md5()
        input_name.update(key.encode())
        #input_name.update(key.encode("utf-8"))
        return (input_name.hexdigest())[8:24].lower()
    for i in range(0,24,1):
        for j in range(0,60,1):
            for k in range(0,60,1):
                targetstr = str(i)+str(j) +str(k)
                str1 = md5value(targetstr)
                str2 = 'flag{' + str1  + '}' + 'AndroidGreatly'
                #Username = Android
                #Password = Greatly
                str3 = md5value(str2)
                print(targetstr,' # ',str1,' # ',str2,' # ',str3)
                if(str3 == '1a9852e856816224'):
                    print("found time:" +targetstr)
                    input()
               
    

    最终生成

    image

    然后提交对应的时间加密的flag即可

posted @ 2022-01-25 00:07  二氢茉莉酮酸甲酯  阅读(227)  评论(0编辑  收藏  举报