首页
社区
课程
招聘
[原创]看雪CTF.TSRC 2018 团队赛第十题侠义双雄WP
2018-12-20 19:38 5650

[原创]看雪CTF.TSRC 2018 团队赛第十题侠义双雄WP

2018-12-20 19:38
5650

初探

可执行文件是Delphi编写。
尝试寻找checkMyFlag按键处理函数,作者是有意隐藏了。在错误提示界面有显示“VBScript”转而查看脚本信息。

VBScript

aScriptLanguage:                        ; DATA XREF: CODE:00469349↑o
CODE:00469598 text "UTF-16LE", '<script language="vbscript">',0Dh,0Ah
CODE:00469598 text "UTF-16LE", 'function alert(msg_str)',0Dh,0Ah
CODE:00469598 text "UTF-16LE", 'MsgBox msg_str,vbOKOnly + vbExclamation + vbApplica'
CODE:00469598 text "UTF-16LE", 'tionModal,""',0Dh,0Ah
CODE:00469598 text "UTF-16LE", 'End Function',0Dh,0Ah
CODE:00469598 text "UTF-16LE", '</script>',0
CODE:004696B8 dword_4696B8 dd 88000101h, 74697277h, 6E6C65h, 0FFFFFFFFh, 8Eh
CODE:004696B8                                         ; DATA XREF: CODE:00469357↑o
CODE:004696CC aCenterBrBrBrIn db '<center><br><br><br><input value="" id="pswd" size=39></input><br'
CODE:004696CC                                         ; DATA XREF: CODE:0046939C↑o
CODE:004696CC db '><br><br><input type=button value="checkMyFlag" onclick="ckpswd()'
CODE:004696CC db ';"></center>',0
CODE:0046975B align 4

这里我们可以看到,checkMyFlag相关处理和ckpswd() 和 pswd敏感信息。
在引用aScriptLanguage处下断点。

CODE:00469343 add     esp, 10h
CODE:00469346 lea     eax, [ebp-0Ch]
CODE:00469349 mov     edx, offset aScriptLanguage     ; "<script language=\"vbscript\">\r\nfunct"...

无意中在eax中指向的地址发现了如下信息:

05432D0  24 00 40 00 69 00 66 00  24 00 24 00 24 00 40 00  $.@.i.f.$.$.$.@.
05432E0  69 00 73 00 24 00 24 00  24 00 40 00 6B 00 61 00  i.s.$.$.$.@.k.a.
05432F0  6E 00 78 00 75 00 65 00  43 00 54 00 46 00 32 00  n.x.u.e.C.T.F.2.
0543300  30 00 31 00 38 00 62 00  79 00 53 00 69 00 6D 00  0.1.8.b.y.S.i.m.
0543310  70 00 6F 00 77 00 65 00  72 00 39 00 31 00 24 00  p.o.w.e.r.9.1.$.
0543320  24 00 24 00 40 00 6D 00  79 00 24 00 24 00 24 00  $.$.@.m.y.$.$.$.
0543330  40 00 6E 00 6F 00 74 00  24 00 24 00 24 00 40 00  @.n.o.t.$.$.$.@.
0543340  70 00 73 00 77 00 64 00  24 00 24 00 24 00 40 00  p.s.w.d.$.$.$.@.
0543350  76 00 61 00 6C 00 75 00  65 00 24 00 24 00 24 00  v.a.l.u.e.$.$.$.
0543360  40 00 77 00 72 00 6F 00  6E 00 67 00 24 00 24 00  @.w.r.o.n.g.$.$.
0543370  24 00 27 00 2E 00 73 00  70 00 6C 00 69 00 74 00  $.'...s.p.l.i.t.

逻辑看上去是个判断pw脚本,使用“kanxueCTF2018bySimpower91”测试了一下,居然通过了。肯定是个非预期了。

继续探索

还原代码

这个脚本从何而来呢?在引用脚本的上面存在这样一段代码,其中内部还有一部分加密的数据。

