[GKCTF 2021]Crash
首先查壳,64bit,elf文件
刚解压完发现只有一个文件,大小足足有2M,我感觉不太简单,ida64, 定位到main函数
main_main()关键部分我看到fmt_Fprintln这个的时候就反应过来了,这是道go的题。
头一次做go的题,没有基础,就试着一点一点分析了:(很多地方都参考了wp)
首先分析main函数关键部分
if ( flag[1] == 43 && *(_DWORD *)v0 == 'TCKG' && *(_WORD *)(v0 + 4) == '{F' && *(_BYTE *)(v0 + 42) == '}' )
{
main_check(*flag, 0x2BuLL);
if ( v1 )
{
v6[0] = &unk_523A20;
v6[1] = &off_5724B0;
fmt_Fprintln((__int64)&off_574420, qword_625B28, (__int64)v6, 1LL, 1LL);
}
满足if条件后执行main_check函数
main_check()void __golang main_check(__int64 a1, unsigned __int64 a2)
{
__int64 v2; // [rsp+10h] [rbp-68h]
__int64 v3; // [rsp+10h] [rbp-68h]
__int64 v4; // [rsp+18h] [rbp-60h]
char v5; // [rsp+18h] [rbp-60h]
__int64 v6; // [rsp+18h] [rbp-60h]
char v7; // [rsp+18h] [rbp-60h]
__int64 v8; // [rsp+18h] [rbp-60h]
__int64 v9; // [rsp+20h] [rbp-58h]
__int64 v10; // [rsp+20h] [rbp-58h]
char v11[32]; // [rsp+30h] [rbp-48h] BYREF
char v12[32]; // [rsp+50h] [rbp-28h] BYREF
if ( a2 < 0x1E )
runtime_panicSliceAlen();
v2 = main_encrypto(a1 + 6, 24LL);
if ( v4 == 44 )
{
v9 = runtime_memequal(v2, (__int64)"o/aWPjNNxMPZDnJlNp0zK5+NLPC4Tv6kqdJqjkL0XkA=", 44LL, 44);
if ( v5 )
{
if ( a2 < 0x22 )
runtime_panicSliceAlen();
v6 = runtime_stringtoslicebyte((__int64)v11, a1 + 30, 4LL);
Encrypt_HashHex2(v6, v9);
if ( v9 == 64 )
{
v10 = runtime_memequal(
v6,
(__int64)"6e2b55c78937d63490b4b26ab3ac3cb54df4c5ca7d60012c13d2d1234a732b74",
64LL,
v6);
if ( v7 )
{
if ( a2 < 0x26 )
runtime_panicSliceAlen();
v8 = runtime_stringtoslicebyte((__int64)v12, a1 + 34, 4LL);
Encrypt_HashHex5(v8, v10);
if ( v10 == 128 )
{
runtime_memequal(
v8,
(__int64)"6500fe72abcab63d87f213d2218b0ee086a1828188439ca485a1a40968fd272865d5ca4d5ef5a651270a52ff952d955c9"
"b757caae1ecce804582ae78f87fa3c9",
128LL,
v8);
if ( (_BYTE)v8 )
{
if ( a2 < 0x2A )
runtime_panicSliceAlen();
main_hash(a1 + 38, 4LL);
if ( v8 == 32 )
runtime_memequal(v3, (__int64)"ff6e2fd78aca4736037258f0ede4ecf0", 32LL, 32);
}
}
}
}
}
}
}
里面的逻辑就是把flag分为四部分,然后分别进行了不同的加密
第一部分v2 = main_encrypto(a1 + 6, 24LL);
if ( v4 == 44 )
{
v9 = runtime_memequal(v2, (__int64)"o/aWPjNNxMPZDnJlNp0zK5+NLPC4Tv6kqdJqjkL0XkA=", 44LL, 44);
main_encrypto()
__int64 __usercall main_encrypto@(__int64 a1, __int64 a2) { __int64 v3; // [rsp+18h] [rbp-100h] __int64 v4; // [rsp+20h] [rbp-F8h] __int64 v5; // [rsp+20h] [rbp-F8h] __int64 v6; // [rsp+28h] [rbp-F0h] __int64 v7; // [rsp+48h] [rbp-D0h] __int64 v8; // [rsp+60h] [rbp-B8h] __int64 v9; // [rsp+68h] [rbp-B0h] __int64 v10; // [rsp+70h] [rbp-A8h] __int64 v11; // [rsp+78h] [rbp-A0h] char v12[32]; // [rsp+B0h] [rbp-68h] BYREF __int64 v13; // [rsp+D0h] [rbp-48h] __int64 v14; // [rsp+D8h] [rbp-40h] __int64 v15; // [rsp+E0h] [rbp-38h] __int64 v16; // [rsp+E8h] [rbp-30h] __int64 v17; // [rsp+F0h] [rbp-28h] __int64 *v18; // [rsp+F8h] [rbp-20h] _QWORD v19[2]; // [rsp+100h] [rbp-18h] BYREF v18 = (__int64 *)runtime_newobject((__int64)" "); v6 = encoding_json_Unmarshal((__int64)off_61E540, qword_61E548, qword_61E550, (__int64)"b", (__int64)v18); v13 = *v18; v10 = v18[1]; v14 = v18[2]; v11 = v18[3]; v15 = runtime_stringtoslicebyte(0LL, a1, a2); v16 = runtime_stringtoslicebyte((__int64)v12, v13, v10); v3 = runtime_stringtoslicebyte(0LL, v14, v11); Encrypt_DesEncrypt(v15, v4, v6, v16, v4, v6, v3, v4); v17 = v7; if ( v8 ) { v19[0] = *(_QWORD *)(v8 + 8); v19[1] = v9; fmt_Fprintln((__int64)&off_574420, qword_625B28, (__int64)v19, 1LL, 1LL); } encoding_base64___ptr_Encoding__EncodeToString(qword_625AD0, v17); return v5; }
在其中代码里找到了Encrypt_DesEncrypt()函数,由于是以encrypt命名的,所以猜测代码的加密在这个函数里,继续查看该函数内部,该函数内部第一个crypto_des_NewTripleDESCipher函数引起了注意,其内部是这样的
__int64 __usercall crypto_des_NewTripleDESCipher@(__int64 a1, __int64 a2) { __int64 v3; // [rsp+20h] [rbp-10h] if ( a2 != 24 ) return runtime_convT64(a2); v3 = runtime_newobject((__int64)&unk_534820); crypto_des___ptr_desCipher__generateSubkeys(v3, a1, 8LL); crypto_des___ptr_desCipher__generateSubkeys(v3 + 128, a1 + 8, 8LL); crypto_des___ptr_desCipher__generateSubkeys(v3 + 256, a1 + 16, 8LL); return v3; }
去查看了一下wp,发现这是3des加密算法,然后搜集了一些3des加密算法的信息,要解密的话需要得到密钥,一般的题目好像都会有welcome这样的话,我就直接搜素了一下,然后直接找到了key 和 iv,然后要加密的字符串是"o/aWPjNNxMPZDnJlNp0zK5+NLPC4Tv6kqdJqjkL0XkA="
然后就模仿wp放在在线解密工具中,得到了第一部分
87f645e9-b628-412f-9d7a-第二部分加密
Encrypt_HashHex2(44LL, v4);
if ( v4 == 64 )
{
runtime_memequal(44LL,(__int64)"6e2b55c78937d63490b4b26ab3ac3cb54df4c5ca7d60012c13d2d1234a732b74");
}
Encrypt_HashHex2()
__int64 __usercall Encrypt_HashHex2@(__int64 a1, __int64 a2, __int64 a3) { __int128 v4; // [rsp+18h] [rbp-50h] __int64 v5; // [rsp+18h] [rbp-50h] __int64 v6; // [rsp+20h] [rbp-48h] __int64 v7; // [rsp+48h] [rbp-20h] __int64 v8; // [rsp+50h] [rbp-18h] __int64 v9; // [rsp+58h] [rbp-10h] v8 = Encrypt_Sha256(a1, a2, a3); v7 = 2 * v6; v9 = runtime_makeslice((__int64)&unk_523B60, 2 * v6, 2 * v6); *((_QWORD *)&v4 + 1) = encoding_hex_Encode(v9, v7, v7, v8); runtime_slicebytetostring(0LL, v9, v7, v4); return v5; }
可知这个是sha256加密
直接上python爆破
import hashlib
hash="6e2b55c78937d63490b4b26ab3ac3cb54df4c5ca7d60012c13d2d1234a732b74"
for i in range(90000000):
pwd1=hex(i)
pwd1=pwd1[2:]
h1=hashlib.sha256(pwd1.encode('utf-8')).hexdigest()
#print(h1)
if h1==hash:
print(hex(i))
break
#0xe402
第三部分加密
Encrypt_HashHex5(v8, v10);
if ( v10 == 128 )
{
runtime_memequal(v8,(__int64)"6500fe72abcab63d87f213d2218b0ee086a1828188439ca485a1a40968fd272865d5ca4d5ef5a651270a52ff952d955c9b757caae1ecce804582ae78f87fa3c9", 128LL,v8);
Encrypt_HashHex5()
__int64 __usercall Encrypt_HashHex5@(__int64 a1, __int64 a2, __int64 a3) { __int64 v4; // [rsp+18h] [rbp-50h] __int128 v5; // [rsp+18h] [rbp-50h] __int64 v6; // [rsp+18h] [rbp-50h] __int64 v7; // [rsp+20h] [rbp-48h] __int64 v8; // [rsp+48h] [rbp-20h] __int64 v9; // [rsp+50h] [rbp-18h] __int64 v10; // [rsp+58h] [rbp-10h] v9 = Encrypt_Sha512(a1, a2, a3); v8 = 2 * v7; runtime_makeslice((__int64)&unk_523B60, 2 * v7, 2 * v7, v9); v10 = v4; *((_QWORD *)&v5 + 1) = encoding_hex_Encode(v4, v8, v8, v9); runtime_slicebytetostring(0LL, v10, v8, v5); return v6; }
可知是sha512加密,上python
import hashlib
hash="6500fe72abcab63d87f213d2218b0ee086a1828188439ca485a1a40968fd272865d5ca4d5ef5a651270a52ff952d955c9b757caae1ecce804582ae78f87fa3c9"
for i in range(90000000):
pwd1=hex(i)
pwd1=pwd1[2:]
h1=hashlib.sha512(pwd1.encode('utf-8')).hexdigest()
if h1==hash:
print(hex(i))
break
#0xf20a
第四部分加密
main_hash(a1 + 38, 4LL); if ( v8 == 32 ) runtime_memequal(v3, (__int64)"ff6e2fd78aca4736037258f0ede4ecf0", 32LL, 32);main_hash()函数
__int64 __usercall main_hash@(__int64 a1, __int64 a2) { const char *v2; // rdi __int128 v4; // [rsp+18h] [rbp-78h] __int64 v5; // [rsp+28h] [rbp-68h] __int128 v6; // [rsp+48h] [rbp-48h] BYREF char v7[32]; // [rsp+58h] [rbp-38h] BYREF __int128 v8; // [rsp+78h] [rbp-18h] *(_QWORD *)&v4 = runtime_stringtoslicebyte((__int64)v7, a1, a2); crypto_md5_Sum(v4); v6 = v4; v8 = 0LL; *(_QWORD *)&v8 = runtime_convT2Enoptr((__int64)&unk_524360, (__int64)&v6); *((_QWORD *)&v8 + 1) = v4; fmt_Sprintf(v2); return v5; }
可知是md5加密
网上找md5在线解密,但是没有找到一个可以正确解密出来的,直接用python写了(自己写不出来,还是wp里面的)
解密
import itertools
import string
import hashlib
def md5crash(sha256enc):
code = ''
strlist = itertools.product(string.ascii_letters + string.digits, repeat=4)
for i in strlist:
code = i[0] + i[1] + i[2] + i[3]
encinfo = hashlib.md5(code.encode()).hexdigest()
if encinfo == sha256enc:
return code
flag = md5crash("ff6e2fd78aca4736037258f0ede4ecf0")
print(flag)
#f940
最后的flag是
GKCTF{87f645e9-b628-412f-9d7a-e402f20af940}
这绝对是我做过最难的题目了
还发现一个奇怪的事情,第一次ida64打开该文件时,main_check函数里面四个runtime_memequal()函数都没有参数,但是第二次再打开,它又突然显示出来了所有的参数。
参考wp:
GKCTF 2021 Re复现_Pvr1sC的博客-CSDN博客
2021GKCTF re wp_yaoxixixi的博客-CSDN博客


![BUU [GKCTF 2021]Crash BUU [GKCTF 2021]Crash](http://www.mshxw.com/aiimages/31/938801.png)
