# ImagePrc - Run executable ![image](https://hackmd.io/_uploads/BJAWVox9C.png) - How program checks our input (`WndClass.lpfnWndProc = check_img`) ![image](https://hackmd.io/_uploads/S138Vslc0.png) - Let's dump desired input to a file ![image](https://hackmd.io/_uploads/rkApVoe5A.png) - Print dumped data to output file ![image](https://hackmd.io/_uploads/B12bUil5C.png) - Minimize text size until we get something interesting ![image](https://hackmd.io/_uploads/SJ9lUix90.png) - Flag: `GOT` # Position - ReadMe.txt ![image](https://hackmd.io/_uploads/ryM8W6ecR.png) - Run executable ![image](https://hackmd.io/_uploads/ryqqb6g5A.png) - As instructed in the text file, we need to determine how the PE file matches the input name and serial number. - Since a 'Wrong' text pops up, I can search for it in IDA. ![image](https://hackmd.io/_uploads/S1qcGpl90.png) - check `display` function (from DATA XREF) ![image](https://hackmd.io/_uploads/S19Rzpg9R.png) - `check_function` ![image](https://hackmd.io/_uploads/SJozm6x9R.png) ![image](https://hackmd.io/_uploads/HkJNXpg5R.png) ![image](https://hackmd.io/_uploads/r1ySmag9C.png) ![image](https://hackmd.io/_uploads/rJlUXTgcA.png) - The algorithm is obvious (`itow_s` will transfer an integer to a string). Let's bruteforce each character and rebuild this algorithm to find the name that matches the given serial number. ```python import string alphabet = string.ascii_lowercase for x in alphabet: v6 = ord(x) v40 = (v6 & 1) + 5 v48 = ((v6 & 0x10) != 0) + 5 v42 = ((v6 & 2) != 0) + 5 v44 = ((v6 & 4) != 0) + 5 v46 = ((v6 & 8) != 0) + 5 for y in alphabet: v7 = ord(y) v32 = (v7 & 1) + 1 v38 = ((v7 & 0x10) != 0) + 1 v34 = ((v7 & 2) != 0) + 1 v8 = ((v7 & 4) != 0) + 1 v36 = ((v7 & 8) != 0) + 1 if (v40 + v8 == 7 and v46 + v36 == 6 and v42 + v38 == 8 and v44 + v32 == 7 and v48 + v34 == 6): for z in alphabet: v19 = ord(z) v41 = (v19 & 1) + 5 v49 = ((v19 & 0x10) != 0) + 5 v43 = ((v19 & 2) != 0) + 5 v45 = ((v19 & 4) != 0) + 5 v47 = ((v19 & 8) != 0) + 5 v20 = ord('p') v33 = (v20 & 1) + 1 v39 = ((v20 & 0x10) != 0) + 1 v35 = ((v20 & 2) != 0) + 1 v21 = ((v20 & 4) != 0) + 1 v37 = ((v20 & 8) != 0) + 1 if (v41 + v21 == 7 and v47 + v37 == 7 and v43 + v39 == 7 and v45 + v33 == 7 and v49 + v35 == 6): print(x + y + z + "p") ``` - output: ```bash bump cqmp ftmp gpmp ``` - I choose `bump` as my answer. ![image](https://hackmd.io/_uploads/SkAQ46lqA.png) - Flag: `bump` # Ransomware - Check file `run.exe` with `PEiD`, we can see that `UPX1` appeared in the section. Therefore, I use `upx -d` to unpack it ![image](https://hackmd.io/_uploads/rJI76o-90.png) - Now we can load the file into IDA and analyze it. Because there are many useless instructions obfuscating the decompiler, I'll patch the program to jump over them. (`.text:004135E9 jmp loc_44A771`) ![image](https://hackmd.io/_uploads/Byfd_3bqC.png) - After that, we can see the decompiled code. ![image](https://hackmd.io/_uploads/SkYcOhb9A.png) ![image](https://hackmd.io/_uploads/H1aj_nWqA.png) - `sub_401000` is also a trash function, we can skip them. The encryption is simple, just xoring original `file` with the input key. So we can look for the `NULL` region in some other `PE` file and compare with current `file`. Then we could find the key that encrypted the `file`. ![image](https://hackmd.io/_uploads/H1n8RhZqA.png) ![image](https://hackmd.io/_uploads/SkrB0hbq0.png) - The key is `[0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C, 0x8C]`. Now, we can decrypt the `file`. ```python key = [0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C, 0x8C] with open("file", "rb") as f: byte_arr = f.read() new_byte_arr = [] with open("origin_file", "wb") as g: for i in range(len(byte_arr)): g.write((byte_arr[i] ^ key[i % len(key)]).to_bytes()) f.close() g.close() ``` - Check `origin_file` again with hexEdit. ![image](https://hackmd.io/_uploads/HJyX-6bqR.png) - It looks correct. However, `PEiD` detect an `UPX` section again so we have to unpack it. ![image](https://hackmd.io/_uploads/By93WTW90.png) - Load into IDA and we get the key. ![image](https://hackmd.io/_uploads/ByVaMTb5A.png) - Flag: `Colle System` # CSHOP - Load the given file to `PEiD` ![image](https://hackmd.io/_uploads/r1gmYT-9R.png) - Hmm, `Basic .NET`, let's load it to `dnSpy` ![image](https://hackmd.io/_uploads/HJm8FpWqC.png) ![image](https://hackmd.io/_uploads/HJvPY6ZcC.png) - Check the `tabIndex` for each label and put the `Text` in `Click` function in that order, I get `P4W6RP6SES`. I guess that was the flag and it's true. - Flag: `P4W6RP6SES` # Direct3D FPS - Run the given game: ![image](https://hackmd.io/_uploads/BkadsXEjR.png) - It's lagging because it has only 8 FPS (limited?). Let's decompile with `IDA`. Searching for string (`shift+F12`), I found `"Game Clear"` and located the `win` function from `DATA XREF` ![image](https://hackmd.io/_uploads/Hy1XhmVjA.png) - If we win, there would be a message poped up with `Game Clear`. However, it is encrypted currently. ![image](https://hackmd.io/_uploads/S1CdnXNsC.png) - Analyze `decrypt` function from `DATA XREF` ![image](https://hackmd.io/_uploads/HJ0s374jC.png) - Set a breakpoint in this function, press `F9` to run the program and shoot, the game will be paused and we could be able to get in this function. Then, use `python` plugin to get byte in memory. ![image](https://hackmd.io/_uploads/S1OVTXEsR.png) - It seems that the message will be decrypted by xoring with 0x0, 0x4, 0x8,0xc,...Let's retrieve the final message. ![image](https://hackmd.io/_uploads/rkzcTmEiA.png) - Flag: `Thr3EDPr0m` - P/S: [idapython plugin](https://github.com/idapython/src) # CSHARP - Another `Basic .NET`'s detected from `PEiD` (we can guess from challenge's name, btw) ![image](https://hackmd.io/_uploads/S1gYE-BNo0.png) - Load it to `dnSpy (32bit)` and we can see the `check` function. ![image](https://hackmd.io/_uploads/Hk_2-HEoC.png) - Hmm, the `array` has changed after `method.Invoke`. Let's set a breakpoint and step into (`F11`) it when debugging. After a while, an interesting function appeared which located in `Dynamic Assembly` section. ![image](https://hackmd.io/_uploads/S1DHzSVsR.png) ![image](https://hackmd.io/_uploads/HJ1qGr4jC.png) - Reverse it and I get ![image](https://hackmd.io/_uploads/H1pafHNsA.png) - It looks like `base64`. Use `Cyberchef` to decode it ![image](https://hackmd.io/_uploads/SJmEmrEo0.png) - Flag: `dYnaaMic` # AutoHotkey1 - Kiểm tra bằng DIE: ![image](https://hackmd.io/_uploads/HypFJXDcyl.png) - Unpack file bằng [UPX unpacker](https://upx.github.io/): ![image](https://hackmd.io/_uploads/Byl4ymv5yl.png) - Tuy nhiên, khi chạy file ta nhận được một thông báo là `EXE is corrupted`. Kiểm tra trong IDA thì có một đoạn check như sau: ![image](https://hackmd.io/_uploads/BkT_eQv9ye.png) - Đoạn check này có vẻ liên quan đến mã CRC32 của file ban đầu, bên dưới hàm cũng có một đoạn trông khá giống decode data -> Ta sẽ sử dụng file được unpack để phân tích tĩnh (static) trong IDA còn unpack bằng tay sử dụng x64dbg. Đặt các breakpoint: ![image](https://hackmd.io/_uploads/S1f2bmPqJx.png) - Sử dụng địa chỉ hàm trong IDA để đặt breakpoint vào hàm kiểm tra trong x64dbg, chạy đến gần cuối hàm, ta thấy đoạn key được hiển thị (có vẻ là `DecryptKey`) `220226394582d7117410e3c021748c2a` - `isolated` ![image](https://hackmd.io/_uploads/rkQWGXwc1x.png) - Chính là đoạn này trong IDA: ![image](https://hackmd.io/_uploads/SkkVfQw5kx.png) - Tiếp tục debug trong hàm `sub_4481E0` siêu dài và sau địa chỉ `00448422`, ta thấy một xâu rất giống key còn lại hiện ra: `if (pwd== \"54593f6b9413fc4ff2b4dec2da337806\"){{` ![image](https://hackmd.io/_uploads/H1P8E7D9yl.png) - Nhập key này vào chương trình và ta nhận được thông báo khác thay vì tự tắt: ![image](https://hackmd.io/_uploads/B10oVmDq1l.png) `54593f6b9413fc4ff2b4dec2da337806` - `pawn` - Flag: `isolated pawn` # X64 Lotto - Ta cần nhập đúng 6 số giống với các số random bởi hàm rand() để chương trình in ra flag -> điều đó gần như là không thể vì seed lấy theo thời gian thực: ![image](https://hackmd.io/_uploads/B1VtFOdckg.png) - Vì vậy ta chỉ cần Set IP qua đoạn check này và để chương trình in ra flag một cách tự nhiên là được (do không có tham số nào liên quan đến quá trình giải mã flag): ![image](https://hackmd.io/_uploads/H1-y9ud9kl.png) ![image](https://hackmd.io/_uploads/SkfVYuO9yx.png) - Flag: `from_GHL2_-_!` # HateIntel - Hàm main bắt ta nhập 1 `input` sau đó đưa `input` qua hàm mã hoá rồi so sánh với `data`: ![image](https://hackmd.io/_uploads/Hy8E3h_9kg.png) - Hàm mã hoá `encrypt`, mã hoá từng ký tự của `input`, thực hiện gọi hàm `encryptChar` 4 lần với từng ký tự: ![image](https://hackmd.io/_uploads/ryLu32_cJl.png) - Hàm `encryptChar` thực hiện mã hoá ký tự bằng cách sử dụng phép `ROR 1`, xoay trái 1 bit: ![image](https://hackmd.io/_uploads/H10Za2O5ke.png) - Từ data ta có thể xây dựng lại key cần nhập bằng cách xoay phải 1 bit 4 lần: ![image](https://hackmd.io/_uploads/r1VQX6Oqke.png) ``` def rotate_right(byte, times=1): for _ in range(times): byte = ((byte >> 1) | ((byte & 1) << 7)) & 0xFF return byte data = [ 0x44, 0xF6, 0xF5, 0x57, 0xF5, 0xC6, 0x96, 0xB6, 0x56, 0xF5, 0x14, 0x25, 0xD4, 0xF5, 0x96, 0xE6, 0x37, 0x47, 0x27, 0x57, 0x36, 0x47, 0x96, 0x03, 0xE6, 0xF3, 0xA3, 0x92 ] rotated_data = [rotate_right(byte, 4) for byte in data] print("".join(chr(c) for c in rotated_data)) ``` - Flag: `Do_u_like_ARM_instructi0n?:)` # Multiplicative - Chương trình đơn giản chỉ cần nhập vào một số để thoả mãn phương trình tuy nhiên làm khó chúng ta bằng cách dùng tràn số: ![image](https://hackmd.io/_uploads/Skv3doYcJe.png) - Để không phải xử lí tràn số, ta có thể dùng python để xử lý số lớn. Ta sẽ tìm một `x` thoả mãn (-1536092243306511225 + x * 2^64) chia hết cho 26729 ![image](https://hackmd.io/_uploads/SkT-sjYcye.png) - Biến cần tìm (unsigned): ![image](https://hackmd.io/_uploads/S1-7siF5kg.png) - Chuyển về signed: ![image](https://hackmd.io/_uploads/SkPEsoYcye.png) - Chạy chương trình: ![image](https://hackmd.io/_uploads/BkuLosYqye.png) - Flag: `-8978084842198767761` # PEPassword - File được pack bằng `PE Password(0.2)` ![image](https://hackmd.io/_uploads/rkQW4aKckl.png) - Đưa vào trong IDA, ta chỉ thấy vài hàm từ section `SMT__SMF`: ![image](https://hackmd.io/_uploads/By78V6F5kg.png) - Vì ít hàm nên ta có thể đặt breakpoint vào tất cả các hàm và thực hiện debug, sau đó đổi tên hàm để dễ đoán thuật toán được sử dụng: ![image](https://hackmd.io/_uploads/HJARVaFqyl.png) - Dựa vào tên hàm vào debug động có thể tìm được cách chương trình kiểm tra input. Chương trình sẽ nhận input mỗi khi ta nhận thêm một kí tự mới rồi đưa vào hàm `checksum_calc` với `result` ban đầu là số lượng kí tự đầu vào, sau dó sẽ thay đổi result theo `từng ký tự`: ![image](https://hackmd.io/_uploads/H1ZcVzc5Je.png) - Sau khi tính toán xong, kết quả sẽ được so sánh với `0xE98F842A` và nếu khớp chương trình sẽ gọi đến một đoạn rất lạ (khả năng cao là gọi đến messageBox("Congrat") :Đ): ![image](https://hackmd.io/_uploads/BJk8Bz95kg.png) - Do không biết độ dài yêu cầu của password cũng như không thể dịch ngược lại được (khó), nên ta sẽ đi bruteforce password trước (nếu password dưới 6 ký tự thì có thể vét cạn được): ```c++ #define int unsigned int string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; int ror(int x, int k) { return ((x >> k) | (x << (32 - k))) & 0xFFFFFFFF; } void calc(int pos, int len, string cur) { if (pos == len) { int result = len; for (int i = 0; i < len; ++ i) { int c = cur[i]; result ^= (c << 8); short v2 = 0; do { result ^= (v2 & 0xff); result += 0x434F4445; result = ror(result, result & 0xff); result ^= 0x55AA5A5A; -- v2; } while (v2); } { int c = 0; result ^= (c << 8); short v2 = 0; do { result ^= (v2 & 0xff); result += 0x434F4445; result = ror(result, result & 0xff); result ^= 0x55AA5A5A; -- v2; } while (v2); } // cout << cur << " : " << result << "\n"; if (result == 3918496810) { cout << "Password is: " << cur << "\n"; exit(0); } return; } for (auto c : alphabet) { string tmp = cur + c; calc(pos + 1, len, tmp); } } void solve(int Test) { for (int len = 1; len <= 10; ++ len) { calc(0, len, ""); } } ``` ![image](https://hackmd.io/_uploads/SypI3yu3Jl.png)