首页
论坛
课程
招聘
[原创]KCTF 2021秋季赛 第七题 声名远扬
2021-12-3 11:54 17315

[原创]KCTF 2021秋季赛 第七题 声名远扬

2021-12-3 11:54
17315

很久没在看雪写东西了,题目本身不难,晚上抽了点时间看看,最后想的是尽量用工具去做,第一次写WP,简单记录下。

起点

  • 32位,无保护,ida搜索字符串没有看到错误输出,没有明显的函数处理过程
  • 发现Duilib写的,下载源码,编译lib,https://github.com/duilib/duilib,pct,sigmake制作签名文件,应用之~
  • 识别了500多个还可以了,阅读源码,跟踪按钮事件,CNotifyPump::NotifyPump->CNotifyPump::LoopDispatch,进而跟踪到按钮消息处理函数sub_89D2D0。
  • 分析出大致流程如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int __userpurge sub_89D2D0@<eax>(int a1@<ecx>, int a2@<ebx>, int a3@<edi>, int a4@<esi>, int a5)
    {
    v13 = a1;
    result = a1;
    if ( *(_DWORD *)(a1 + 1384) == *(_DWORD *)(a5 + 136) )
    {
      //...
      v10 = sub_89E530(a1a, a2a);                    //编码函数
      //...
      sub_89D600(&v15, a2, a3, a4, v7, (int)v16);    //校验函数
      (*(void (__thiscall **)(_DWORD, char *))(**(_DWORD **)(v13 + 1388) + 44))(*(_DWORD *)(v13 + 1388), v16);    //结果提示
    }
    return result;
    }

