首页
论坛
专栏
课程

[原创] CTF2019 Q1 第一题write up

2019-3-10 13:04 516

[原创] CTF2019 Q1 第一题write up

2019-3-10 13:04
516

环境配置

系统 : Windows xp
程序 : 流浪者
要求 : 输入口令
使用工具 :IDA pro / Ollydbg / peid

开始分析

首先将程序拖入peid中查看下,程序提示:
Microsoft Visual C++ 6.0

 

看来这就是一个传统的CrackMe程序,输入flag即可夺旗成功。我们直接用od附加程序,然后用中文搜索引擎插件查看字符串信息:

中文搜索引擎
地址       反汇编                                    文本字符串
00401059   mov dword ptr ds:[eax],cm.00403240        X@
004010F9   mov ecx,cm.00404028                       @2@
004010F9   mov ecx,cm.00404028                       X@
00401139   mov ecx,cm.00404028                       @2@
00401139   mov ecx,cm.00404028                       X@
00401155   push cm.004021F9                          给5@
004012CB   mov dword ptr ds:[eax],cm.004033A0        B@
004013E7   mov dword ptr ds:[ecx],cm.0040347C        B@
00401572   push cm.00403554                          关于(&A)...
004015D5   push cm.00402289                          赴6@
00401655   push cm.004022A9                          肛6@
0040177B   push cm.00403568                          恭喜!
00401780   push cm.00403560                          pass!
004017BB   push cm.00403578                          错了!
004017C0   push cm.00403570                          加油!
0040180A   mov [local.17],cm.004035C0                KanXueCTF2019JustForhappy
00401811   mov [local.44],cm.00403580                abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ
004018E8   push cm.004035DC                          请输入pass!
004018FA   mov [local.3],0x0                         (Initial CPU selection)

这里,程序中的关键信息便一目了然。我们直接双击错了!定位到关键代码段:

