-
-
[原创]看雪 2025·KCTF 第三题 邪影显现 by 5m10v3
-
发表于: 2025-8-19 01:08 4965
-
通过输入name,code从而来进行校验,题目要求以特定用户名('KCTF')获取code进行校验。
无壳,32位程序

main函数的逻辑很简单,分别获取输入的name和code,同时将name和code作为两个参数传入check函数进行校验,同时check函数的返回值也作为判断值去判断正确和错误。
主要的大头还是check函数,可以先看一下控制流程图,简直就是一面旗帜(当时看的这里确实萌发了投降的念头),不过我还是想把这个旗子给摘了。

利用FindCrypt这个插件,可以看到有md5,并且也是在我们的check函数里面

这里是将我们输入的name,经过md5之后作为一段hash值拼接在了KCTF2025后面
跳过一些初始化变量的地方,我们可以定位这里开始对我们输入的code进行校验了,输入的code字符串的长度必须为48,并且为十六进制数,然后会将我们输入的字符串转化为24字节数存储在数组里面。
往下分析首先遇到了第一个处理,进行了一个大小端的转化将24字节作为一个大数进行传递,同时还有乘积,mod操作,让我们联想到模幂运算,后面还有一个模逆运算,最低字节加一。
由于伪代码太难看了并且有很多奇奇怪怪的循环,因此直接选择动调调试

在动态调试的过程中也发现了一件事情,就是这个模幂运算中的指数可以爆破出来,以下是在动态调试中的所想。
我在动调的时候发现了很多相似的地方,他们都在最低字节加一,所有就大胆测试了几个确实对应上了。
但是模乘的指数太难看了,这个简单直接爆破,然后在以下这种地方设置断点观察进行模幂运算和模逆元之后的大数与断点处的进行比较。


然后我们还原一下check函数的逻辑
这里写出解密脚本利用了sage这个工具

公开组序列号name: EA35B2C3F2B5FCE4code: 20DB698F803FB15F6DFFBADD0E125ABEBE96494B0CCCA620请找出特定用户名(“KCTF”,不含引号) 的序列号,经KCTF系统自动确认,将认定攻击方获胜;公开组序列号name: EA35B2C3F2B5FCE4code: 20DB698F803FB15F6DFFBADD0E125ABEBE96494B0CCCA620请找出特定用户名(“KCTF”,不含引号) 的序列号,经KCTF系统自动确认,将认定攻击方获胜;int __cdecl main(int argc, const char **argv, const char **envp){ int v3; // ecx int v4; // ecx int v5; // eax char *v6; // ecx char v8; // [esp-38h] [ebp-CCh] char v9; // [esp-2Ch] [ebp-C0h] char v10; // [esp-20h] [ebp-B4h] char Buffer[64]; // [esp+4h] [ebp-90h] BYREF char ArgList[64]; // [esp+44h] [ebp-50h] BYREF int v13; // [esp+90h] [ebp-4h] *(_DWORD *)(sub_420782(4096, 2) + 576) = 1; v13 = 0; memset(Buffer, 0, sizeof(Buffer)); memset(ArgList, 0, sizeof(ArgList)); printf(v3, "name: ", v10); gets_s(Buffer, 0x40u); // 获取name printf(v4, "code: ", v9); gets_s(ArgList, 0x40u); // 获取code v5 = check(Buffer, ArgList); // 校验函数 v6 = "ok\n"; if ( v5 != 1 ) v6 = "error\n"; printf((int)v6, v6, v8); sub_420BBA(); return 0;}int __cdecl main(int argc, const char **argv, const char **envp){ int v3; // ecx int v4; // ecx int v5; // eax char *v6; // ecx char v8; // [esp-38h] [ebp-CCh] char v9; // [esp-2Ch] [ebp-C0h] char v10; // [esp-20h] [ebp-B4h] char Buffer[64]; // [esp+4h] [ebp-90h] BYREF char ArgList[64]; // [esp+44h] [ebp-50h] BYREF int v13; // [esp+90h] [ebp-4h] *(_DWORD *)(sub_420782(4096, 2) + 576) = 1; v13 = 0; memset(Buffer, 0, sizeof(Buffer)); memset(ArgList, 0, sizeof(ArgList)); printf(v3, "name: ", v10); gets_s(Buffer, 0x40u); // 获取name printf(v4, "code: ", v9); gets_s(ArgList, 0x40u); // 获取code v5 = check(Buffer, ArgList); // 校验函数 v6 = "ok\n"; if ( v5 != 1 ) v6 = "error\n"; printf((int)v6, v6, v8); sub_420BBA(); return 0;}//'KCTF2025'+md5('name')qmemcpy(v259, "KCTF2025", sizeof(v259));v250[23] = 0;v250[19] = 0x67452301;v250[20] = 0xEFCDAB89;v250[21] = 0x98BADCFE;v250[22] = 0x10325476;memset(v250, 0, 12);sub_41E530(a1, v250, strlen(a1));sub_41E660((int)v250, v260);v8 = sub_41EA2E((int **)&v258, 24, v264);//'KCTF2025'+md5('name')qmemcpy(v259, "KCTF2025", sizeof(v259));v250[23] = 0;v250[19] = 0x67452301;v250[20] = 0xEFCDAB89;v250[21] = 0x98BADCFE;v250[22] = 0x10325476;memset(v250, 0, 12);sub_41E530(a1, v250, strlen(a1));sub_41E660((int)v250, v260);v8 = sub_41EA2E((int **)&v258, 24, v264);if ( strlen(Buffer) == 48 ) { for ( j = 0; j < 24; ++j ) { v29 = *v27; if ( (*v27 < 48 || v29 > 57) && (unsigned __int8)(v29 - 65) > 5u ) goto LABEL_209; v30 = v27[1]; if ( (v30 < 48 || v30 > 57) && (unsigned __int8)(v30 - 65) > 5u ) goto LABEL_209; if ( sub_401F00(v27, "%02X", &v262[j]) != 1 ) goto LABEL_209; v27 += 2; }if ( strlen(Buffer) == 48 ) { for ( j = 0; j < 24; ++j ) { v29 = *v27; if ( (*v27 < 48 || v29 > 57) && (unsigned __int8)(v29 - 65) > 5u ) goto LABEL_209; v30 = v27[1]; if ( (v30 < 48 || v30 > 57) && (unsigned __int8)(v30 - 65) > 5u ) goto LABEL_209; if ( sub_401F00(v27, "%02X", &v262[j]) != 1 ) goto LABEL_209; v27 += 2; }do { v33 = *v32--; *((_BYTE *)v261 + v31++) = v33; } while ( v31 < 24 ); v221 = 0; bytes2Big((int)v261, 6, &v221); mult(v221, v221, (int *)&v235); mult(v221, v235, &v249); mod(v249, v194, &v235); mod_inv(v235, v194, &v235); v252 = 6; sub_4556D0(v235, v261, &v252); v34 = 0; v35 = 4 * v252; v252 = v35; sub_4556D0(v235, v261, &v252); v34 = 0; v35 = 4 * v252; v252 = v35; if ( v35 > 0 ) { do { v262[v34] = v260[v35 - v34 + 247]; ++v34; } while ( v34 < v35 ); } ++*(_DWORD *)v262;do { v33 = *v32--; *((_BYTE *)v261 + v31++) = v33; } while ( v31 < 24 ); v221 = 0; bytes2Big((int)v261, 6, &v221); mult(v221, v221, (int *)&v235); mult(v221, v235, &v249); mod(v249, v194, &v235); mod_inv(v235, v194, &v235); v252 = 6; sub_4556D0(v235, v261, &v252); v34 = 0; v35 = 4 * v252; v252 = v35; sub_4556D0(v235, v261, &v252); v34 = 0; v35 = 4 * v252; v252 = v35; if ( v35 > 0 ) { do { v262[v34] = v260[v35 - v34 + 247]; ++v34; } while ( v34 < v35 ); } ++*(_DWORD *)v262;//第二处处理 v229[11] = mp_mul(&v215[14], v215[10], &v229[14], &v229[10]); v229[12] = 0; sub_4065C0(&v229[10], v40); v243[11] = mp_mul(&v229[14], v229[10], &v243[14], &v243[10]); v243[12] = v215[12] ^ v229[12]; sub_4065C0(&v243[10], v41); v202[11] = mp_mul(&v243[14], v243[10], &v202[14], &v202[10]); v202[12] = 0; sub_4065C0(&v202[10], v42); v243[11] = mp_mul(&v215[14], v39, &v243[14], &v243[10]); v243[12] = v215[12] ^ v202[12]; sub_4065C0(&v243[10], v43); sub_4067B0(&v243[10], &v191[10], &v229[10]); sub_4074B0(&v229[10]); v44 = (v229[11] + 7) >> 3; v252 = v44; sub_4065C0(&v229[10], v45); memset(v262, 0, v44); for ( m = 0; m < v44; *((_BYTE *)&v261[63] + v46 + 3) = v48 ) { v48 = *((_BYTE *)&v229[14] + m); v46 = v44 - m++; } ++*(_DWORD *)v262;......//第三处处理 mul((int)v215, v229, v215); mul((int)v215, v243, v229); mul((int)v243, v202, v243); mul((int)v202, v215, v243); mul((int)v215, v243, v229); sub_41AB20(v191); sub_41AF50(v191); v252 = (unsigned int)(v49 + 7) >> 3; sub_419780(v229, v262, v252); ++*(_DWORD *)v262;......//第四处处理 bignum_momve(&v215[3], 24, 1, 1, 0, 0, (unsigned int)v262); sub_43B620(&v229[3]); sub_43B620(&v243[3]); sub_43B620(&v202[3]); mul1(&v229[3], &v215[3], (int)&v215[3]); mul1(&v243[3], &v215[3], (int)&v229[3]); mul1(&v202[3], &v243[3], (int)&v229[3]); mul1(&v243[3], &v202[3], (int)&v202[3]); mul1(&v215[3], &v243[3], (int)&v202[3]); mul1(&v243[3], &v215[3], (int)&v229[3]); sub_43C460(&v229[3], (int)&v243[3], &v191[3]); sub_43B650(&v229[3], &v229[3], &v191[3]); sub_43B7A0((unsigned int)v262, &v252, 1, 1u, 0, 0, (int)&v229[3]); ++*(_DWORD *)v262;//第二处处理 v229[11] = mp_mul(&v215[14], v215[10], &v229[14], &v229[10]); v229[12] = 0; sub_4065C0(&v229[10], v40); v243[11] = mp_mul(&v229[14], v229[10], &v243[14], &v243[10]); v243[12] = v215[12] ^ v229[12]; sub_4065C0(&v243[10], v41); v202[11] = mp_mul(&v243[14], v243[10], &v202[14], &v202[10]);赞赏
他的文章
赞赏
雪币:
留言: