美文网首页
【CTF-RE】KanXue_CTF_2017

【CTF-RE】KanXue_CTF_2017

作者: Kirin_say | 来源:发表于2018-07-18 20:21 被阅读222次

    去年没参加
    今年又赶上考试月
    只能先整理之前的题目了

    0x01 Helllo-CTF

    签到题:
    IDA -> sheft+F12打开字符串界面
    即能看到passwod

    0x02 ctf2017_Fpc

    接收输入流使用scanf读取,存在栈溢出,测试后发现可以直接跳转到成功处,但存在不可见字符,猜测不是正解:

    sub_401050:
    .text:00401050 var_C           = dword ptr -0Ch
    .text:00401050
    .text:00401050                 sub     esp, 0Ch
    .text:00401053                 push    offset aCodedByFpc ; " Coded by Fpc.\n\n"
    .text:00401058                 call    sub_413D42
    .text:0040105D                 add     esp, 4
    .text:00401060                 push    offset aPleaseInputYou ; " Please input your code: "
    .text:00401065                 call    sub_413D42
    .text:0040106A                 add     esp, 4
    .text:0040106D                 lea     eax, [esp+0Ch+var_C]
    .text:00401071                 push    eax
    .text:00401072                 push    offset aS       ; "%s"
    .text:00401077                 call    _scanf
    .text:0040107C                 lea     eax, [esp+14h+var_C]
    .text:00401080                 add     esp, 14h
    .text:00401083                 retn
    

    接着调用两个函数检测输入字符串,提取其中的判断式:

    v1 && v0 && v1 != v0 && 5 * (v1 - v0) + v1 == 0x8F503A42&& 13 * (v1 - v0) + v0 == 0xEF503A42
    v1 && v0 && v1 != v0 && 17 * (v1 - v0) + v1 ==  0xF3A94883 && 7 * (v1 - v0) + v0 ==  0x33A94883
    

    即:

    v1!=0
    v0!=0
    5 * (v1 - v0) + v1 = 0x8F503A42
    13 *(v1 - v0) + v0 = 0xEF503A42
    17 *(v1 - v0) + v1 = 0xF3A94883
    7 * (v1 - v0) + v0 = 0x33A94883
    

    无解
    接着看程序:
    发现可疑点:

    .text:00413131                 db 83h, 0C4h, 0F0h
    .text:00413134                 dd 20712A70h, 0F1C75F2h, 28741C71h, 2E0671DDh, 870F574h
    .text:00413134                 dd 74F17169h, 0DC167002h, 0EA74C033h, 0DC261275h, 0F471E771h
    .text:00413134                 dd 6903740Fh, 0EB75EB70h, 0FDF7069h, 22712C70h, 0B8261F7Dh
    .text:00413134                 dd 2B741E71h, 3E067169h, 870F57Ch, 7CF17169h, 0DC197002h
    .text:00413134                 dd 41B034A3h, 75E77400h, 0E571DC12h, 7CDCF271h, 0E9706903h
    .text:00413134                 dd 6965E97Dh, 70B8DC70h, 3E1D7127h, 710F1971h, 0DD257019h
    .text:00413134                 dd 0F6700571h, 71DD0870h, 700270F2h, 70580F14h, 0F1171ECh
    ............
    

    .text:00413131 后跟着一堆花指令
    猜测这里是真正验证的地方
    而且恰巧可以借助scanf字符串11A(可见字符)覆盖返回地址来跳转到413131处,返回地址与栈中存储输入流的距离是0xc,我们输入:

    aaaaaaaaaaaa11A
    

    动态调试忽略无关跳转
    得到真正的验证代码:

    add     esp, 0FFFFFFF0h
    mov     dword_41B034, eax
    pop     eax             ;前四位
    mov     ecx, eax 
    pop     eax             ;中四位
    mov     ebx, eax
    pop     eax             ;后四位
    mov     edx, eax
    mov     eax, ecx
    sub     eax, ebx 
    //判断相等
    shl     eax, 2
    add     eax, ecx
    //判断正负
    add     eax, edx
    sub     eax, 0EAF917E2h
    //判断相等
    add     eax, ecx
    sub     eax, ebx
    mov     ebx, eax
    shl     eax, 1
    add     eax, ebx
    add     eax, ecx
    mov     ecx, eax
    add     eax, edx
    sub     eax, 0E8F508C8h
    //判断相等
    mov     eax, ecx
    sub     eax, edx
    //判断相等
    sub     eax, 0C0A3C68h
    //判断相等
    

    可得:

    前三位:v1
    中三位:v2
    后三位:v3
    (v1-v2)*4+v1+v3=0xEAF917E2
    (v1-v2)*3+v1+v3=0xE8F508C8
    (v1-v2)*3+v1-v3=0xC0A3C68
    

    即得:

    v0=7473754A
    v1=726F6630
    v2=6E756630
    

    拼接后再加上溢出用的11A即得:

    Just0for0fun11A
    

    0x02 crackMe

    定位WinMain函数:
    找到了窗口处理函数DialogFunc:

    .text:00434CC8                 push    0               ; dwInitParam
    .text:00434CCA                 push    offset DialogFunc ; lpDialogFunc
    .text:00434CCF                 push    0               ; hWndParent
    .text:00434CD1                 push    65h             ; lpTemplateName
    .text:00434CD3                 mov     eax, [ebp+hInstance]
    .text:00434CD6                 push    eax             ; hInstance
    .text:00434CD7                 call    ds:DialogBoxParamA
    

    跳转到DialogFunc
    开始是一大堆反调试函数,先抛去不看
    看到GetDlgItemTextA,主要流程在这里开始:

    .text:0043505C                 add     esp, 0Ch
    .text:0043505F                 mov     esi, esp
    .text:00435061                 push    401h            ; cchMax
    .text:00435066                 lea     eax, [ebp+String]
    .text:0043506C                 push    eax             ; lpString
    .text:0043506D                 push    3E9h            ; nIDDlgItem
    .text:00435072                 mov     ecx, [ebp+hDlg]
    .text:00435075                 push    ecx             ; hDlg
    .text:00435076                 call    ds:GetDlgItemTextA
    

    base64decode

    接下来进入第一个函数:sub_42D267:
    依然调用很多反调试函数:
    查看伪代码,发现这里类似一个base64解码操作
    简单测试一下:
    dump下来,除去反调试改写成可编译C文件:

    #include<stdio.h>
    int main()
    {
      signed int result; 
      unsigned int v4; 
      int v5; 
      unsigned int i; 
      int code[1024]={77,84,73,122};  // "123".encode("base64")='MTIz'
      int a2=1024;
    
    unsigned char chars[] =
    {
      0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 
      0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
      0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 
      0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 
      0x39, 0x2B, 0x2F, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 
      0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 
      0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 
      0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
      0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 
      0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 
      0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 
      0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    };
    int answer[1024]={0};
      v5 = 0;
      for ( i = 0; i <1024 ; ++i )
      {
        v4 = chars[code[i]];
        switch ( i % 4 )
        {
          case 0:
            answer[v5] = 4 * v4;
            break;
          case 1:
            answer[v5++] += (v4 >> 4) & 3;
            if ( i < a2 - 3 || code[a2  - 2] != 61 )
              answer[v5] = 16 * (v4 & 0xF);
            break;
          case 2:
            answer[v5++] += (v4 >> 2) & 0xF;
            if ( i < a2 - 2 || code[a2 - 1] != 61 )
              answer[v5] = (v4 & 3) << 6;
            break;
          case 3u:
            answer[v5++] += v4;
            break;
          default:
            continue;
        }
      }
    printf("%d %d %d  %d\n",answer[0],answer[1],answer[2]);
      return 0;
    }
    //gcc 1.c
    // ./a.out
    //49 50 51      (1  2  3)
    

    发现这是标准的base64解码算法
    不过在判断解码结尾时类似规避了报错

    Morsedecode

    两次base64解码后
    解码后的字符串进入sub_435DE0
    看到关键处:

    if ( a1[v9] == 32 || a1[v9] == 47 )
        {
          if ( a1[v9] != 32 || a1[v9 - 1] == 47 )
          {
            if ( a1[v9] == 47 )
              *(_BYTE *)(v7++ + a2) = 32;
          }
          else
          {
            if ( (unsigned __int8)sub_42D0DC(v10, &v5) != 1 || v8 >= 5 )
            {
              if ( (unsigned __int8)sub_42D7B2(v10, &v5) == 1 )
              {
                *(_BYTE *)(v7++ + a2) = v5;
              }
              else if ( sub_42E414((int)v10, (int)&v5) == 1 )
              {
                *(_BYTE *)(v7++ + a2) = v5;
              }
              else
              {
                j__printf("error !\n");
              }
            }
            else
            {
              *(_BYTE *)(v7++ + a2) = v5;
            }
            v8 = 0;
            j__memset(v10, 42, 8u);
          }
        }
        else
        {
          *((_BYTE *)v10 + v8++) = a1[v9];
        }
        ++v9;
      }
    

    以及解码用到的数据表:

    图片.png
    显然是一个摩斯密码解密,且以空格为分隔符
    且"空格"前有"/"视为转义,解密为空格
    单一"/"会被解密为空格

    SM3

    接下来两次base64解码后的字符串进入sub_437E70:
    开始时其调用了一个函数初始化了一段数据:

    .text:0043673B                 mov     dword ptr [eax+8], 7380166Fh
    .text:00436742                 mov     eax, [ebp+arg_0]
    .text:00436745                 mov     dword ptr [eax+0Ch], 4914B2B9h
    .text:0043674C                 mov     eax, [ebp+arg_0]
    .text:0043674F                 mov     dword ptr [eax+10h], 172442D7h
    .text:00436756                 mov     eax, [ebp+arg_0]
    .text:00436759                 mov     dword ptr [eax+14h], 0DA8A0600h
    .text:00436760                 mov     eax, [ebp+arg_0]
    .text:00436763                 mov     dword ptr [eax+18h], 0A96F30BCh
    .text:0043676A                 mov     eax, [ebp+arg_0]
    .text:0043676D                 mov     dword ptr [eax+1Ch], 163138AAh
    .text:00436774                 mov     eax, [ebp+arg_0]
    .text:00436777                 mov     dword ptr [eax+20h], 0E38DEE4Dh
    .text:0043677E                 mov     eax, [ebp+arg_0]
    .text:00436781                 mov     dword ptr [eax+24h], 0B0FB0E4Eh
    

    而后接着对字符串前三位进行了加密
    搜索这些数据
    发现这里是SM3加密

    迷宫算法

    而后将Morsedecode后的结果传入sub_435400
    可以看出这是一个10*10的迷宫:

    0 1 1 1 1 1 1 1 1 0
    0 0 1 1 1 1 1 0 0 0
    1 0 0 0 0 0 1 0 1 1
    1 1 1 1 1 0 1 0 0 1
    1 0 0 0 1 0 1 0 0 1
    1 0 1 0 0 0 1 0 1 1
    1 0 1 1 1 1 1 0 0 1
    1 0 0 0 0 1 1 1 0 0
    1 1 1 1 0 0 0 0 1 0
    1 1 1 1 1 1 1 0 0 0
    

    其中:

    0为可走点
    q z分别表示向上和向下
    p l分别表示向左和向右
    

    其次有一个注意点,程序有一处判断:

    v5 != 8 || v4 != 3
    

    故而第3行第8列的0不能走
    不过这个算法在判断时可以绕过:
    程序开始检测:

    while ( *a2 != 32 )
    

    当我们走任意可行步(包括0步)都可以在结尾加上一个空格构造绕过

    反调试

    可以把文件的重定位表地址rv清0便于调试
    利用CheckRemoteDebuggerPresent、ZwQueryInformationProcess和IsDebuggerPresent等API调用判断调试状态,检查调试类驱动,判断打开程序窗体名,检查进程,抛出异常
    不过都很好绕过,直接全部nop掉,或者调试断点时绕过,或者在对应函数修改第一条指令为ret即可

    序列号

    尽量简化过程我们最终构造的字符串"code"经解密传入迷宫时开头为空格
    且sm3(base64decode(base64decode(code))[:3])=code[-64:]
    考虑到base64以及摩斯解密时的容错性(因为解码时字符串结尾需要有64位sm3加密后的字符串)
    我们构造base64解密后为"///"的字符串,摩斯解密时其会自动生成三个空格(也可以一个"/",不过sm3时需要补\x00以及考虑base64时及时截断问题,为了简化,直接"///"即可),满足最后的迷宫算法的需求
    最终序列号:

    THk4dgo9aa4f168af9fcb372825d2e817379ab6ad4a7da973a38c44a0ec56a788dfb89b
    

    相关文章

      网友评论

          本文标题:【CTF-RE】KanXue_CTF_2017

          本文链接:https://www.haomeiwen.com/subject/yzdxyftx.html