004017B0  /$  55            push ebp
004017B1  |.  8BEC          mov ebp,esp
004017B3  |.  83EC 44       sub esp,0x44
004017B6  |.  53            push ebx
004017B7  |.  56            push esi
004017B8  |.  57            push edi
004017B9  |.  6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL
004017BB  |.  68 78354000   push cm.00403578                         ; |错了!
004017C0  |.  68 70354000   push cm.00403570                         ; |加油!
004017C5  |.  6A 00         push 0x0                                 ; |hOwner = NULL
004017C7  |.  FF15 00324000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
004017CD  |.  FF15 0C304000 call dword ptr ds:[<&KERNEL32.GetCurrent>; [GetCurrentProcess
004017D3  |.  8945 FC       mov [local.1],eax
004017D6  |.  6A 00         push 0x0                                 ; /ExitCode = 0
004017D8  |.  8B45 FC       mov eax,[local.1]                        ; |
004017DB  |.  50            push eax                                 ; |hProcess
004017DC  |.  FF15 00304000 call dword ptr ds:[<&KERNEL32.TerminateP>; \TerminateProcess
004017E2  |.  5F            pop edi
004017E3  |.  5E            pop esi
004017E4  |.  5B            pop ebx
004017E5  |.  8BE5          mov esp,ebp
004017E7  |.  5D            pop ebp
004017E8  \.  C3            retn

然后在call MessageBoxA函数处下断,运行程序,我们直接输入一个口令如123456引发断点。断下后,按下Alt + k查看函数调用栈:

调用堆栈:     主线程
地址       堆栈       函数过程 / 参数                       调用来自                      结构
0012F690   0040187F   cm.004017B0                           cm.0040187A                   0012F68C
0012F794   004019C8   cm.004017F0                           cm.004019C3                   0012F790
0012F860   73D324C0   cm.00401890                           MFC42.73D324BD                0012F85C
0012F870   73D323BF   MFC42.73D3243E                        MFC42.73D323BA                0012F86C
0012F8A0   73D9DEAD   MFC42.#4424                           MFC42.73D9DEA8                0012F89C
0012F8C4   73D33244   包含MFC42.73D9DEAD                      MFC42.73D33241                0012F8C0
0012F914   73D31BF1   包含MFC42.73D33244                      MFC42.73D31BEB                0012F910
0012F994   73D31B9B   包含MFC42.73D31BF1                      MFC42.73D31B95                0012F990
0012F9B4   73D31B05   包含MFC42.73D31B9B                      MFC42.73D31AFF                0012F9B0
0012FA14   73D31A58   MFC42.#1109                           MFC42.73D31A53                0012FA10
0012FA34   73DC847D   MFC42.#1578                           MFC42.73DC8478                0012FA30
0012FA60   77D18734   包含MFC42.73DC847D                      USER32.77D18731               0012FA5C
0012FA8C   77D18816   ? USER32.77D1870C                     USER32.77D18811               0012FA88
0012FAF4   77D2927B   USER32.77D1875F                       USER32.77D29276               0012FAF0
0012FB30   77D292E3   USER32.77D291B3                       USER32.77D292DE               0012FB2C
0012FB50   77D4FF7D   USER32.SendMessageW                   USER32.77D4FF78               0012FB4C
0012FB54   00A8014E     hWnd = A8014E
0012FB58   00000111     Message = WM_COMMAND
0012FB5C   00000001     age = Notify = MENU/BN_CLICKED...
0012FB60   008C0134     hControage = 008C0134 ('验证',clas
0012FB68   77D465D2   USER32.77D4FF3C                       USER32.77D465CD               0012FB64
0012FB84   77D25E94   USER32.77D25491                       USER32.77D25E8F               0012FB80
0012FC08   77D3B082   USER32.77D25238                       USER32.77D3B07D               0012FC04
0012FC28   77D18734   包含USER32.77D3B082                     USER32.77D18731               0012FC24
0012FC54   77D18816   ? USER32.77D1870C                     USER32.77D18811               0012FC50
0012FC58   77D3B036   包含USER32.77D18816                     USER32.77D3B030               0012FCB8

单击可查看函数体,这里用IDA将关键汇编代码段转换成伪C代码:

int __thiscall sub_401890(CWnd *this)
{
  struct CString *v1; // ST08_4@1
  CWnd *v2; // eax@1
  int v3; // eax@1
  int result; // eax@2
  int input_data[26]; // [sp+4Ch] [bp-74h]@7
  int index; // [sp+B4h] [bp-Ch]@3
  char *my_str; // [sp+B8h] [bp-8h]@1
  CWnd *v8; // [sp+BCh] [bp-4h]@1

  v8 = this;
  v1 = (CWnd *)((char *)this + 100);
  v2 = CWnd::GetDlgItem(this, 1002);
  CWnd::GetWindowTextA(v2, v1);
  v3 = sub_401A30((char *)v8 + 100);
  my_str = CString::GetBuffer((CWnd *)((char *)v8 + 100), v3);
  if ( strlen(my_str) )
  {
    for ( index = 0; my_str[index]; ++index )
    {
      if ( my_str[index] > 57 || my_str[index] < 48 )
      {
        if ( my_str[index] > 122 || my_str[index] < 97 )
        {
          if ( my_str[index] > 'Z' || my_str[index] < 'A' )//  a - z,A -z,0 - 9
            wrong_4017B0();
          else
            input_data[index] = my_str[index] - 29;
        }
        else
        {
          input_data[index] = my_str[index] - 87;
        }
      }
      else
      {
        input_data[index] = my_str[index] - '0';
      }
    }
    result = check_4017F0((int)input_data);
  }
  else
  {
    result = CWnd::MessageBoxA(v8, "请输入pass!", 0, 0);
  }
  return result;
}

int __cdecl check_4017F0(int input_data)
{
  int result; // eax@6
  char Str1[28]; // [sp+D8h] [bp-24h]@4
  int v3; // [sp+F4h] [bp-8h]@1
  int index; // [sp+F8h] [bp-4h]@1

  index = 0;
  v3 = 0;
  while ( *(_DWORD *)(input_data + 4 * index) < '>' && *(_DWORD *)(input_data + 4 * index) >= 0 )
  {
    Str1[index] = aAbcdefghiabcde[*(_DWORD *)(input_data + 4 * index)];
    ++index;
  }
  Str1[index] = 0;
  if ( !strcmp(Str1, "KanXueCTF2019JustForhappy") )
    result = success_401770();
  else
    result = wrong_4017B0();
  return result;
}

逻辑推理

可以看出这里用input_data数组的元素作为索引,取aAbcdefghiabcde数组内的值,最终将它们组成一个子串和KanXueCTF2019JustForhappy对比,相等则成功。

 

所以这里input_data数组的元素是由offest(偏移值)组成,而偏移值按以下公式取得y = F(my_str - x)。

 

那么首先算出偏移值,然后将偏移值加上减去的x即可得到flag。

编写代码

按照以上逻辑,编写如下python代码:

abc_str = 'abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ'
target_str = 'KanXueCTF2019JustForhappy'

offest_list = []

for ch in target_str:
    offest_list.append(abc_str.find(ch))

flag = ''
for offest in offest_list:
    if offest >= 0 and offest <= 9:
        flag += str(offest)
    if offest >= 10 and offest <= 35:
        flag += chr(offest+87)
    if offest >= 36 and offest <= 61:
        flag += chr(offest+29)

print flag

夺旗成功

运行程序,得到flag为:

➜  playground python test.py
j0rXI4bTeustBiIGHeCF70DDM

输入flag,程序提示恭喜,夺旗成功。



[公告]安全测试和项目外包请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 2019-3-10 13:06 被胡八一编辑 ,原因:
最新回复 (0)
游客
登录 | 注册 方可回帖
返回