-
-
[原创]2020KCTF春季赛 第二题 子鼠开天 WP
-
发表于: 2020-4-17 12:11 3988
-
文章里分析的是初版,也就是有多解的版本。
直接把程序拉到IDA,分析main函数,伪代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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,伪代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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,伪代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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,伪代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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实现
赞赏
他的文章
赞赏
雪币:
留言: