首页
社区
课程
招聘
[原创]KCTF2021 春季赛 第四题 英雄救美 WP
2021-5-15 01:23 5564

[原创]KCTF2021 春季赛 第四题 英雄救美 WP

2021-5-15 01:23
5564

main函数伪代码如下:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int len; // kr00_4
  int v4; // ecx
  char *v5; // esi
  int v6; // edi
  void (*v8)(void); // [esp+Ch] [ebp-2CCh]
  int v9[22]; // [esp+10h] [ebp-2C8h] BYREF
  int solve[128]; // [esp+68h] [ebp-270h] BYREF
  __int128 v11; // [esp+268h] [ebp-70h] BYREF
  char serial[92]; // [esp+278h] [ebp-60h] BYREF
 
  printf("\t\t\t看雪CTF大赛\r\n");
  printf("\t\t祝愿看雪CTF大赛越办越好\r\n");
  printf("Serial: ");
  scanf_s("%s", serial);
  len = strlen(serial);
  // 先检查序列号是否合法,检测合法则转换成数独的解,然后开始填数独
  if ( len <= 64 && serial2solve(len, serial, solve) == 1 && sudoku((int)solve, len - 9) == 1 )
  {
    v11 = 0i64;
    memset(v9, 0, sizeof(v9));
    v9[5] = 0;
    v9[4] = 0;
    v9[0] = 0x67452301;
    v9[1] = 0xEFCDAB89;
    v9[2] = 0x98BADCFE;
    v9[3] = 0x10325476;
    sub_4014E0((int)serial, (int)v9, len);      // 计算serial的hash,解密shellcode
    sub_4015B0((int)&v11, (int)v9);
    sub_401ED0(v4, (unsigned __int8 *)&v11);
    v8 = (void (*)(void))VirtualAlloc(0, 0x620u, 0x1000u, 0x40u);
    v5 = (char *)v8;
    v6 = 98;
    do
    {
      *(__m128i *)v5 = _mm_loadu_si128((const __m128i *)&v5[&unk_4181A0 - (_UNKNOWN *)v8]);
      sub_4028B0((int)solve, v5);
      v5 += 16;
      --v6;
    }
    while ( v6 );
    v8();
  }
  return 0;
}

从sudoku函数内可以提取到数独

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0,4,0,7,0,0,0,0,0
9,2,0,0,0,0,6,0,7
8,3,0,0,0,5,4,0,0
0,1,0,0,0,3,0,0,0
0,0,0,2,0,1,0,0,0
0,0,0,5,0,0,0,4,0
0,0,4,9,0,0,0,7,1
3,0,5,0,0,0,0,9,4
0,0,0,0,0,8,0,6,0
//懒得解(不会解)数独,直接求助度娘解出来
5,4,6,7,1,9,2,3,8
9,2,1,8,3,4,6,5,7
8,3,7,6,2,5,4,1,9
7,1,8,4,6,3,9,2,5
4,5,3,2,9,1,7,8,6
6,9,2,5,8,7,1,4,3
2,8,4,9,5,6,3,7,1
3,6,5,1,7,2,8,9,4
1,7,9,3,4,8,5,6,2

sudoku函数只在数值为0处填充解,所以把0处的解提取出来

[(5, 6, 1, 9, 2, 3, 8), (1, 8, 3, 4, 5), (7, 6, 2, 1, 9), (7, 8, 4, 6, 9, 2, 5), (4, 5, 3, 9, 7, 8, 6), (6, 9, 2, 8, 7, 1, 3), (2, 8, 5, 6, 3), (6, 1, 7, 2, 8), (1, 7, 9, 3, 4, 5, 2)]

再看serial2solve函数

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
int __usercall serial2solve@<eax>(int len@<edx>, char *serial@<ecx>, int *solve)
{
  int decnum; // ebx
  int v4; // esi
  unsigned int y; // edi
  char chr; // al
  signed int v7; // ecx
  int v9; // ecx
  char *v10; // [esp+0h] [ebp-64h]
  int v11; // [esp+4h] [ebp-60h]
  __int128 strtable[5]; // [esp+Ch] [ebp-58h]
  char v14; // [esp+5Ch] [ebp-8h]
 
  strtable[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_416280);
  decnum = 0;
  strtable[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_4162A0);
  v4 = 0;
  v11 = len;
  v10 = serial;
  v14 = 113;
  strtable[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_416270);
  strtable[3] = (__int128)_mm_load_si128((const __m128i *)&xmmword_416290);
  strtable[4] = (__int128)_mm_load_si128((const __m128i *)&xmmword_416260);
  if ( len <= 0 )
    return 1;
  y = 0;
  while ( 1 )
  {
    chr = serial[v4];
    if ( chr > '0' && chr <= '9' )
      break;
    v7 = y;                                     // 可以当成strtable的纵坐标
    if ( y >= 81 )
      return 0;
    while ( chr != *((_BYTE *)strtable + v7) )
    {
      if ( (unsigned int)++v7 >= 81 )
        return 0;
    }
    v9 = v7 % 9 + 1;                            // 将strtable的横坐标+1,写到数独的解
    if ( v9 == -1 )
      return 0;
    *solve = v9;
    serial = v10;
    ++decnum;
    ++solve;
    len = v11;
LABEL_13:
    if ( ++v4 >= len )
      return 1;
  }
  if ( decnum + chr == '9' )                    // 猜测serial每填满一行数独后就跟一位数字表示没填到的数独的个数
  {
    decnum = 0;
    y += 9;
    goto LABEL_13;
  }
  return -1;
}

清楚序列号转数独解的过程后,撸一份python解出flag即可

1
2
3
4
5
6
7
8
9
resultarr=[(5, 6, 1, 9, 2, 3, 8), (1, 8, 3, 4, 5), (7, 6, 2, 1, 9), (7, 8, 4, 6, 9, 2, 5), (4, 5, 3, 9, 7, 8, 6), (6, 9, 2, 8, 7, 1, 3), (2, 8, 5, 6, 3), (6, 1, 7, 2, 8), (1, 7, 9, 3, 4, 5, 2)]
table="""$BPV:ubfYp}]DtN>aT^MGmJQ#*Hr`O'wjic0!hdy{oZz-@n+?&%s_/g<e[W)XUxRFSLRA;.l=CEkvK-(q"""
flag=''
for i in range(len(resultarr)):
    for j in range(len(resultarr[i])):
        flag+=table[9*i+resultarr[i][j]-1]
        if len(resultarr[i])-1==j:
            flag+=chr(0x39-j-1)
print(flag)

运行得到flag(下面整行都是)

:u$YBPf2pa]Dt4#QM^H4ic'j0`w2y{d-Zzo2%/n_s@+2<UW)e4AR;F.4=-qEkvC2

吐槽:目前的flag都不是KCTF{}格式


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回