DE:004691A2 loc_4691A2:                             ; CODE XREF: CODE:00469468↓j
CODE:004691A2 nop
CODE:004691A3 nop
CODE:004691A4 pushf
CODE:004691A5 call    sub_467ACC
CODE:004691AA mov     word ptr [esi+72928992h], ss
CODE:004691B0 mov     dl, 73h
CODE:004691B2 jz      short loc_46915E
CODE:004691B4 add     ebx, [esi+37h]
CODE:004691B7 xor     edi, [ecx+19D217FFh]
CODE:004691B7 ; ---------------------------------------------------------------------------
CODE:004691BD db 0, 0, 74h
CODE:004691C0 dd 0BA7273AAh, 4591170Bh, 0BA720006h
CODE:004691CC db 0Bh, 0AFh, 97h
CODE:004691CF dd 0FFB96AC7h
CODE:004691D3 db 97h
CODE:004691D4 dd 0FFB96AE7h
CODE:004691D8 dd 936A72h, 0BA740000h, 77F7407h, 17FFFFFDh, 979Fh, 937A72h, 72AF0000h
CODE:004691D8 dd 837Ah, 0CA17AF00h, 7C000597h, 7A72F33Bh, 83h, 17FF95AFh, 597DBh, 14EF3B7Ch
CODE:004691D8 dd 92968CF6h, 919A9289h
CODE:0046921C db 9Bh, 0FFh, 68h
CODE:0046921F dd offset aScript_0                     ; "</script>"
CODE:00469223 ; ---------------------------------------------------------------------------
CODE:00469223 push    offset dword_46950C
CODE:00469228 push    offset dword_469518
CODE:0046922D lea     edx, [ebp-0B4h]
CODE:00469233 mov     eax, [ebp-8]
CODE:00469236 mov     eax, [eax+2F8h]
CODE:0046923C call    @Olectrls@TOleControl@GetOleObject$qqrv ; Olectrls::TOleControl::GetOleObject(void)

分析发现,函数467ACC() 将代码中的加密代码数据进行了解密,反汇编,重定位,动态解析执行,一条一条语句的执行。还原的程序解密了上面看到的脚本。
467ACC()-> 467878() -> 46750C()-->467938()