分析

  • 关键代码1(编码函数),一个简单的类似base64的编码,这里我想的是直接通过ida脚本去把表提出来。
    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
    for ( i = 0; ; i += v11 )
    {
      v2 = get_len(a2);
      v11 = v2 - i;
      v27 = '@';
      Src = *(_BYTE *)sub_89E970(v30, (int)&v27);    //从编码表中替换
      v26 = 64;
      v32 = *(_BYTE *)sub_89E970(v30, (int)&v26);
      v25 = 64;
      v33 = *(_BYTE *)sub_89E970(v30, (int)&v25);
      v24 = 0x40;
      v34 = *(_BYTE *)sub_89E970(v30, (int)&v24);
      if ( !v11 )
        break;
      if ( v11 == 1 )
      {
        v23 = ((int)*(unsigned __int8 *)char_at(i) >> 2) & 0x3F;    //char_at是std::string.at
        Src = *(_BYTE *)sub_89E970(v30, (int)&v23);
        v22 = (16 * *(_BYTE *)char_at(i)) & 0x3F;
        v32 = *(_BYTE *)sub_89E970(v30, (int)&v22);
        v21 = 64;
        v33 = *(_BYTE *)sub_89E970(v30, (int)&v21);
        v20 = 64;
        v34 = *(_BYTE *)sub_89E970(v30, (int)&v20);
      }
      else if ( v11 == 2 )
      {
        v19 = ((int)*(unsigned __int8 *)char_at(i) >> 2) & 0x3F;
        Src = *(_BYTE *)sub_89E970(v30, (int)&v19);
        v3 = 16 * *(_BYTE *)char_at(i);
        v18 = (((int)*(unsigned __int8 *)char_at(i + 1) >> 4) | v3) & 0x3F;
        v32 = *(_BYTE *)sub_89E970(v30, (int)&v18);
        v17 = (4 * *(_BYTE *)char_at(i + 1)) & 0x3F;
        v33 = *(_BYTE *)sub_89E970(v30, (int)&v17);
        v16 = 64;
        v34 = *(_BYTE *)sub_89E970(v30, (int)&v16);
      }
      else
      {
        v15 = ((int)*(unsigned __int8 *)char_at(i) >> 2) & 0x3F;
        Src = *(_BYTE *)sub_89E970(v30, (int)&v15);
        v4 = (16 * *(_BYTE *)char_at(i)) & 0x3F;
        v14 = (((int)*(unsigned __int8 *)char_at(i + 1) >> 4) & 0x3F | v4) & 0x3F;
        v32 = *(_BYTE *)sub_89E970(v30, (int)&v14);
        v5 = 4 * *(_BYTE *)char_at(i + 1);
        v13 = (((int)*(unsigned __int8 *)char_at(i + 2) >> 6) | v5) & 0x3F;
        v33 = *(_BYTE *)sub_89E970(v30, (int)&v13);
        v12 = *(_BYTE *)char_at(i + 2) & 0x3F;
        v34 = *(_BYTE *)sub_89E970(v30, (int)&v12);
        v11 = 3;
      }
  • 写个调试脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//大致流程是这样,不过调试的时候连续执行step_over我再ida里一直没成功,没时间看了,有知道的兄弟请告知.
//因为本身循环次数不多,通过条件断点输出和多次run脚本把表打了出来
import time
for i in range(64):
    edx = idc.get_reg_value("EBP")-0x39
    idc.patch_dbg_byte(edx,i)
    idc.set_reg_value(0x0089E5AF,'EIP')
    idaapi.step_over()
    idaapi.step_over()
    idaapi.step_over()
    idaapi.step_over()
    time.sleep(0.1)
    eax = idc.get_reg_value("EAX")
    code = idc.read_dbg_byte(eax)
    print(hex(code), end='')
//编码表[0x70,0x72,0x76,0x6f,0x39,0x43,0x48,0x53,0x4a,0x4f,0x63,0x50,0x49,0x62,0x36,0x78,0x52,0x56,0x55,0x58,0x51,0x7a,0x30,0x71,0x42,0x47,0x44,0x45,0x37,0x32,0x4c,0x4e,0x5a,0x64,0x75,0x61,0x65,0x66,0x59,0x54,0x35,0x4b,0x5f,0x38,0x2d,0x34,0x46,0x41,0x68,0x6c,0x69,0x6d,0x6a,0x6b,0x6e,0x67,0x74,0x31,0x79,0x4d,0x57,0x73,0x33,0x77,0x21]
  • 关键代码2(校验函数),0089D8A2:call fword ptr [ebp+var_C] 校验代码放在了x64里执行,所以直接上windbg
  • 看了看代码,一个简单的比较,bp 00895606 下断点,da rbp-30打印输出,直接拿最后的编码比较
  • GYldGg-iIoJlPX9hPXpjPqfdEY21B01TBTzeGqfKNR!!

求解

  • 写了个简单的z3求解
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
64
from z3 import *
table = [0x70,0x72,0x76,0x6f,0x39,0x43,0x48,0x53,0x4a,0x4f,0x63,0x50,0x49,0x62,0x36,0x78,0x52,0x56,0x55,0x58,0x51,0x7a,0x30,0x71,0x42,0x47,0x44,0x45,0x37,0x32,0x4c,0x4e,0x5a,0x64,0x75,0x61,0x65,0x66,0x59,0x54,0x35,0x4b,0x5f,0x38,0x2d,0x34,0x46,0x41,0x68,0x6c,0x69,0x6d,0x6a,0x6b,0x6e,0x67,0x74,0x31,0x79,0x4d,0x57,0x73,0x33,0x77,0x21]
A = Array('A', IntSort(), IntSort())
i = 0
for elem in table:
  A = Store(A, i, elem)
  i = i + 1
permute = lambda k:Select(A, BV2Int(k))
flag_len = 31
x = [BitVec('u%d'%i,8) for i in range(x_len)]
s = Solver()
 
i = 0
v = 0
xxx = []
while True:
    k = x_len - i
    if (k == 0):
        break
    if k == 1:
        pos = (x[i] >> 2) & 0x3f
        m0 = permute(pos)
        pos = (16 * x[i]) & 0x3f
        m1 = permute(pos)
        pos = BitVecVal(0x40, 8)
        m2 = permute(pos)
        m3 = permute(pos)
    elif k == 2:
        pos = (x[i] >> 2) & 0x3f
        m0 = permute(pos)
        pos = ((x[i+1] >> 4) | (16 * x[i])) & 0x3f
        m1 = permute(pos)
        pos = (4 * x[i+1]) & 0x3f
        m2 = permute(pos)   
        pos = BitVecVal(0x40, 8)
        m3 = permute(pos)
    else:
        pos = (x[i] >> 2) & 0x3f
        m0 = permute(pos)
        pos = ((x[i+1] >> 4) & 0x3f | (16 * x[i])) & 0x3f
        m1 = permute(pos)      
        pos = ((x[i+2] >> 6) | (4 * x[i+1])) & 0x3f
        m2 = permute(pos)
        pos = x[i+2] & 0x3f
        m3 = permute(pos)
        k = 3
    xxx += [m0,m1,m2,m3]
    i += k
 
cip = 'GYldGg-iIoJlPX9hPXpjPqfdEY21B01TBTzeGqfKNR!!'
j = 0
for t in xxx:
    s.add(t==ord(cip[j]))
    j+=1
res = s.check()
if res == z3.sat:
    print(s.model())
    model = s.model()
    flag = ''
    for i in range(0,flag_len):
        flag += chr(model[x[i]].as_long().real)
    print(flag)
else:
    print('oh,no')
  • 最后得到:flag{2021-10-04-yangyangbudeyi}

【公告】看雪招聘大学实习生!看雪20年安全圈的口碑,助你快速成长!

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