首页
论坛
课程
招聘
[原创]KCTF2020秋季赛 第四题 突破重围 writeup
2020-11-23 23:42 1102

[原创]KCTF2020秋季赛 第四题 突破重围 writeup

2020-11-23 23:42
1102

KCTF2020秋季赛 第四题 突破重围 wp

一道Android题

图片描述

Java层分析

1、com.kanxue.crackme.MainActivity

1
2
3
4
5
System.loadLibrary("crack");
 
init();  -> DexClassLoader /assets/b.txt
 
check() 反射执行 com.kanxue.crackme.Crack.check()

2、com.kanxue.crackme.MyCrack

1
2
3
4
5
public class MyCrack {
    public static String crypt = "otVvmpP4ZI58pqB26OTaYw==";
 
    public static native byte[] crackjni(byte[] bArr);
}

3、/assets/b.txt -> /assets/b.dex

com.kanxue.crackme.Crack.check

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public static boolean check(String content) {
        if (content == null || content.length() != 16) {
            return false;
        }
        Class MyCrackClass = null;
        Field cryptfield = null;
        byte[] result = crypt(content.getBytes());
        Method crackjni = null;
        try {
            MyCrackClass = Crack.class.getClassLoader().loadClass("com.kanxue.crackme.MyCrack");
            cryptfield = MyCrackClass.getDeclaredField("crypt");
            Method[] methods = MyCrackClass.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                if (methods[i].getName().equals("crackjni")) {
                    crackjni = methods[i];
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e2) {
            e2.printStackTrace();
        }
        if (crackjni != null) {
            try {
                result = (byte[]) crackjni.invoke(null, new Object[]{result});
            } catch (IllegalAccessException e3) {
                e3.printStackTrace();
            } catch (InvocationTargetException e4) {
                e4.printStackTrace();
            }
        }
        String finalresult = Base64.encodeToString(crypt(result), 0);
        String cryptcontent = "test";
        if (!(cryptfield == null || MyCrackClass == null)) {
            try {
                cryptcontent = (String) cryptfield.get(null);
            } catch (IllegalAccessException e5) {
                e5.printStackTrace();
            }
        }
        if (finalresult.equals(cryptcontent)) {
            return true;
        }
        return false;
    }

com.kanxue.crackme.Crack.crypt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public static byte[] crypt(byte[] b_data) {
        String mKkey = "kaokaonio";
        if (b_data == null) {
            return null;
        }
        int x = 0;
        int y = 0;
        byte[] b_key = mKkey.getBytes();
        byte[] key = new byte[256];
        for (int i = 0; i < 256; i++) {
            key[i] = (byte) i;
        }
        int index1 = 0;
        int index2 = 0;
        if (b_key == null || b_key.length == 0) {
            return null;
        }
        for (int i2 = 0; i2 < 256; i2++) {
            index2 = ((b_key[index1] & 255) + (key[i2] & 255) + index2) & 255;
            byte tmp = key[i2];
            key[i2] = key[index2];
            key[index2] = tmp;
            index1 = (index1 + 1) % b_key.length;
        }
        byte[] result = new byte[b_data.length];
        for (int i3 = 0; i3 < b_data.length; i3++) {
            x = (x + 1) & 255;
            y = ((key[x] & 255) + y) & 255;
            byte tmp2 = key[x];
            key[x] = key[y];
            key[y] = tmp2;
            result[i3] = (byte) (b_data[i3] ^ key[((key[x] & 255) + (key[y] & 255)) & 255]);
        }
        return result;
    }

对/assets/b.dex进行动态调试:

图片描述
找到cryptcontent的值为 "l+x7fKd2FBaaEY4NV4309A==\n"

 

图片描述
crypt中的mkey有改变 "kaokaonio" -> "keepGoing"

执行流程如下:

1
2
3
4
5
6
7
8
9
1. input 长度16
 
2. byte[] result = crypt(input) crypt方法中的 mkey=kaokaonio
 
3. crackjni_reslut = libcarack.so->crackjni(reslut) 对 reslut 进行加密
 
4. reslut = crypt(crackjni_reslut) crypt方法中的 mkey=keepGoing
 
5. base64(reslut) 与 cryptcontent = "l+x7fKd2FBaaEY4NV4309A==\n" 进行比较

Native层分析

1、libcrack.so 使用了 aes 加密

图片描述
S盒
图片描述

2、Java_com_kanxue_crackme_MyCrack_crackjni

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
int __fastcall Java_com_kanxue_crackme_MyCrack_crackjni(_JNIEnv *a1, int a2, int a3)
{
  v25 = sub_CF79ECBC((void *)0xFFFFFF9C, "/proc/self/maps", 0, 0); // frida anti
  if ( v25 >= 1 )
  {
    while ( sub_CF7A2168(v25, &s, 0x200) >= 1 )
    {
      if ( strstr(&s, "frida") )
        MEMORY[0] = 0x63;
      if ( sscanf(&s, "%x-%lx %4s %lx %*s %*s %s", &v31, &v30, &v33, &v32, &v39) == 5
        && v33 == 0x72
        && v34 == 0x70
        && !v32
        && strlen(&v39)
        && v39 != 0x5B
        && (unsigned int)(v30 - v31) > 0xF4240
        && !sub_CF7A22C0(&v39, ".oat")
        && sub_CF7A2228(v31) == 1
        && sub_CF7A20D2(v31, 0, v30, v30 >> 0x1F) == 1 )
      {
        MEMORY[0] = 0x63;
        break;
      }
    }
  }
    ......
 
  sub_CF79ED60(v5, "kaokaonikaokaoni", v6); // AES加密
 
    ......
 
  if ( dword_CF7D73E4 )
  {
    if ( dword_CF7D73D8 )
    {
      v12 = dword_CF7D73D8 + 0x16D3A6;
      v13 = *(_BYTE *)(dword_CF7D73D8 + 0x16D3A6);
      v14 = dword_CF7D73E4++;
      *(_BYTE *)(dword_CF7D73D8 + 0x16D3A6) = v13 + v14;
      *(_BYTE *)(v12 + 1) = 0x3D;
      v15 = sub_CF7A38C2(v29, "com/kanxue/crackme/MyCrack");
      v16 = sub_CF7A38EC(v29, v15, "crypt", "Ljava/lang/String;");
      v17 = sub_CF7A3934(v29, "ZmxhZ3RyeWFnYWluP30=");
      sub_CF7A3960(v29, v15, v16, v17);
    }
    ++dword_CF7D73E4;
  }
  else
  {
    if ( dword_CF7D73D8 )
    {
      v8 = dword_CF7D73D8 + 0x16D3A6;
      *(_BYTE *)(dword_CF7D73D8 + 0x16D3A6) = 0xD3u;              // "kaokaonio" -> "keepGoing"
      *(_BYTE *)(v8 + 1) = 0x3D;
      v9 = sub_CF7A38C2(v29, "com/kanxue/crackme/MyCrack");
      v10 = sub_CF7A38EC(v29, v9, "crypt", "Ljava/lang/String;");                                    
      v11 = sub_CF7A3934(v29, "l+x7fKd2FBaaEY4NV4309A==\n"); // "otVvmpP4ZI58pqB26OTaYw==" -> "l+x7fKd2FBaaEY4NV4309A=="   
      sub_CF7A3960(v29, v9, v10, v11);
    }
    ++dword_CF7D73E4;
  }
 
}

AES扩展密钥算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int sub_CF79EDE8()
{
  unsigned __int8 v0; // ST04_1
  unsigned int j; // [sp+8h] [bp-18h]
  unsigned int i; // [sp+Ch] [bp-14h]
  unsigned __int8 v4; // [sp+10h] [bp-10h]
  unsigned __int8 v5; // [sp+11h] [bp-Fh]
  unsigned __int8 v6; // [sp+12h] [bp-Eh]
  unsigned __int8 v7; // [sp+13h] [bp-Dh]
 
  for ( i = 0; i <= 3; ++i )
  {
    byte_CF7B6318[4 * i] = *(_BYTE *)(dword_CF7B6314 + 4 * i);
    byte_CF7B6318[4 * i + 1] = *(_BYTE *)(dword_CF7B6314 + 4 * i + 1);
    byte_CF7B6318[4 * i + 2] = *(_BYTE *)(dword_CF7B6314 + 4 * i + 2);
    byte_CF7B6318[4 * i + 3] = *(_BYTE *)(dword_CF7B6314 + 4 * i + 3);
  }
  while ( i <= 0x2B )
  {
    for ( j = 0; j <= 3; ++j )
      *(&v4 + j) = byte_CF7B6318[4 * i - 4 + j];
    if ( !((unsigned __int8)i << 0x1E) )
    {
      v0 = v4;
      v4 = v5;
      v5 = v6;
      v6 = v7;
      v7 = v0;
      v4 = sub_CF79F084(v4);
      v5 = sub_CF79F084(v5);
      v6 = sub_CF79F084(v6);
      v7 = sub_CF79F084(v7);
      v4 ^= byte_CF7AFE5C[i >> 2];
    }
    byte_CF7B6318[4 * i] = byte_CF7B6318[4 * i - 0x10] ^ v4;
    byte_CF7B6318[4 * i + 1] = byte_CF7B6318[4 * i - 0xF] ^ v5;
    byte_CF7B6318[4 * i + 2] = byte_CF7B6318[4 * i - 0xE] ^ v6;
    byte_CF7B6318[4 * i + 3] = byte_CF7B6318[4 * i - 0xD] ^ v7;
    ++i;
  }
  return _stack_chk_guard;
}

图片描述

获取flag

1、"l+x7fKd2FBaaEY4NV4309A==" -> bytes -> base64 -> crypto (mKey=keepGoing)

1
40, -128, -114, -30, 10, -79, 122, 37, -62, 22, 120, 86, 58, 74, 127, -85

2、AES解密
图片描述
3、解密字符串
crypto (mKey=kaokaonio)
图片描述

 

图片描述


看雪学院推出的专业资质证书《看雪安卓应用安全能力认证 v1.0》(中级和高级)!

最后于 2020-11-24 07:56 被neilwu编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回