int __stdcall sub_46750C(int a1, int a2, int a3, _DWORD *a4, int *a5, _DWORD *a6)
{
  _DWORD *v6; // ebx
  int v7; // eax
  int v8; // edi
  int *v10; // [esp-Ch] [ebp-37Ch]
  void *v11; // [esp-8h] [ebp-378h]
  int *v12; // [esp-4h] [ebp-374h]
  void *v13; // [esp+0h] [ebp-370h]
  int v14; // [esp+Ch] [ebp-364h]
  int *v15; // [esp+10h] [ebp-360h]
  char v16; // [esp+14h] [ebp-35Ch]
  char v17; // [esp+24h] [ebp-34Ch]
  char v18; // [esp+28h] [ebp-348h]
  char v19; // [esp+128h] [ebp-248h]
  char *v20; // [esp+35Ch] [ebp-14h]
  int v21; // [esp+360h] [ebp-10h]
  int v22; // [esp+364h] [ebp-Ch]
  int v23; // [esp+368h] [ebp-8h]
  int v24; // [esp+36Ch] [ebp-4h]
  int savedregs; // [esp+370h] [ebp+0h]

  v15 = 0;
  v14 = 0;
  v21 = 0;
  v12 = &savedregs;
  v11 = &loc_4677B2;
  v10 = (int *)__readfsdword(0);
  __writefsdword(0, (unsigned int)&v10);
  v6 = sub_466DAC();
  sub_467938((int)v6, (const void *)a2, &v16, (int)v6, &v22);
  v22 = ((int (__stdcall *)(char *, int, signed int, char *, signed int, int *))v6[1036])(
          &v16,
          v22,
          0x400000,                             // 反汇编,LEA ECX,[SS:EBP-74]
          &v17,
          4,
          v10);
  *a4 = v22;
  v20 = (char *)(v6 + 1038);
  sub_464518(v6 + 1038, &v16, v22);
  *((_BYTE *)v6 + v22 + 4152) = 104;
  unknown_libname_54((int)&v21, &v19);
  if ( (unsigned __int8)sub_466EF8(v21, v6[10]) )
  {
    unknown_libname_54((int)&v21, &v18);
    v24 = sub_464598(&str___15[1], v21);
    v10 = &v21;
    unknown_libname_58(v21);
    System::__linkproc__ LStrCopy(v10);
    v24 = sub_4645FC(v21);
    if ( v22 - 1 >= 0 )
    {
      v7 = v22;
      v23 = 0;
      do
      {
        *((_BYTE *)v6 + v23++ + 4152) = 0x90u;
        --v7;
      }
      while ( v7 );
    }
    v24 += v22;
  }
  else if ( sub_464598(&str_CALL[1], v21) == 1 )
  {
    unknown_libname_54((int)&v21, &v18);
    if ( sub_464598(&str_FF[1], v21) != 1 )
    {
      v24 = sub_464598(&str___15[1], v21);
      v23 = v24 - 1;
      v8 = (v24 - 1) / 2;
      v20 = (char *)v6 + v8 + 4152;
      v10 = &v21;
      unknown_libname_58(v21);
      System::__linkproc__ LStrCopy(v10);
      v24 = sub_4645FC(v21);
      v23 = v24 + a2 - (_DWORD)(v6 + 1038);
      sub_464518(v20, &v23, v22 - v8);
    }
    v24 = v22;
  }
  else
  {
    v24 = v22;
  }
  *a6 = v24;
  v6[1] = v24;
  v24 = a3;
  v20 = (char *)v6 + v22 + 4153;
  sub_464518(v20, &v24, 4u);
  *((_BYTE *)v6 + v22 + 4157) = -61;
  *a5 = (int)(v6 + 1038);
  v6[9] = a2 + *a6;
  unknown_libname_54((int)&v15, &v19);
  v10 = v15;
  unknown_libname_54((int)&v14, &v18);
  sub_4678BC((int)v6, *a5, a2, (int)v10, v14, v22);
  __writefsdword(0, (unsigned int)v11);
  v13 = &loc_4677B9;
  System::__linkproc__ LStrArrayClr((int)&v14, 2);
  return System::__linkproc__ LStrClr(&v21);
}
int __fastcall sub_467938(int a1, const void *a2, void *a3, _DWORD *a4)
{
  int result; // eax

  if ( *(_WORD *)(a1 + 0x1062) )
    return (*(int (__fastcall **)(_DWORD, const void *))(a1 + 0x1060))(*(_DWORD *)(a1 + 0x1064), a2);// 对应 467974()
  sub_464518(a3, a2, 0x10u);
  result = (int)a4;
  *a4 = 16;
  return result;
}
int __fastcall sub_467974(int a1, int a2, int a3, _DWORD *a4)
{
  int v4; // ecx
  char v5; // zf
  _DWORD *v6; // eax
  unsigned int v8; // [esp+8h] [ebp-20h]
  void *v9; // [esp+Ch] [ebp-1Ch]
  int *v10; // [esp+10h] [ebp-18h]
  int v11; // [esp+20h] [ebp-8h]
  int v12; // [esp+24h] [ebp-4h]
  int savedregs; // [esp+28h] [ebp+0h]

  v11 = 0;
  v10 = &savedregs;
  v9 = &loc_467A18;
  v8 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v8);
  *a4 = 16;
  v12 = a3;
  v4 = 0;
  do
  {
    *(_BYTE *)(v12 + v4) = ~*(_BYTE *)(a2 + v4);
    ++v4;
  }
  while ( v4 != 16 );
  getInsStr(v12 + 2, (int)&v11);                // 获取指令opcode字符串
  System::__linkproc__ LStrCmp(v11, &str_simvmend[1]);
  if ( v5 )
  {
    v6 = sub_466DAC();
    v6[3] = v6[9];
  }
  __writefsdword(0, v8);
  v10 = (int *)&loc_467A1F;
  return System::__linkproc__ LStrClr(&v11);
}

467974()函数将0x4691AF所在数据(加密的代码)与0xFF异或解密,每次解密16个字节。如上所述经过了解密,反汇编,重定位的过程,组织好了一条汇编指令。

 

指令准备好了,而指令又在那里执行的呢?

