-
-
[原创]【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漏洞挖掘与利用;代码审计。
赞赏
他的文章
看原图