首页
社区
课程
招聘
[原创]【2019看雪CTF】Q1赛季 第五题 青梅竹马 WP
2019-3-23 20:55 2677

[原创]【2019看雪CTF】Q1赛季 第五题 青梅竹马 WP

2019-3-23 20:55
2677

【2019看雪CTF】Q1赛季 第五题 青梅竹马 WP

这是一个窗体程序,程序流程比较简洁,直接在WinMain中通过DialogBoxParamA设置对话框的事件处理函数DialogFunc

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
  int v4; // eax

  v4 = GetTickCount();
  sub_403371(v4);
  ::hInstance = hInstance;
  DialogBoxParamA(hInstance, (LPCSTR)0x65, 0, DialogFunc, 0);
  return 0;
}

函数DialogFunc伪代码如下:

BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
  switch ( a2 )
  {
    case WM_CLOSE:
      goto LABEL_14;
    case WM_INITDIALOG:
      sub_402B3A(hDlg);
      return 0;
    case WM_COMMAND:
      switch ( (unsigned __int16)a3 )
      {
        case 2u:
          goto LABEL_14;
        case 0x3EAu:
          mainroutine_402652(hDlg);
          return 0;
        case 0x3ECu:
LABEL_14:
          EndDialog(hDlg, 0);
          break;
      }
      break;
  }
  return 0;
}

按钮响应函数mainroutine_402652主要流程如下:

  • 获取隐藏文本框值及用户输入
  • 调用402A90函数解码提示信息
  • 检查输入格式并去除分隔字符'V'
  • 输入编解码校验
  • 输入最终校验

程序中的信息解码及输入编解码校验用的是改了表的base64。所用表如下:

ABCyVPGHTJKLMNOFQRSIUEWDYZgbc8sfah1jklmnopqret5v0xX9wi234u67dz+/

输入格式检查规则如下:

  • 第1、2字节不全为'A'
  • 第6、12字节为'V'
  • 输入为大小写字母+数字

以下是输入的编解码及最终校验的调用代码:

    gen_402889(80, v10, 0x40u);
    gen_base_re_table_402270(v10);
    v6 = debase_402297((unsigned __int8 *)v11, v13);
    enbase_40231E((unsigned __int8 *)v13, v9, v6);
    if ( v13[0] )
    {
      if ( !memcmp(v9, v11, v17) )
      {
        v7 = check_4024E1(100, v5, v13, v6);
        decode_info_402A90((int)v7, Text);
      }
    }

输入先base64解码再编码后与原始输入比较,如正确则进入最终校验。最终校验返回2,则解码成功提示信息,最后弹窗显示。因为解码信息的函数第一个参数是解码字串的index,这些字串后解码后是这样的:

no, wrong sn!!!!
more work to do!
yes, correct sn!
sn doesn't work!

最终校验代码如下:

char *__cdecl check_4024E1(int a1, int a2, char *de_input, int debase_length)
{
  int v4; // ST28_4
  signed int v5; // ebx
  int *v6; // edi
  int v8[100]; // [esp+Ch] [ebp-1C0h]
  BN l_bn_1; // [esp+19Ch] [ebp-30h]
  BN l_bn_2; // [esp+1A8h] [ebp-24h]
  BN l_bn_3; // [esp+1B4h] [ebp-18h]
  BN l_bn_4; // [esp+1C0h] [ebp-Ch]
  int v13; // [esp+1D4h] [ebp+8h]
  int result; // [esp+1E0h] [ebp+14h]

  v8[0] = 0;
  memset(&v8[1], 0, 0x18Cu);
  v13 = sub_40243F(a1, v8);                     // 100 以内素数
  bn_init_401000(&l_bn_3, &l_bn_2, &l_bn_4);
  bn_init_401000(&l_bn_1, 0, v4);
  bn_set_40115C((DWORD)&l_bn_3, 0);
  bn_set_40115C((DWORD)&l_bn_2, 0);
  v5 = 1;
  bn_set_40115C((DWORD)&l_bn_4, 1);
  bn_set_40115C((DWORD)&l_bn_1, v8[0]);
  bn_from_str_4011EB(&l_bn_2.flag, de_input, debase_length);
  result = bg_2_num_4021A7(&l_bn_3);
  if ( v13 > 1 )
  {
    v6 = &v8[1];
    while ( *v6 != a2 )                         // 0x4f
    {
      if ( *v6 )
        bg_mul((int)&l_bn_4, (int)&l_bn_4, *v6);
      ++v5;
      ++v6;
      if ( v5 >= v13 )
        goto LABEL_9;
    }
    v13 = v8[v5 + 1];
  }
LABEL_9:
  if ( bg_cmp(&l_bn_2, &l_bn_1) >= 0 && bg_cmp(&l_bn_2, &l_bn_4) <= 0 )
  {
    powmod_4020F1((int)&l_bn_3, (int)&l_bn_2, v13, (int)&l_bn_4);
    if ( bg_cmp(&l_bn_3, &l_bn_1) >= 0 && bg_cmp(&l_bn_3, &l_bn_4) <= 0 )
      result = bg_2_num_4021A7(&l_bn_3);
  }
  bn_free_401029((int)&l_bn_3);
  bn_free_401029((int)&l_bn_1);
  return (char *)result;
}

大致流程是:生成100以内的素数数组,输入debase后值转成大数记为m,0x4f(隐藏文本框中的值)以内的素数相乘记为大数n,然后求pow(m,0x53,n) == 2
明显的RSA,只不过n不是两个素数相乘,而是多素数相乘。求解是差不多的,(p-1)*(q-1)换成各素乘数减1相乘即可。其它都是一样的。

>>> 2*4*6*10*12*16*18*22*28*30*36*40*42*46*52*58*66*70*72
85564252652648351662080000L
>>> gmpy2.powmod(2,gmpy2.invert(0x53,85564252652648351662080000),b)
mpz(6602940601029543050476765433L)

再用上面的base64表做下base64编码,加上分隔符'V'就是答案了:PEDIyV9102dVreadyu


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

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