int __usercall sub_467878@<eax>(int a1@<ebx>, int a2@<edi>, int a3@<esi>, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14)
{
  unsigned int v14; // et0
  int (__fastcall *v15)(unsigned int *, unsigned int); // ST10_4
  unsigned int v17; // [esp+14h] [ebp-2Ch]
  int v18; // [esp+30h] [ebp-10h]
  void **v19; // [esp+34h] [ebp-Ch]
  int *v20; // [esp+38h] [ebp-8h]
  int v21; // [esp+3Ch] [ebp-4h]
  unsigned int vars0; // [esp+40h] [ebp+0h]
  void *retaddr; // [esp+44h] [ebp+4h]

  vars0 = a3;
  v21 = a2;
  v20 = (int *)&vars0;
  v19 = &retaddr;
  v18 = a1;
  v14 = __readeflags();
  *(_DWORD *)(a13 + 40) = retaddr;
  sub_46750C(a13, a14, a12, &v20, (int *)&v19, &v18);
  vars0 = v17;
  __writeeflags(v17);
  __writeeflags(v17);
  return v15(&vars0, v14);   //jmp     [esp-4+var_3C] 
                            执行解密后的单条指令
}

我们可以看到EIP跳转到0xA4038执行了一条指令,然后返回到0x467B10

000A4038 8D 4D 8C                      lea     ecx, [ebp-74h]
000A403B 68 10 7B 46 00                push    offset loc_467B10
:000A4040 C3                            retn

继续下一条。
所有加密代码还原后如下:

 004691B2 8B 55 FC                      mov     edx, [ebp-4]
CODE:004691B0                               ; ---------------------------------------------------------------------------
CODE:004691B1 8C                            db  8Ch
CODE:004691B2                               ; ---------------------------------------------------------------------------
CODE:004691B2 8B 55 FC                      mov     edx, [ebp-4]
CODE:004691B5 A1 C8 CC 46 00                mov     eax, ds:dword_46CCC8
CODE:004691BA E8 2D E6 FF FF                call    sub_4677EC
CODE:004691BF 8B 55 8C                      mov     edx, [ebp-74h]
CODE:004691C2 8D 45 F4                      lea     eax, [ebp-0Ch]
CODE:004691C5 E8 6E BA F9 FF                call    @System@@WStrFromLStr$qqrr17System@WideStringx17System@AnsiString ; System::__linkproc__ WStrFromLStr(System::WideString &,System::AnsiString)
CODE:004691CA 8D 45 F4                      lea     eax, [ebp-0Ch]
CODE:004691CD 50                            push    eax
CODE:004691CE 68 38 95 46 00                push    offset dword_469538
CODE:004691D3 68 18 95 46 00                push    offset dword_469518
CODE:004691D8 8D 95 6C FF FF FF             lea     edx, [ebp-94h]
CODE:004691DE 8B 45 F8                      mov     eax, [ebp-8]
CODE:004691E1 8B 80 F8 02 00 00             mov     eax, [eax+2F8h]
CODE:004691E7 E8 60 68 FF FF                call    @Olectrls@TOleControl@GetOleObject$qqrv ; Olectrls::TOleControl::GetOleObject(void)
CODE:004691EC 8D 85 6C FF FF FF             lea     eax, [ebp-94h]
CODE:004691F2 50                            push    eax
CODE:004691F3 8D 85 7C FF FF FF             lea     eax, [ebp-84h]
CODE:004691F9 50                            push    eax
CODE:004691FA E8 35 68 FA FF                call    @Variants@@DispInvoke$qp8TVarDatarx8TVarDatap16System@TCallDescpv ; Variants::__linkproc__ DispInvoke(TVarData *,TVarData &,System::TCallDesc *,void *)
CODE:004691FF 83 C4 0C                      add     esp, 0Ch
CODE:00469202 8D 85 7C FF FF FF             lea     eax, [ebp-84h]
CODE:00469208 50                            push    eax
CODE:00469209 6A 00                         push    0
CODE:0046920B E8 24 68 FA FF                call    @Variants@@DispInvoke$qp8TVarDatarx8TVarDatap16System@TCallDescpv ; Variants::__linkproc__ DispInvoke(TVarData *,TVarData &,System::TCallDesc *,void *)
CODE:00469210 83 C4 10                      add     esp, 10h
CODE:00469213 EB 09                         jmp     short loc_46921E    short loc_46921E

还原脚本

还原完代码,继续还原脚本,解密后的代码中有个函数sub_4677EC(),该函数还原脚本文件。

nt __usercall sub_4677EC@<eax>(_BYTE *a1@<edx>, int a2@<ecx>, int a3@<ebx>, int a4@<edi>, int a5@<esi>)
{
  int v5; // esi
  int v6; // edx
  unsigned int v8; // [esp-18h] [ebp-24h]
  void *v9; // [esp-14h] [ebp-20h]
  int *v10; // [esp-10h] [ebp-1Ch]
  int v11; // [esp-Ch] [ebp-18h]
  int v12; // [esp-8h] [ebp-14h]
  int v13; // [esp-4h] [ebp-10h]
  int v14; // [esp+0h] [ebp-Ch]
  int v15; // [esp+4h] [ebp-8h]
  _BYTE *i; // [esp+8h] [ebp-4h]
  int savedregs; // [esp+Ch] [ebp+0h]

  v15 = 0;
  v14 = 0;
  v13 = a3;
  v12 = a5;
  v11 = a4;
  v5 = a2;
  i = a1;
  v10 = &savedregs;
  v9 = &loc_467867;
  v8 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v8);
  LOBYTE(a3) = *a1;
  for ( i = a1 + 1; (unsigned __int8)a3 > 0x7Fu; ++i )
  {
    v6 = a3;
    LOBYTE(v6) = a3 - 127;
    unknown_libname_53(&v14, v6);
    System::__linkproc__ LStrCat(&v15, v14);
    LOBYTE(a3) = *i;
  }
  System::__linkproc__ LStrAsg(v5, v15);
  __writefsdword(0, v8);
  v10 = (int *)&loc_46786E;
  return System::__linkproc__ LStrArrayClr(&v14, 2);
}

//加密的脚本数据
CODE:004693F8 dword_4693F8    dd 0BFA3A3A3h, 0A3A3E5E8h, 0F2E8BFA3h, 0BFA3A3A3h, 0F7EDE0EAh
CODE:004693F8                                         ; DATA XREF: CODE:loc_469460↓o
CODE:004693F8                 dd 0D3C2E4F4h, 0B0AFB1C5h, 0D2F8E1B7h, 0EEEFECE8h, 0B8F1E4F6h
CODE:004693F8                 dd 0A3A3A3B0h, 0A3F8ECBFh, 0EDBFA3A3h, 0A3A3F3EEh, 0F2EFBFA3h
CODE:004693F8                 dd 0A3A3E3F6h, 0E0F5BFA3h, 0A3E4F4EBh, 0F6BFA3A3h, 0E6EDEEF1h
CODE:004693F8                 dd 0A6A3A3A3h, 0EBEFF2ADh, 0A6A7F3E8h, 0ABA8A6BFh, 0FCFAABAFh
CODE:004693F8                 dd 7FA8A8h

解密后的数据,就是我们开头看到的文本内容了

f...$$$@if$$$@is
$$$@kanxueCTF201
8bySimpower91$$$
@my$$$@not$$$@ps
wd$$$@value$$$@w
rong$$$'.split('

Flag:kanxueCTF2018bySimpower91


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2018-12-21 16:44 被ODPan编辑 ,原因:
收藏
点赞4
打赏
分享
最新回复 (2)
雪    币: 10845
活跃值: (1049)
能力值: (RANK:190 )
在线值:
发帖
回帖
粉丝
看场雪 3 2018-12-21 18:13
2
0
佩服楼主的钻研精神
不仅“杀人”,而且“诛心”
雪    币: 6779
活跃值: (1069)
能力值: ( LV12,RANK:782 )
在线值:
发帖
回帖
粉丝
ODPan 5 2018-12-21 19:22
3
0
看场雪 佩服楼主的钻研精神[em_63] 不仅“杀人”,而且“诛心”[em_19]
被你惨虐的后遗症
游客
登录 | 注册 方可回帖
返回