# **FPTU SECATHON 2024** # Summary - Reverse Engineering - [RE1](#RE1) - [RE2](#RE2) - [RE3](#RE3) - [Horrible childhood memories](#Horrible-childhood-memories) - [MiniSteg](#MiniSteg) - [Nothing there](#Nothing-there) - [Mov](#Mov) - Forensics - [No suspicious](#No-suspicious) # Reverse Engineering ## RE1 ### Description ![image](https://hackmd.io/_uploads/r1GGUrImA.png) ### Solution Sau khi mình nhận được file và kiểm tra thì biết đây là 1 file ELF64 ![image](https://hackmd.io/_uploads/Hk1-q1Im0.png) Sau đó, mình đã sử dụng decompiler để decompile file này. Tại hàm main, mình có thấy 2 array cùng với đoạn check đáng chú ý này (Câu if bên trên chỉ là kiểm tra độ dài của ký tự bên trong 2 dấu ngoặc nhọn thôi) ![image](https://hackmd.io/_uploads/SyHB5y87C.png) Tại hàm check, mình thấy được sẽ có việc lấy từng phần tử của dãy đầu trừ đi từng phần tử dãy sau ![image](https://hackmd.io/_uploads/rkAt5JUmC.png) Nên mình đã viết nhanh 1 đoạn script bằng Python để tìm ra license key ```python! v7 = [168,193,122,172,158,108,206,153,175,175,194,189,141,127,101,202,208,116,149,160,146,179,114,143,187,159,126,109,174,156,185,120,164,189,112,120,123,145] v8 = [53,87,22,73,48,1,91,53,58,62,89,74,35,28,1,92,99,17,41,45,29,79,10,44,68,58,11,12,72,38,83,2,67,74,12,5,23,45] for i in range(len(v7)): print(chr(v7[i] - v8[i]), end = "") ## OUTPUT sjdcnksduqisjcdnmclsudhcwesafvfvasdsdd ``` Nghi ngờ rằng đoạn mình nhận được bị sai, nên mình có kiểm tra lại và nó lại là đúng ![image](https://hackmd.io/_uploads/rJZe2JUXC.png) Flag: `FUSec{sjdcnksduqisjcdnmclsudhcwesafvfvasdsdd}` ## RE2 ### Description ![image](https://hackmd.io/_uploads/HkmVISL7A.png) ### Solution Sau khi nhận được file và kiểm tra, mình biết được đây là 1 file ELF64 ![image](https://hackmd.io/_uploads/Sylv2yLQC.png) Mình đã load file vào decompiler để xem có những gì. Sau khi load xong, mình có thấy 1 hàm để check debug nên nghĩ chắc bài này cần debug rồi ![image](https://hackmd.io/_uploads/rkEohJIQC.png) Sau khi check debug, sẽ đến đoạn modify lại key và tiếp đến là compare. Tại hàm modifyString, mình có thấy việc sẽ đảo ngược lại ký tự bên trong 2 dấu ngoặc nhọn ![image](https://hackmd.io/_uploads/rJH3pJ8mC.png) Sau khi modifyString xong, sẽ đến đoạn compare ![image](https://hackmd.io/_uploads/H10eRJL7R.png) Tại hàm compare này, có việc tạo ra 1 cái Serial, tham số truyền vào hàm tạo ra Serial chính là username. Tại hàm generateSerial, mình thấy có 1 hàm scrambleData, và sẽ truyền username sau khi thêm 'youfoundme' vào hàm này ![image](https://hackmd.io/_uploads/Sy3_0JI7C.png) Hàm scrambleData này thực chất chỉ thực hiện việc XOR từng giá trị 1 với 171. Tiếp theo sau khi thực hiện xong sẽ chuyển giá trị từ bytes -> string. Ví dụ: ``` byte: 0xcd -> 2 chars: cd (bytes: 0x63,0x64) ``` Sau đó, chương trình sẽ thực hiện việc kiểm tra nội dung bên trong `FUSec{` và `}` với string vừa lấy được ![image](https://hackmd.io/_uploads/BkekLyg8QC.png) Đề bài yêu cầu username là fpt, nên mình đã viết nhanh 1 đoạn script để lấy key ```python! username = 'fptyoufoundme' key = "" for c in username: key += hex(ord(c) ^ 171)[2:] key = "FUSec{" + key[::-1] + "}" print(key) ## OUTPUT FUSec{ec6cfc5ced4cdced4c2dfdbddc} ``` Sau đó mình chạy thử lại với chương trình để kiểm tra và thành công lấy được flag (Trong lúc làm bài này, debugger của mình như bị quỷ đớ nhập ý, nó bị abcxyz ngay từ lúc bắt đầu load file vào decompiler, phải tắt đi bật lại ạ) ![image](https://hackmd.io/_uploads/B1eXxxLXR.png) Flag: `FUSec{ec6cfc5ced4cdced4c2dfdbddc}` ## RE3 ### Description ![image](https://hackmd.io/_uploads/HyYLUrL7C.png) ### Solution Sau khi nhận được file, mình kiểm tra và nhận ra file bị pack bởi UPX và là file ELF64 ![image](https://hackmd.io/_uploads/rJ0rXcDXA.png) Unpack xong, mình sử dụng decompiler để xem file này có những gì ![image](https://hackmd.io/_uploads/rJT3ex8mR.png) Tại hàm main, mình có thấy sẽ truyền vào 1 arg là get_flag và có thêm 1 arg nữa, tuy nhiên khi truyền vào là get_flag thì sẽ đến bước decrypt_flag và mình xem trong này có gì ![image](https://hackmd.io/_uploads/rJXlWxIQC.png) Trong này, sẽ lấy arg thứ 2 và kiểm tra với secretflagkey, nếu đúng thì sẽ thực hiện in flag còn sai thì thôi. Giờ việc mình làm chỉ là chạy chương trình với 2 arg là `get_flag` và `secretflagkey` rồi lấy flag ( 🤡 Bài này hề vc) ![image](https://hackmd.io/_uploads/H1pIbl8Q0.png) Flag: `FUSec{Y0ugotm2friendscongrat}` ## Horrible childhood memories ### Description ![image](https://hackmd.io/_uploads/HkKY8rU7A.png) ### Solution Sau khi extract ra, mình sort lại theo thời gian để xem file nào được chỉnh sửa gần nhất và biết được đó là file EOSClient.exe ![image](https://hackmd.io/_uploads/BkJnbeLXA.png) Tiếp theo, mình kiểm tra thì biết được đây là file PE32 được viết bằng .NET ![image](https://hackmd.io/_uploads/Sk-kMgL7R.png) Mình sử dụng dnSpy cho tiết mục này. Tại Program, mình có thấy gọi AuthenticateForm() ![image](https://hackmd.io/_uploads/rkV4fgImC.png) Và mình đã xem bên trong AuthenticateForm có gì ![image](https://hackmd.io/_uploads/HJn8MxLXC.png) Hơ cái gì đây, tại btnLogin_Click lại có flag bị encode base64 à ![image](https://hackmd.io/_uploads/S1xYMx8QR.png) Trong Base64Encoding, mình có thấy gọi đến SixBitToChar ![image](https://hackmd.io/_uploads/SJZazlL7A.png) Đơn giản thì cái này nó chỉ là 1 cái dict không hơn không kém. Nên mình sử dụng CyberChef cho tiết mục lấy flag (Cơ mà char map bị thay đổi nên cần lấy theo char map ở trong file này) ![image](https://hackmd.io/_uploads/S1jH7x8mR.png) Flag: `FUSec{IAM101_n0w_try_the_Re4L_0n3}` ## MiniSteg ### Description ![image](https://hackmd.io/_uploads/BJGiLHLmR.png) ### Solution Sau khi kiểm tra file nhận được, mình biết đây là 1 file PE64. ![image](https://hackmd.io/_uploads/S1kJEl8mA.png) Vì vậy nên mình đã load vào trình decompile để xem nó làm gì. Nhìn qua thì khá giống với Golang và file có vẻ đã bị strip hay gì gì đấy 🙂 ![image](https://hackmd.io/_uploads/Bk-LNgUX0.png) Bằng vài lần nghịch ngu nên mình đã nhanh chóng xác định được hàm main của cái này. Hàm main của nó đây, cái được bôi vàng ý ![image](https://hackmd.io/_uploads/rkn5EgLQC.png) Tại hàm này, sẽ thực hiện việc gì gì đó mà cần truyền vào 1 arg ![image](https://hackmd.io/_uploads/BJ4pNlIXA.png) Sau khi có được arg đó thì sẽ đến hàm xử lý (mình nghĩ là đoạn giấu gì đó vào file ảnh thôi). Tại đây, mình thấy khá nghi ngờ cái v4 này và nó chỉ được truyền vào `sub_4019d4` ![image](https://hackmd.io/_uploads/HJ4bHxUmA.png) Tại hàm `sub_4019d4` có thực hiện tính toán gì đó với cái này ![image](https://hackmd.io/_uploads/SJCEBlIQC.png) Mình đã viết nhanh 1 đoạn script để xem kết quả và tđn lấy luôn được flag ```python! v4 = [0xE7,0xF6,0xF4,0x06,0x04,0x1C,0xEF,0xD1,0x18,0x00,0xFA,0xD1,0x16,0x00,0xEC,0x0F,0xD1,0x18,0x00,0xE9,0xD1,0x18,0x00,0xF5,0xD1,0x00,0xE9,0xD2,0xE5,0xE6,0x00,0xEA,0xD7,0xD7,0x1E,0x23] for i in v4: print(chr((i - 5793) % 256), end = "") ## OUTPUT FUSec{N0w_Y0u_Kn0w_H0w_T0_H1DE_I66} ``` Flag: `FUSec{N0w_Y0u_Kn0w_H0w_T0_H1DE_I66}` ## Nothing there ### Description ![image](https://hackmd.io/_uploads/HyUpUrI7A.png) ### Solution Sau khi kiểm tra file, mình biết file này đã bị pack và là file PE32 ![image](https://hackmd.io/_uploads/ByHgveUmC.png) Mình đã quyết định học nhanh 1 khóa unpack ASPack tại [Youtube](https://www.youtube.com/watch?v=Oejq7_mH3IM&ab_channel=UrielKosayev). Sau khi Unpack xong, mình có thấy tại hàm main sẽ có Inject gì đó vào tiến trình - Tại hàm main: ![image](https://hackmd.io/_uploads/SklKvg8QR.png) - Đoạn inject: ![image](https://hackmd.io/_uploads/SkijvxI7C.png) Thấy có sử dụng dữ liệu tại `&unk_2C8F58` cùng với cái chỗ này không bị encrypt nên mình lấy ra luôn xem nó có những gì. Và đây là kết quả ![image](https://hackmd.io/_uploads/S1LgOeU7C.png) Có kết nối ra bên ngoài, có nhận dữ liệu từ bên ngoài, có việc so sánh dữ liệu và in ra (Mình đã khá tốn thời gian vì chỉ chăm chăm vào việc kiểm tra mà không để ý cái in ra). Nó sẽ có in v16 và v16 là kết quả của `sub_5D12CB()` và trong cái hàm đó sẽ trả về 1 array và nhìn nhanh thì cũng biết là chữ cái đọc được (hàm `sub_5D90B0` được gọi trong `sub_5D12CB` ) ![image](https://hackmd.io/_uploads/BykvdgUm0.png) Mình lấy thử đống đấy ra đọc thử thì thấy có 1 đoạn hex khá đáng ngờ. Mình có viết nhanh 1 script để thực hiện việc này (Trông dài thế thôi chứ chả có gì) ```python! result = [0] * 0xf8 result[20] = 53 result[99] = 121 result[66] = 105 result[21] = 102 result[91] = 99 result[41] = 51 result[83] = 118 result[22] = 54 result[52] = 54 result[62] = 0 result[8] = 54 result[0] = 52 result[104] = 118 result[33] = 50 result[32] = 55 result[70] = 107 result[123] = 118 result[94] = 117 result[67] = 111 result[57] = 51 result[68] = 99 result[114] = 115 result[12] = 54 result[88] = 115 result[85] = 118 result[120] = 104 result[36] = 55 result[76] = 99 result[115] = 107 result[72] = 112 result[111] = 100 result[16] = 54 result[40] = 51 result[25] = 102 result[55] = 51 result[121] = 118 result[65] = 99 result[96] = 107 result[11] = 98 result[46] = 55 result[113] = 98 result[7] = 53 result[44] = 53 result[14] = 55 result[29] = 51 result[48] = 55 result[10] = 55 result[35] = 49 result[56] = 55 result[116] = 106 result[95] = 103 result[31] = 55 result[81] = 107 result[51] = 48 result[82] = 99 result[117] = 106 result[87] = 100 result[86] = 122 result[1] = 54 result[53] = 51 result[23] = 49 result[2] = 53 result[71] = 110 result[101] = 121 result[73] = 122 result[105] = 106 result[45] = 102 result[28] = 51 result[74] = 121 result[77] = 122 result[100] = 106 result[27] = 50 result[118] = 99 result[119] = 97 result[60] = 55 result[47] = 48 result[39] = 52 result[92] = 102 result[13] = 52 result[84] = 120 result[3] = 53 result[18] = 55 result[34] = 51 result[109] = 104 result[107] = 121 result[54] = 51 result[63] = 117 result[49] = 50 result[102] = 110 result[19] = 48 result[4] = 53 result[78] = 118 result[43] = 101 result[93] = 109 result[112] = 115 result[89] = 105 result[122] = 109 result[79] = 118 result[97] = 107 result[9] = 51 result[90] = 116 result[103] = 103 result[98] = 119 result[80] = 122 result[42] = 54 result[24] = 53 result[61] = 100 result[75] = 117 result[38] = 55 result[37] = 52 result[6] = 54 result[106] = 108 result[110] = 117 result[15] = 53 result[50] = 51 result[69] = 120 result[5] = 51 result[108] = 112 result[30] = 55 result[59] = 51 result[17] = 100 result[64] = 121 result[58] = 55 result[26] = 55 for i in result: print(chr(i), end = "") ``` Output: ![image](https://hackmd.io/_uploads/rJqtYl8XC.png) Sau khi ném đống hex này lên CyberChef thì mình lấy được flag ![image](https://hackmd.io/_uploads/HyB3tlUmR.png) Flag: `FUSec{dump_a_r3wr1tt3n_pr0c3ss}` ## Mov ### Description ![image](https://hackmd.io/_uploads/ryhVSGw70.png) ### Solution Sau khi lấy được file, mình có kiểm tra xem đây là file gì và biết là file ELF32 ![image](https://hackmd.io/_uploads/rJZvOb5XR.png) Tiếp theo, mình load vào decompiler để xem có những gì và caideogiday,caigithenay ![image](https://hackmd.io/_uploads/ryw1tZqX0.png) Vâng, mình kéo 1 lượt, toàn `mov` với `mov`, chỉ có `mov` thôi. Bên cạnh đó, khi xem hàm `dispatch` và `sub_8049000` cùng 1 số loc ở gần đó thì thấy có lệnh `jmp` ![image](https://hackmd.io/_uploads/B1n8KWcXC.png) Đầu mình kiểu "Thôi xong rồi, ơ nhưng toàn lệnh mov như này thì không biết nó chạy sẽ thế nào". Mình quyết định chạy thử file và ahshiet, nó chạy bình thường như bình thường. ![image](https://hackmd.io/_uploads/rJZTh-5mA.png) Ngay lúc này mình nhận ra: "Thôi thì ốm đòn với việc debug rồi". Không để mất thời gian, mình bắt đầu setup ngay cho việc debug. ![image](https://hackmd.io/_uploads/ByaIYM5mA.png) Sau 1 thời gian debug, mình biết được cách hoạt động của cái file này. Mình có xem các hàm được import vào file. ![image](https://hackmd.io/_uploads/B1wcFzqmR.png) Đầu tiên, file sẽ import 1 sig sa_dispatch và 1 sig sa_loop (Mục đích làm gì hồi sau sẽ rõ) ![image](https://hackmd.io/_uploads/Sya5qz9mR.png) Tiếp theo sẽ chạy hết 1 lượt từ _start -> read_string -> check -> main Sẽ không có gì xảy ra cả vì cuối hàm này là lệnh mov và đầu hàm kia là lệnh mov. ![image](https://hackmd.io/_uploads/ry7l3McmC.png) Tuy nhiên, tại cuối hàm main thì lại có 2 bytes 0x8E và 0xC8 ![image](https://hackmd.io/_uploads/rkZ72G5QR.png) Quay lại các hàm đã import vào file, thì làm sao để có thể gọi được các hàm đó. Khi mình chạy debug lần đầu, chạy đến đoạn mov offset của `malloc` vào external ![image](https://hackmd.io/_uploads/rk5ohfcXR.png) Sau khi chạy đến `mov eax, [eax]`, ngay lúc đó tại thanh ghi eax đang là giá trị 0x0 ![image](https://hackmd.io/_uploads/HyVA2MqXC.png) Khi chạy tiếp, sẽ nhảy vào exception. ![image](https://hackmd.io/_uploads/HJo1pGqXC.png) `Pass to app`, mình sẽ nhảy vào dispatch và jump đến offset được lưu trong external ![image](https://hackmd.io/_uploads/B1nmTM57A.png) Tiếp tục thì mình đã vào được thư viện và thực thi hàm đó ![image](https://hackmd.io/_uploads/SkZLTfcmC.png) Thực thi xong, giá trị sẽ được trả về như mình sử dụng hàm 1 cách bình thường ![image](https://hackmd.io/_uploads/H1-T6G9QC.png) Vậy là mình cũng đã rõ được cách mà file gọi các hàm để thực thi. 2 giá trị `on` và `fault` sẽ đánh dấu xem hàm được load vào external có được thực thi hay không, nếu có thì sẽ nhảy vào exception do lệnh `mov eax, [eax]` tạo ra. Nhưng 1 điều là nếu như chạy hết hàm main rồi thì làm sao để có thể thực hiện tiếp các bước tiếp theo như nhập giá trị. Thì khi chạy đến đây, mình lại gặp exception tiếp ![image](https://hackmd.io/_uploads/B1fvAGq7R.png) Khi thực hiện tiếp, mình đã nhảy về master_loop, ngay bên dưới việc load sig ![image](https://hackmd.io/_uploads/r1750GcQ0.png) Mình đã suy ra được rằng file này sẽ chạy trong 1 vòng lặp vô hạn cho đến khi lệnh exit được thực hiện. Một vài lần chạy thử nữa được diễn ra, mình nhận ra rằng sau khi nhập 1 string vào, file sẽ kiểm tra độ dài với 0x23 (35 ký tự) ![image](https://hackmd.io/_uploads/Syyp17970.png) Để biết được việc kiểm tra độ dài được diễn ra tại đâu, hãy đọc cái [docs](https://kirschju.re/docs/jonischkeit-2016-demovfuscator.pdf) này. Mình tìm được khi tìm thấy repo [demovfuscator](https://github.com/leetonidas/demovfuscator) (Mình có thử tool này rồi nma sau khi chạy xong mình thấy code nó khó đọc hơn nên thôi mình quyết định làm việc với file ban đầu) Flow của file này sẽ là ``` -> Malloc -> Lấy input -> Check độ dài input -> Check từng ký tự của input -> Output ``` Biết được độ dài string là 35 ký tự, mình truyền vào đúng 35 ký tự và tiếp tục công cuộc debug. Thì việc kiểm tra flag sẽ diễn ra tại hàm `check`. Mình bắt đầu nhận ra có điều gì đó khá là lạ khi thấy các giá trị ở trong `c_array` sẽ được load trước chứ không phải các ký tự mình nhập vào. ![image](https://hackmd.io/_uploads/BkXqWm9QR.png) Và đây chính là các giá trị trong `c_array` ![image](https://hackmd.io/_uploads/S1ZaW75mA.png) Debug thêm 1 lúc, mình khá chắc rằng đoạn check này sẽ giống với đoạn pseudocode mình viết bằng python bên dưới ```python3! res = True for i in range(35): if(input[i] != (c_array[i] - i)): res = False return res ``` Để kiểm tra, mình có viết nhanh 1 đoạn python để chạy và lấy được kết quả ```python3! c_array = [0x42,0x34,0x4E,0x34,0x37,0x7B,0x6B,0x66,0x75,0x3C,0x69,0x78,0x3C,0x83,0x74,0x84,0x83,0x74,0x46,0x87,0x44,0x87,0x75,0x48,0x8B,0x78,0x88,0x4C,0x83,0x85,0x92,0x8C,0x54,0x93,0x55] for i in range(35): print(chr(c_array[i] - i), end = "") ## OUTPUT B3L13ve_m3_m0vfusc4t0r_1s_n1ghtm4r3 ``` Mình kiểm tra lại với file thực thi và thành công lấy được flag (Btw, mình thấy được rằng mình guessing khá nhiều ở bài này cũng như vẫn tồn tại lỗ hổng kiến thức về các registor, chạy debug và các thứ các thứ) ![image](https://hackmd.io/_uploads/SkzyLxcmA.png) Flag: `FUSec{B3L13ve_m3_m0vfusc4t0r_1s_n1ghtm4r3}` # Forensics ## No suspicious ### Description ![image](https://hackmd.io/_uploads/SyoVwSI70.png) ### Solution Sau khi lấy được file pcap, mở lên và đọc, mình có lấy được 1 file ELF là `treasure` ![image](https://hackmd.io/_uploads/r1fScgLQR.png) Extract file này và kiểm tra, mình biết được đây là 1 file ELF64 ![image](https://hackmd.io/_uploads/BJTvqg870.png) Tiếp theo, mình sử dụng decompiler để kiểm tra xem bên trong cái này có gì. Tại hàm main, mình có thấy việc có kết nối đến ip `4.236.191.192` port `443`. Có cả nhận dữ liệu, thực hiện shell và gửi dữ liệu đi ![image](https://hackmd.io/_uploads/SJRncl87C.png) Mình có thấy hàm `rc2` được gọi với key, có vẻ như là cho việc decrypt message được gửi tới cũng như encrypt message gửi đi. Trong hàm này sẽ thực hiện việc mã hóa cũng như giải mã. Tại hàm `rc2` này có thêm 2 hàm là `ksa` và `prga` ![image](https://hackmd.io/_uploads/ry94jx870.png) Hàm `ksa` phục vụ cho việc tạo key từ 16 bytes key được truyền vào ![image](https://hackmd.io/_uploads/r1bKjgLQR.png) Hàm `prga` phục vụ cho việc mã hóa cũng như giải mã ![image](https://hackmd.io/_uploads/SkkcjlI7A.png) Được rồi, flow của cái `treasure` này là: ``` -> Command bị mã hóa gửi đến -> Giải mã -> Thực hiện Command -> Mã hóa kết quả của command -> Gửi đi ``` Mình đã viết lại 1 cái script thực hiện lại 2 công việc encrypt cũng như decrypt (Tôi xin lỗi vì code ngu được chưa 🙂) ```python! from Crypto.Util.number import long_to_bytes key = [0x79,0xE1,0x0A,0x5D,0x87,0x7D,0x9F,0x46,0x49,0x41,0x2E,0x11,0x65,0xAC,0xE3,0x25] plain = long_to_bytes(<lừa>) plain = list(plain) s = list() for i in range(0xff+1): s.append(i) j = 0 for i in range(0xff+1): j = (s[i] + j + key[i % len(key)]) & 0xff #swap tmp = s[i] s[i] = s[j] s[j] = tmp i_0 = 0 j_0 = 0 for n in range(len(plain)): i_0 = (i_0 + 1) % 256 j_0 = (j_0 + s[i_0]) % 256 tmp = s[i_0] s[i_0] = s[j_0] s[j_0] = tmp print(chr(s[(s[i_0] + s[j_0]) & 0xff] ^ (plain[n])), end = "") ``` Quay trở lại file pcap, mình chắc chắn đã capture được quá trình nhận dữ liệu và gửi dữ liệu. Trước đó, khi phân tích file `treasure` mình đã lấy được ip nên mình sẽ filter ip này để tìm ra các package có dính líu đến ip này ![image](https://hackmd.io/_uploads/HJ_Qhg8QC.png) Và giờ chỉ cần lấy dữ liệu ra xem thôi, mình đã thử với package có độ dài lớn nhất và kết quả là - Package có độ dài lớn nhất: ![image](https://hackmd.io/_uploads/ryUchgI7C.png) - Kết quả sau khi decrypt: ![image](https://hackmd.io/_uploads/S1jtnl8XA.png) Và ok rồi đấy, giờ thử các package khác thôi, sau 1 hồi tìm tòi thì mình có tìm được flag - Package chứa flag: ![image](https://hackmd.io/_uploads/Byp6hlU7A.png) - Decrypt: ![image](https://hackmd.io/_uploads/B1Kk6eImA.png) Flag: `FUSec{f4k3_TLS_1s_s0m3th1ng_bruuhhh}`