本文主要是介绍BUU [GKCTF 2021]Crash,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
[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] BYREFchar 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@<rax>(__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] BYREFv18 = (__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@<rax>(__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@<rax>(__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@<rax>(__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@<rax>(__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] BYREFchar 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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!