-
-
[原创]2020KCTF春季赛 第二题 子鼠开天 WP
-
发表于: 2020-4-17 12:11 3807
-
文章里分析的是初版,也就是有多解的版本。
直接把程序拉到IDA,分析main函数,伪代码如下
int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // eax unsigned int namelen; // kr04_4 int result; // eax char name[97]; // [esp+8h] [ebp-12Ch] __int16 v7; // [esp+69h] [ebp-CBh] char v8; // [esp+6Bh] [ebp-C9h] char sn[197]; // [esp+6Ch] [ebp-C8h] __int16 v10; // [esp+131h] [ebp-3h] char v11; // [esp+133h] [ebp-1h] name[0] = 0; sn[0] = 0; memset(&name[1], 0, 0x60u); v7 = 0; v8 = 0; memset(&sn[1], 0, 0xC4u); v10 = 0; v11 = 0; v3 = time(0); sub_411AD8(v3); printf(aEnterYourName); scanf(Format, name); namelen = strlen(name) + 1; if ( namelen - 1 < 3 || namelen - 1 > 0x14 ) // 判断name的长度 { printf(aBadName); result = -1; } else { printf(aEnterYourSn); scanf(Format, sn); if ( strlen(sn) == 64 ) // sn长度是否为64 { checksn((int)name, namelen - 1, (int)sn, 64); result = 0; } else { printf(aBadSn); result = -1; } } return result; }
关键函数为checksn,伪代码如下
void __cdecl checksn(int name, unsigned int namelen, int sn, int snlen) { int hash[4]; // [esp+4h] [ebp-70h] char deresult[32]; // [esp+14h] [ebp-60h] char v6; // [esp+34h] [ebp-40h] char aesdecrypt; // [esp+54h] [ebp-20h] if ( namelen >= 3 && namelen <= 0x14 && snlen == 64 ) { if ( hexstrtodata((_WORD *)sn, 64, (int)&v6) != 32 || (aes((int)&v6, 32, (int)&aesdecrypt, (int)&key, 128, 0), RSA_decrypt((int)&aesdecrypt, 32, (int)deresult), deresult[0]) // aes+rsa || deresult[1] != 2 || deresult[15] ) { printf(aBadSn); } else { gethash((const void *)name, namelen, (int)hash); if ( !memcmp(hash, &deresult[16], 0x10u) )// 比较后0x10字节是否相同 printf(aCongratulation); } } }
sn先把hex字符串转成数据,再用AES和RSA解密,需要注意的是解密后的结果是0x20字节,最后比较的字节数只有0x10。
所以需要把解密结果的前0x10字节跟"KCTF"的hash拼接,再加密就可以得到flag了。
int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // eax unsigned int namelen; // kr04_4 int result; // eax char name[97]; // [esp+8h] [ebp-12Ch] __int16 v7; // [esp+69h] [ebp-CBh] char v8; // [esp+6Bh] [ebp-C9h] char sn[197]; // [esp+6Ch] [ebp-C8h] __int16 v10; // [esp+131h] [ebp-3h] char v11; // [esp+133h] [ebp-1h] name[0] = 0; sn[0] = 0; memset(&name[1], 0, 0x60u); v7 = 0; v8 = 0; memset(&sn[1], 0, 0xC4u); v10 = 0; v11 = 0; v3 = time(0); sub_411AD8(v3); printf(aEnterYourName); scanf(Format, name); namelen = strlen(name) + 1; if ( namelen - 1 < 3 || namelen - 1 > 0x14 ) // 判断name的长度 { printf(aBadName); result = -1; } else { printf(aEnterYourSn); scanf(Format, sn); if ( strlen(sn) == 64 ) // sn长度是否为64 { checksn((int)name, namelen - 1, (int)sn, 64); result = 0; } else { printf(aBadSn); result = -1; } } return result; }
关键函数为checksn,伪代码如下
int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // eax unsigned int namelen; // kr04_4 int result; // eax char name[97]; // [esp+8h] [ebp-12Ch] __int16 v7; // [esp+69h] [ebp-CBh] char v8; // [esp+6Bh] [ebp-C9h] char sn[197]; // [esp+6Ch] [ebp-C8h] __int16 v10; // [esp+131h] [ebp-3h] char v11; // [esp+133h] [ebp-1h] name[0] = 0; sn[0] = 0; memset(&name[1], 0, 0x60u); v7 = 0; v8 = 0; memset(&sn[1], 0, 0xC4u); v10 = 0; v11 = 0; v3 = time(0); sub_411AD8(v3); printf(aEnterYourName); scanf(Format, name); namelen = strlen(name) + 1; if ( namelen - 1 < 3 || namelen - 1 > 0x14 ) // 判断name的长度 { printf(aBadName); result = -1; } else { printf(aEnterYourSn); scanf(Format, sn); if ( strlen(sn) == 64 ) // sn长度是否为64 { checksn((int)name, namelen - 1, (int)sn, 64); result = 0; } else { printf(aBadSn); result = -1; } } return result; }
关键函数为checksn,伪代码如下
void __cdecl checksn(int name, unsigned int namelen, int sn, int snlen) { int hash[4]; // [esp+4h] [ebp-70h] char deresult[32]; // [esp+14h] [ebp-60h] char v6; // [esp+34h] [ebp-40h] char aesdecrypt; // [esp+54h] [ebp-20h] if ( namelen >= 3 && namelen <= 0x14 && snlen == 64 ) { if ( hexstrtodata((_WORD *)sn, 64, (int)&v6) != 32 || (aes((int)&v6, 32, (int)&aesdecrypt, (int)&key, 128, 0), RSA_decrypt((int)&aesdecrypt, 32, (int)deresult), deresult[0]) // aes+rsa || deresult[1] != 2 || deresult[15] ) { printf(aBadSn); } else { gethash((const void *)name, namelen, (int)hash); if ( !memcmp(hash, &deresult[16], 0x10u) )// 比较后0x10字节是否相同 printf(aCongratulation); } } }
sn先把hex字符串转成数据,再用AES和RSA解密,需要注意的是解密后的结果是0x20字节,最后比较的字节数只有0x10。
所以需要把解密结果的前0x10字节跟"KCTF"的hash拼接,再加密就可以得到flag了。
void __cdecl checksn(int name, unsigned int namelen, int sn, int snlen) { int hash[4]; // [esp+4h] [ebp-70h] char deresult[32]; // [esp+14h] [ebp-60h] char v6; // [esp+34h] [ebp-40h] char aesdecrypt; // [esp+54h] [ebp-20h] if ( namelen >= 3 && namelen <= 0x14 && snlen == 64 ) { if ( hexstrtodata((_WORD *)sn, 64, (int)&v6) != 32 || (aes((int)&v6, 32, (int)&aesdecrypt, (int)&key, 128, 0), RSA_decrypt((int)&aesdecrypt, 32, (int)deresult), deresult[0]) // aes+rsa || deresult[1] != 2 || deresult[15] ) { printf(aBadSn); } else { gethash((const void *)name, namelen, (int)hash); if ( !memcmp(hash, &deresult[16], 0x10u) )// 比较后0x10字节是否相同 printf(aCongratulation); } } }
sn先把hex字符串转成数据,再用AES和RSA解密,需要注意的是解密后的结果是0x20字节,最后比较的字节数只有0x10。
所以需要把解密结果的前0x10字节跟"KCTF"的hash拼接,再加密就可以得到flag了。
aes函数的最后一个参数是判断加解密的标志,改1就是加密。然后从RSA_decrypt函数里提取N和E,分解N得到P Q,算出D就可以了。
RSA的部分,用python实现
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
他的文章
看原图
赞赏
雪币:
留言: