<h1>Hack The Box - Reversing (Hard Part 1)</h1> ![image](https://hackmd.io/_uploads/ryk7IcWl0.png) Ghi chú: <ul> <li>Hard: 1-6 challenge</li> <ul> <li><a href="#LicenseGenerator">1. LicenseGenerator</a></li> <li><a href="#ReRop">2. ReRop</a></li> <li><a href="#Vessel Cartographer">3. Vessel Cartographer</a></li> <li><a href="#Spell Weaving Exam">4. Spell Weaving Exam</a></li> <li><a href="#Convoluted Boot">5. Convoluted Boot</a></li> <li><a href="#Freaky Forum Interception">6. Freaky Forum Interception</a></li> </ul> </li> </ul> <h2>Difficulty: Hard </h2> <div id="LicenseGenerator"></div> <h3>Challenge 1: LicenseGenerator</h3> Arodor has been distributing promotional license keys to users across the world. We suspect that there could be some backdoor in this 'special gift' - can you investigate? <a href="https://drive.google.com/file/d/1TqS55gOKRDwFL-4df8GIUwpmaNXZzpLa/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Ta có được tệp thực thi`free-windows-license.exe` và một tệp gói tin `capture.pcapng` Mở chương trình trong DIE để xem tổng quan của tệp. ![image](https://hackmd.io/_uploads/BJfLIQ-ZR.png) Chương trình đã bị pack UPX, tiến hành unpack nó. ![image](https://hackmd.io/_uploads/ByyhUmWZC.png) Mở chương trình trong IDA. ![image](https://hackmd.io/_uploads/HkrrTU-WC.png) Chương trình đầu tiên sẽ gọi hàm `sub_401320` ![image](https://hackmd.io/_uploads/rkvDTUb-A.png) Hàm `sub_401200` có vẻ như trả về con trỏ của một hàm khác. Sau đó được gọi và giá trị trả về được dùng để trả về cho hàm main. Quan sát hàm `sub_401200` ![image](https://hackmd.io/_uploads/SkFHR8--0.png) Giá trị `byte_40453C ^ 0x69` nhằm tạo chuỗi `kernel32.dll` để lấy handle của module kernel32.dll. Từ đó dùng kĩ thuật API Hashing để tìm API tương ứng với giá trị. Ta viết chương trình để tìm các API được gọi :::info ```python import requests from bs4 import BeautifulSoup URL = "https://www.geoffchappell.com/studies/windows/win32/kernel32/api/" resp = requests.get(URL) h = resp.text soup = BeautifulSoup(h, 'html.parser') fns = [tag.text for tag in soup.find_all('span', class_='function')] print(fns) ``` ::: :::info ```cpp #include <immintrin.h> #include <iostream> #include <cstring> int main() { const char* names[] = { }; unsigned int initial_value = 0xFFFFFFFF; for (const char* name : names) { int v3 = 0x13371337; for ( int i = 0; i < strlen(name); ++i ) v3 = 0x6969 * (v3 ^ name[i]); if ( v3 == 0x7B3154AB || v3 == 0x7CD69675 || v3 == 0x75E2ACB5 || v3 == 0x6333EC90 || v3 == 0xF9FE50E0) { std::cout << "Hash for " << name << ": 0x" << std::hex << v3 << std::dec << std::endl; } } return 0; } ``` ::: Ta sẽ nhận được kết quả như sau: ![image](https://hackmd.io/_uploads/SkJmSkGZR.png) Vậy hàm `sub_401320` cấp phát và đưa vùng nhớ vào sử dụng, cho phép đọc, ghi, và thực thi mã trong vùng nhớ được cấp phát. ![image](https://hackmd.io/_uploads/HysQUyz-0.png) Sau khi được cấp vùng nhớ, chương trình ghi 0x514 byte lên vùng nhớ đó và đưa vào hàm `sub_401360`. Thế thì quan sát hàm đó thôi. ![image](https://hackmd.io/_uploads/SywMDkGWC.png) ![image](https://hackmd.io/_uploads/BkSKOkfbA.png) Chương trình tạo một Thread mới nhưng đưa nó vào trạng thái tạm dừng ngay sau khi được tạo. Với địa chỉ bắt đầu là địa chỉ đầu của vùng nhớ cấp phát ở trên . ![image](https://hackmd.io/_uploads/SJbbhkGZC.png) Giá trị `asc_404018 ^ 0x69` nhằm tạo chuỗi `ntdll.dll` để lấy handle của module ntdll.dll. Chương trình sẽ đặt thông tin cho Thread đó, giá trị 17 đại diện cho giá trị enum `ThreadInformationClass`, tương ứng với `ThreadHideFromDebugger`, với ý định giấu thread đang chạy khỏi debugger. Ta tóm tắt hoạt động như sau: * Cấp phát một vùng bộ nhớ mới trong quá trình thực thi. * Sao chép nội dung của địa chỉ sub_404028 vào vùng nhớ vừa cấp phát. * Tạo một luồng mới bằng cách sử dụng hàm CreateThread ở thạng thái tạm dừng. * Đặt thông tin cho luồng mới được tạo, giúp ẩn thread khỏi bất kỳ debugger nào đang theo dõi. * Tiếp tục luồng và chờ đợi luồng mới kết thúc. :::info ```cpp Buffer = VirtualAlloc( 0, 0x514, MEM_COMMIT, PAGE_EXECUTE_READWRITE); qmemcpy(Buffer, &sub_404028, 0x514u); Thread = CreateThread( &v5, 0, *this, 0, CREATE_SUSPENDED, 0); NtSetInformationThread(*this, 17, 0, 0); ResumeThread(*this); WaitForSingleObject(this, -1); ``` ::: Vậy phần chính của chúng ta là phân tích luồng được sử dụng. Đoạn phân tích Thread khá "đơn giản", chỉ mất công debug và đoán luồng hoạt động thôi. Các chuỗi được dùng trong Thread đều có thể tìm thông qua phép XOR, API Hashing. Ở đây mình không mô tả làm sao mình tìm được chuỗi và vì sao hiểu được luồng của nó, nó quá dài. Đoạn Thread hoạt động như sau: :::info ```cpp # Lấy module LoadLibraryA() từ danh sách mô-đun PEB Decrypt và Load ws2_32.dll Lấy các hàm connect(), gethostbyname(), socket(), send(), recv() Tạo chuỗi DNS "free-windows-license.uwu" Tạo kết nối đến free-windows-license.uwu:1337 # Giao tiếp C2 Gửi b"auth" đến máy chủ C2 Nhận 8 byte key - b"1337cafebabe0420" Mã hóa và gửi b"shellgen" Nhận độ dài của shellcode Nhận shellcode Giải mã shellcode bằng xorkey // Map shellcode Tìm kernel32.dll thông qua danh sách mô-đun PEB Lấy các hàm NtVirtualAlloc(), NtCreateThread(), NtWriteVirtualMemory(), NtWaitSingleObject() từ ntdll.dll Lấy GetCurrentProcess()) từ kernel32.dll Phân bổ một khu vực RWX mới Viết shellcode giải mã đã tải xuống vào khu vực // Patch shellcode Sửa các byte đầu tiên để định danh socket Cập nhật mảng khóa xor 1 Cập nhật mảng khóa xor 2 Tạo thread trong khu vực mới và đợi luồng // Downloaded Shellcode Giải mã FileGenerator từ tệp thực thi malware Tạo mảng xor Giải mã mảng xor Tạo mảng add (cộng) Giải mã mảng add Đọc một tệp thông qua FileGenerator Mã hóa sử dụng mảng xor ban đầu trả về từ C2 (được cập nhật bởi người gọi) Mã hóa sử dụng mảng add Mã hóa sử dụng mảng xor thứ hai Thuật toán rút gọn như sau: for i in range(payload_len): data[i] ^= c2xor[i % 8] for i in range(payload_len): data[i] = ctypes.c_uint8(data[i] - plus[i % 36]).value for i in range(payload_len): data[i] ^= second_xor[i % 44] Người gọi đã sửa trong hàm send Gửi tệp đã mã hóa đến C2 ``` ::: Quá trình tìm key của chúng ta như sau: với x~i~ là khóa cần tìm ![image](https://hackmd.io/_uploads/BysVbqEbA.png) Ta bỏ qua phần dữ liệu không phải là shellcode trong gói tin pcap đi và tiến hành giải mã toàn bộ quá trình trên :::info ```python import ctypes encfile = None with open("dump_shell", "rb") as fin: encfile = fin.read() obfarray = bytearray(b'uwuxxowo') key = bytearray(b'\x13\x37\xca\xfe\xba\xbe\x04\x20') final = bytearray(b'00000000') second_xor = bytearray(b'1t5_n0t_th4t_34sy_but_y0u_4r3_pr3tty_cl0s3:)') plus = bytearray(b'th1s_w1ll_sur3ly_k33p_th1s_pr0t3ct3d') for i in range(8): final[i] = obfarray[i] ^ key[i] print(final) data = bytearray(encfile) payload_len = len(encfile) for i in range(payload_len): data[i] ^= second_xor[i % 44] for i in range(payload_len): data[i] = ctypes.c_uint8(data[i] - plus[i % 36]).value for i in range(payload_len): data[i] ^= final[i % 8] with open("image.png", "wb+") as fout: fout.write(data) ``` ::: ![image](https://hackmd.io/_uploads/Sy9IX9N-0.png) :::success ``` Flag: HTB{1t_w4snt_4fr33_l1c3ns3_4ft3r_4ll} ``` ::: <div id="ReRop"></div> <h3>Challenge 2: ReRop</h3> How is that even possible, I thought it was only an exploitation technique, but maybe it has other applications as well <a href="https://drive.google.com/file/d/1JkWLVOh4xR90ksNhB86hzHYQC5PWQALz/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> <div id="Vessel Cartographer"></div> <h3>Challenge 3: Vessel Cartographer</h3> You finally manage to remotely connect to a computer onboard the alien vessel to shutdown the defense mechanisms. However, it instantly starts acting up and ends up deploying malware as a defense mechanism. All your documents including your hard earned map of the vessel topology is now encrypted. <a href="https://drive.google.com/file/d/1wckMt6oeQMBrcdo-o0KmLMX0opRVPupm/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Ta có được tệp thực thi`free-windows-license.exe` và một tệp gói tin `capture.pcapng` Mở chương trình trong DIE để xem tổng quan của tệp. ![image](https://hackmd.io/_uploads/ByqYw04ZR.png) Chương trình đã bị pack UPX, tiến hành unpack nó. ![image](https://hackmd.io/_uploads/ryH0P0EWC.png) Mở chương trình trong IDA. Ta sẽ chú ý đến có hàm TLS Callback - cho phép chỉ định một hàm callback được thực thi cụ thể cho mỗi thread khi thread đó bắt đầu hoạt động hoặc kết thúc. Tức là nó sẽ được thực thi trước hàm main ![image](https://hackmd.io/_uploads/Bk9A_0Eb0.png) Hàm này kiểm tra xem có debugger nào đang chạy không bằng cách sử dụng hàm IsDebuggerPresent() từ Windows API. Ta sửa lệnh nhảy loc_140001077, tức là 0x74 -> 0xEB. ![image](https://hackmd.io/_uploads/Sk5KFREWA.png) `Hàm sub_140001080` có vẻ như trả về con trỏ của một hàm khác. Ta gọi nó là GetFunction() ![image](https://hackmd.io/_uploads/ByWMjR4Z0.png) Chương trình sẽ lấy chuỗi `byte a6L ^ 0x42` để tạo chuỗi `ntdll.dll` và dùng kĩ thuật API Hashing để tìm API cần thiết trong module ntdll.dll ![image](https://hackmd.io/_uploads/HyQxj0EbC.png) Thực thi động, ta được hai API đó là: NtAllocateVirtualMemory và NtWriteVirtualMemory .Ta đọc tiếp hàm `sub_140001590` và chú ý đến chương trình thực hiện XOR mảng cục bộ với 0xA6. Đây có thể là phép giải mã nhằm tạo hàm thực thi. ![image](https://hackmd.io/_uploads/ByN40REbA.png) Sau đó, chương trình cấp phát một phần của vùng nhớ ảo của tiến trình với quyền đọc, ghi, thực thi và ghi dữ liệu từ biến toàn cục vào vùng nhớ được cấp phát. ![image](https://hackmd.io/_uploads/SkhgDkHW0.png) `Hàm sub_140001290`, chương trình sẽ tìm kiếm và lấy thông tin tất cả các tệp và thư mục với đường dẫn được đề cập. Các tập tin không phải là thư mục sẽ được xử lý. Sau đó, tập tin được mở và kích thước của nó được lấy. Một vùng nhớ được cấp phát với kích thước tương ứng và nội dung của tập tin được đọc vào đó. ![image](https://hackmd.io/_uploads/BybpPlBZR.png) Tiếp theo, một hàm không xác định được gọi với hai con trỏ và kích thước vùng nhớ chứa nội dung tập tin đã đọc. Nó chứa hai lệnh gọi hàm, lệnh gọi hàm đầu tiên nhận ba tham số ( hai biến cục bộ + một chưa biết) và hàm thứ hai nhận có hai tham số (nội dung tệp, độ dài tệp). Sau khi mã hóa xong sẽ thêm vào tên tện chuỗi "owo". ![image](https://hackmd.io/_uploads/HJ7F-lBZC.png) Hàm thứ nhất ta thấy đoạn mã của chương trình kết hợp với bảng Sbox của thuật toán mã hóa AES. Ta có thể kết luận hàm này dùng thuật toán AES để mã hóa, giải mã. Nếu như vậy, hàm cũng sẽ yêu cầu KEY và IV. ![image](https://hackmd.io/_uploads/r1bBflHZR.png) Ta sử dụng Key như hình trên nhưng không được kết quả gì. Khi tìm theo các lệnh gọi có tương tác đến biến này và đó là hàm `sub_140001210` `Hàm sub_140001210`, có tham số là base address của vùng nhớ được ghi. Tiếp tục dùng kĩ thuật API Hashing và ta tìm được API NtQueryInformationProcess. Tham số thứ ba của hàm là dwProcessDebugFlags, nó sẽ kiểm tra chương trình đang debug hay không. Có là 0, không là 1. Ta sẽ thay đổi biến này mặc định là 1. ![image](https://hackmd.io/_uploads/S1G291rbR.png) Nhìn qua thấy nó thực hiện tính toán rất nhiều. Nhưng ta không cần quan tâm thuật toán, ta chỉ cần biết khóa của ta được ta khi chương trình không bị debug. `Key = mYq3s6v9y$B&E)H@c|w{` ![image](https://hackmd.io/_uploads/rk6CSxrZR.png) Dùng CyberChef và import tệp bị mã hóa kết hợp Key và IV ![image](https://hackmd.io/_uploads/SyrjPlrWC.png) Kết quả có được là một ảnh, mở ảnh đó lên và có kết quả. ![vessel_map](https://hackmd.io/_uploads/B1qm5mr-A.jpg) :::success ``` Flag: HTB{4l13n_5h3llc0d3_d3c1ph3ring_1s_fun} ``` ::: <div id="Spell Weaving Exam"></div> <h3>Challenge 4: Spell Weaving Exam</h3> Turn your spellbooks over now - the final exam has begun! Under the watchful eye of a strict adjuducator, you must answer each question perfectly <a href="https://drive.google.com/file/d/1iKRoNY_2rqSXgBCawgGTAp2Ds3Jb0KDH/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> Mở chương trình trong DIE. ![image](https://hackmd.io/_uploads/S1HPTLS-C.png) Mở chương trình trong IDA. Ta biết chương trình yêu cầu phải có một tham số. Đồng thời, tham số chỉ chứa các kí tự thường và dấu '-'. Nếu tồn tại chữ in hoa, số hoặc kí hiệu đặc biệt khác thì kết thúc. ![image](https://hackmd.io/_uploads/BJh7RUrZ0.png) Các hàm ta cần phân tích bao gồm: `main()` `task1_reference_gcd()` `task1_unittest_wrapper()` Trong đó, hàm `task1_reference_gcd()` là ngắn và dễ hiểu nhất. Hàm thực hiện tìm ước chung lớn nhất thông qua đệ quy. Lưu ý: các tham số được truyền vào hàm đều có kiểu dữ liệu uint_128 mà giả mã hiện tại là QWORD - 64 bit nên bị rối. Ta tạo một struct mới để cải thiện giả mã. :::info ```c struct Int128Bit { _QWORD low; _QWORD high; }; ``` ::: Ta cần lưu ý, các thao tác nhân chia trong ASM với RAX, nếu làm thanh ghi RAX không thể lưu trữ hết mà sẽ lưu trên RDX. ![image](https://hackmd.io/_uploads/HJz1rPrWC.png) Trong hàm `task1_unittest_wrapper()` , cách các biến thao tác với nhau khiến cho ta dự đoán việc cần sử dụng struct để khôi phục nội dung giả mã. ![image](https://hackmd.io/_uploads/BJvxFwrW0.png) Nó sẽ bao gồm 4 biến: 3 biến 128bit và 1 biến 32bit * value: Các giá trị dùng trong các phép toán thông thường được thực hiện. * cipher: Các giá trị dùng trong các phép toán phức tạp và không rõ ràng được thực hiện. * mod: Đầu vào cho các cuộc gọi hàm tính toán modulo. * mode: Cờ được sử dụng để chỉ định chế độ hoạt động của cấu trúc. :::info ```c struct REG { struct int128bit value; struct int128bit cipher; struct int128bit mod; int32_t mode; }; ``` ::: Kết quả giả mã sau khi sử dụng cấu trúc mới, tôi đã thay đổi tên thành REG2, REG3, REG3, ... để thuận lợi trong việc phân biệt sau này. ![image](https://hackmd.io/_uploads/HyjbhwS-A.png) Chương trình tạo các hành động thao tác các REG qua tham số truyền vào. Chương trình dùng một biến đếm để biết đã thực thi lệnh thứ bao nhiêu, cũng như đánh dấu biết lệnh phải nhảy đến. Thông qua switch case, ta hiểu các REG tương tác với nhau như sau: :::info ```java Các lệnh không có điều kiện: `-` => `REG4 = REG1` `q` => `REG3 = REG1` `v` => `REG1 = REG2` `w` => `REG1 = REG3` `x` => `REG2 = REG1` `y` => `REG2 = REG3` `z` => `REG3 = REG2` `r` => xóa cờ tiếp tục => kết thúc Các lệnh làm tăng biến đếm lệnh khi thỏa điều kiện: (&pc = programCounter + 1;) `p` : khi `REG4 != 0` `s` : khi `REG4 == 0` `t` : khi `REG4 < REG4.mod/2` `u` : khi `REG4 > REG4.mod/2` Các lệnh liên đánh dấu vị trí để nhảy đến: `m` => đánh dấu vị trí (mark = programCounter;) `n` => nhảy đến vị trí đánh dấu (pc = (mark - 1);) Các lệnh thuật toán phức tạp: `c` => `REG1 = (REG1 + REG2) % (REG2.mod)` `d` => `REG1 = ((REG1.mod - REG2) + REG1) % (REG2.mod) = (REG1 - REG2) % (REG2.mod)` ``` ::: Chương trình kiểm tra kết quả sau khi đưa đầu vào của thuật toán mã hóa tạo từ tham số của hàm main() với thuật toán tìm ước chung lớn nhất. Kết quả ước chung này sẽ được dùng để tạo ra flag. Chúng ta cần xây dựng thuật toán tìm ước chung lớn nhất mà không sử dụng đệ quy (vì thuật toán ta được cho không có khả năng ấy). Ta xây dựng đoạn mã như thuật toán Euclid. :::info ```python def GCD(a, b) while a != b: if a > b: a -= b else: b -= a return a ``` ::: Thuật toán ta xây dựng được mô tả như sau: :::info ```python f = a-b if f == 0: return a if f > 0: a = a - b if f < 0: b = b - a ``` ::: Hai số lúc đầu sẽ được lưu tại REG1, Reg2 và REG1.mod = REG2.mod = 0x4DD4C3C6D1B95795. Từ đây, ta xây dựng hàm tương tự như hàm Euclid. :::info ```python # f = a-b `q` => c = a `d` => a = (a - b) % 0x4DD4C3C6D1B95795 `-` => f = a 'w' => a = c # if f == 0: return a `p` => if f != 0: `r` => return (a) # if f < 0: a = a - b `u` => if f > 0 `d` a = (a - b) % 0x4DD4C3C6D1B95795 # if f > 0: b = b - a `t` if f < 0 `q` c = a `t` => if f < 0 `v` a = b `t` => if f < 0 `y` b = c `t` => if f < 0 `d` a = (a - b) % 0x4DD4C3C6D1B95795 `n` loop ``` ::: Vậy chuỗi ta cần nhập là `qd-wprudtqtvtytdn` . Đây chỉ là một trong các chuỗi thỏa điều kiện, bạn có thể thay đổi nó. Kết quả ta thu được. ![image](https://hackmd.io/_uploads/HkeFEFrZR.png) :::success ``` Flag: HTB{w3LL_d0NE_3X4m_p4sS3d!!} ``` ::: <div id="Convoluted Boot"></div> <h3>Challenge 5: Convoluted Boot</h3> You've arrived on the planet Drion-1, where the high galactic court is based. You've come to spread the word about the dangers of Draeger, and gather support, but thousands upon thousands of other lifeforms are also here to argue, squabble and dispute, speaking a thousand different languages. Can you make yourself heard above the babble? <a href="https://drive.google.com/file/d/1IcPj2Rsc3s3T35I1vFDV7rl-8k-T4WRU/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3> <div id="Freaky Forum Interception"></div> <h3>Challenge 6: Freaky Forum Interception</h3> Intelligence indicates that the ancient data storage device you've obtained contains schematics for a never-before-seen weapon. But there's a problem - it's locked, and strange symbiotic lifeforms on its surface are constantly removing parts and reinserting them elsewhere. Can you get a clear picture of what's going on? <a href="https://drive.google.com/file/d/1741QU7BNtZxucMZqb_jd4X3Wbj49CaY-/view?usp=sharing">Download Challenge Here</a> <h3>Solution</h3>