# WRITE-UP FOR PICOCTF 2025 ## I. BINARY EXPLOITATION ### 1. hash-only-1: > Here is a binary that has enough privilege to read the content of the flag file but will only let you know its hash. If only it could just give you the actual content! > Additional details will be available after launching your challenge instance. When we start the file flasgasher, it appearance the information: ``` ctf-player@pico-chall$ ./flaghasher Computing the MD5 hash of /root/flag.txt.... 3daf8ce91eaaba82780562d65223e131 /root/flag.txt ``` ``` flaghasher: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c4fbd07a602b4570abdcfe273078247bdc96b5b2, for GNU/Linux 3.2.0, not stripped ``` ```ubuntu ctf-player@pico-chall$ ls -l total 20 -rwsr-xr-x 1 root root 18312 Mar 6 03:45 flaghasher ``` We make the directory name bin and fake a command that reads the flag in the md5sum output ``` ubuntu ctf-player@pico-chall$ mkdir ~/bin ctf-player@pico-chall$ echo '#!/bin/bash' > ~/bin/md5sum ctf-player@pico-chall$ echo 'cat /root/flag.txt' >> ~/bin/md5sum ``` Now we will grant execution permissions and run the `flaghasher` file again. ``` ctf-player@pico-chall$ chmod +x ~/bin/md5sum ctf-player@pico-chall$ export PATH=~/bin:$PATH ctf-player@pico-chall$ ./flaghasher ``` Flag: ## II. FORENSICS ### 1. Ph4nt0m 1ntrud3r: > A digital ghost has breached my defenses, and my sensitive data has been stolen! 😱💻 Your mission is to uncover how this phantom intruder infiltrated my system and retrieve the hidden flag. > To solve this challenge, you'll need to analyze the provided PCAP file and track down the attack method. The attacker has cleverly concealed his moves in well timely manner. Dive into the network traffic, apply the right filters and show off your forensic prowess and unmask the digital intruder! > Find the PCAP file here Network Traffic PCAP file and try to get the flag. We have three hints here: Hint 1: Filter your packets to narrow down your search. Hint 2: Attacks were done in timely manner. Hint 3: Time is essential When analyzing a PCAP file using Wireshark, in the packet information section, we see an encoded base x86 string at the end. We receive the following strings filtered by packet timestamp order (according to hint 3): > RMq+wTM= > 9DpIbkA= > Tclg/3s= > QKzFX+c= > OwFeP0M= > 7uDCclg= > 4pcYwTg= > 2d71KZI= > 6w46Q70= > RHxhtS4= > Z1Gdyjk= > qo9qpiY= > JbG2Q7w= > oFpZPG8= > hKvZKGA= > cGljb0NURg== > ezF0X3c0cw== > bnRfdGg0dA== > XzM0c3lfdA== > YmhfNHJfOQ== > NjZkMGJmYg== > fQ== Looking at the list of Base64-encoded strings, some of them appear to be parts of a flag. The notable strings are: > cGljb0NURg== > ezF0X3c0cw== > bnRfdGg0dA== > XzM0c3lfdA== > YmhfNHJfOQ== > NjZkMGJmYg== > fQ== Continuing to decode the remaining Base64 strings, we get the flag: ``` ubuntu cat <<EOF | base64 -d cGljb0NURg== ezF0X3c0cw== bnRfdGg0dA== XzM0c3lfdA== YmhfNHJfOQ== NjZkMGJmYg== fQ== EOF ``` ### 2. RED: > RED, RED, RED, RED > Download the image: ![red](https://hackmd.io/_uploads/ByI3deY2ye.png) The goal is likely to uncover a hidden message or flag within the image, possibly using steganography or metadata analysis. If there is hidden data in the color bits, zsteg may be able to find it. Run: zsteg red.png ``` meta Poem .. text: "Crimson heart, vibrant and bold,\nHearts flutter at your sight.\nEvenings glow softly red,\nCherries burst with sweet life.\nKisses linger with your warmth.\nLove deep as merlot.\nScarlet leaves falling softly,\nBold in every stroke." b1,rgba,lsb,xy .. text: "cGljb0NURntyM2RfMXNfdGgzX3VsdDFtNHQzX2N1cjNfZjByXzU0ZG4zNTVffQ==cGljb0NURntyM2RfMXNfdGgzX3VsdDFtNHQzX2N1cjNfZjByXzU0ZG4zNTVffQ==cGljb0NURntyM2RfMXNfdGgzX3VsdDFtNHQzX2N1cjNfZjByXzU0ZG4zNTVffQ==cGljb0NURntyM2RfMXNfdGgzX3VsdDFtNHQzX2N1cjNfZjByXzU0ZG4zNTVffQ==" b1,rgba,msb,xy .. file: OpenPGP Public Key b2,g,lsb,xy .. text: "ET@UETPETUUT@TUUTD@PDUDDDPE" b2,rgb,lsb,xy .. file: OpenPGP Secret Key b2,bgr,msb,xy .. file: OpenPGP Public Key b2,rgba,lsb,xy .. file: OpenPGP Secret Key b2,rgba,msb,xy .. text: "CIkiiiII" b2,abgr,lsb,xy .. file: OpenPGP Secret Key b2,abgr,msb,xy .. text: "iiiaakikk" b3,rgba,msb,xy .. text: "#wb#wp#7p" b3,abgr,msb,xy .. text: "7r'wb#7p" b4,b,lsb,xy .. file: 0421 Alliant compact executable not stripped ``` zsteg has found a hidden Base64 string in the image, decode it using the command. ``` echo "cGljb0NURntyM2RfMXNfdGgzX3VsdDFtNHQzX2N1cjNfZjByXzU0ZG4zNTVffQ==" | base64 -d ``` ### 3. Event-Viewing: > One of the employees at your company has their computer infected by malware! Turns out every time they try to switch on the computer, it shuts down right after they log in. The story given by the employee is as follows: > They installed software using an installer they downloaded online > They ran the installed software but it seemed to do nothing > Now every time they bootup and login to their computer, a black command prompt screen quickly opens and closes and their computer shuts down instantly. > See if you can find evidence for the each of these events and retrieve the flag (split into 3 pieces) from the correct logs! > Download the Windows Log file here We have 2 hints: Hint 1: Try to filter the logs with the right event ID Hint 2: What could the software have done when it was ran that causes the shutdowns every time the system starts up? We run file in Event Viewer. Use Filter Current Log and filter with ID for each event. In the description and hint 2 decide that when they bootup and login to their computer, a black command prompt screen quickly opens and closes and their computer shuts down instantly. We try to filter with three types IDsrelated to the shutdowns instably: 1074, 1033, 4657 We find some encoded base x86 strings in General field: ``` cGljb0NURntFdjNudF92aTN3djNyXw== MXNfYV9wcjN0dHlfdXMzZnVsXw== dDAwbF84MWJhM2ZlOX0= ``` ### 4. flag and stepic: > A group of underground hackers might be using this legit site to communicate. Use your forensic techniques to uncover their message > Additional details will be available after launching your challenge instance. Hint: In the country that doesn't exist, the flag persists. We can find the flag of Upanzi, Republic The which is not a country. We start to analyze the png file: ``` stepic --decode --image-in=upz.png --out=output.txt cat output.txt ``` We finally find the flag ## III. GENERAL SKILLS ## 1. Rust fixme 1: Cargo is Rust's package manager and will make your life easier. See the getting started page here Hint 1: println! Hint 2: Rust has some pretty great compiler error messages. Read them maybe? #### Dấu chấm phẩy thiếu ở dòng khai báo biến `key` ```rust let key = String::from("CSUCKS"); // Cần dấu chấm phẩy ở cuối câu lệnh ``` #### `ret;` không hợp lệ trong Rust Thay vì `ret;`, dùng `return;` hoặc `return Err(...);` nếu cần trả về lỗi. ```rust if res.is_err() { return; // Hoặc có thể xử lý lỗi phù hợp } ``` #### Lỗi cú pháp trong `println!` Lệnh `println!` cần một chuỗi định dạng hợp lệ `{}` để in biến: ```rust println!("{}", String::from_utf8_lossy(&decrypted_buffer)); ``` Sau khi sửa lỗi: ``` cargo run ``` Flag: Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s Running `target/debug/rust_proj` picoCTF{4r3_y0u_4_ru$t4c30n_n0w?} ## 2. Rust fixme 2: #### Thiếu dấu chấm phẩy Dòng này bị thiếu dấu `;` ở cuối: ```rust let key = String::from("CSUCKS"); ``` --- #### `ret;` không hợp lệ Trong Rust, không có từ khóa `ret`. Để dừng hàm khi gặp lỗi, ta dùng `return;`: ```rust if res.is_err() { return; } ``` #### `println!` sai cú pháp Trong Rust, để in một biến bằng `println!`, ta cần đặt `{}`: ```rust println!("{}", String::from_utf8_lossy(&decrypted_buffer)); ``` Sau khi sửa lỗi: ```sh cargo run ``` Flag: Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.29s Running `target/debug/rust_proj` Using memory unsafe languages is a: PARTY FOUL! Here is your flag: picoCTF{4r3_y0u_h4v1n5_fun_y31?} ## 3. Rust fixme 3: #### Phần unsafe bị comment lại (// unsafe {}) Rust không cho phép truy cập con trỏ thô (from_raw_parts) trong vùng an toàn. Không cần dùng con trỏ thô (from_raw_parts) decrypted_buffer đã là Vec<u8>, có thể dùng trực tiếp. Nên thay thế bằng cách dùng &decrypted_buffer thay vì con trỏ thô. #### Bỏ comment `unsafe` ```rust unsafe { let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer); // Tạo con trỏ và chiều dài let decrypted_ptr = decrypted_buffer.as_ptr(); let decrypted_len = decrypted_buffer.len(); // Truy cập con trỏ thô trong vùng unsafe let decrypted_slice = std::slice::from_raw_parts(decrypted_ptr, decrypted_len); borrowed_string.push_str(&String::from_utf8_lossy(decrypted_slice)); } ``` #### Dùng trực tiếp `decrypted_buffer` (Không cần `unsafe`) Thay vì dùng con trỏ thô, có thể viết đơn giản như sau: ```rust let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer); borrowed_string.push_str(&String::from_utf8_lossy(&decrypted_buffer)); ``` Sau khi sửa lỗi: ```sh cargo run ``` Flag: Compiling rayon-core v1.12.1 Compiling rayon v1.10.0 Compiling xor_cryptor v1.2.3 Compiling rust_proj v0.1.0 (/mnt/c/ALL WE NEED HERE/CTF/picoctf/pico2025/gen/ru3/fixme3) Finished `dev` profile [unoptimized + debuginfo] target(s) in 6.15s Running `target/debug/rust_proj` Using memory unsafe languages is a: PARTY FOUL! Here is your flag: picoCTF{n0w_y0uv3_f1x3d_1h3m_411} ## IV. REVERSE ENGINEEERING ### 1. Tap into Hash: > Can you make sense of this source code file and write a function that will decode the given encrypted file content? > Find the encrypted file here. It might be good to analyze source file to get the flag. > Hint 1: Do you know what blockchains are? If so, you know that hashing is used in blockchains. > Hint 2: Download the encrypted flag file and the source file and reverse engineer the source file. Đầu tiên, chúng ta cần tính giá trị key_hash từ Key được cung cấp ```python key = b'\x1d,\x18.\x8a\xe7vt>j\xfb)s\xc4W\xcdD\x83\xa7\xf0\xdfQS\xd7\xec5=zw\x8e(\xec' key_hash = hashlib.sha256(key).digest() print("Key Hash:", key_hash.hex()) ``` Ta được Key Hash: b9aff474083115232a8c10a4fc5617a33d00c5e8b943e52bf32e2780b76917bd Encrypted Blockchain được mã hóa bằng cách XOR từng khối 16 byte của plaintext với key_hash, ta có thể giải mã bằng cách XOR lại Encrypted Blockchain với key_hash. ```python! # Encrypted Blockchain encrypted = b'\xdf\x97\xc6\x10k\x00#BN\xbc%\x96\xc8b\'\xc0\x8b\xc9\x96Gk\x07w\x17\x1a\xbf%\xc1\xc92v\xc7\x8b\x97\x90B1\x06p@\x1e\xbcq\x97\xc9g \xc7\x8d\x9b\xc6F=Ww\x13L\xe9 \x97\xc8o/\xc6\x94\x9f\xc4A8R!\x11\x13\xbc!\xc1\xccot\x93\x81\xca\xc7\x17mS&AH\xee \x96\x99`r\x97\x89\x9b\xc2@8R#A\x1e\xe9 \x93\xc8`u\x93\x8c\xc9\x97G;\x08-\x1b\x1c\xb8$\x9d\x9f`t\x9a\x8e\x82\xc4D1R"\x15I\xee \xc7\x9d3%\xc2\x8e\x96\xc6EjRt\x14\x1f\xbf!\x97\xc5d\'\xc1\x8e\x9e\x84\x1dk^Vwl\xf7r\xc8\x935|\xfc\x8a\xfc\xa6\x1c^XGA~\xbda\xc7\xa4\tO\xf6\xd3\xe2\xc4\x06<\x08vku\xfdS\xde\x91\x1cM\xd9\xfb\xe4\xabLjS"AI\xbf(\xd9\xc9`"\x94\x8e\x96\x91CjT#GI\xbds\xc2\x9fe\'\x91\x8d\xcd\x95C9Pw\x17H\xbft\xc1\xd1f\'\x9b\xdd\x98\x90Dj\x02-\x1bK\xbfr\x90\x9e3s\x9b\x8e\x9c\x95\x17;\x08#\x16N\xba(\x90\xcd0u\x93\x8a\xca\xc2AkW-AH\xbc%\x95\xcbb"\x9b\x8a\x99\xcd\x11<\x05,GK\xba)\x90\x99{\'\x93\xda\x9c\x91EiPt\x14O\xbeu\x92\x993.\x9b\x89\xcd\xc1DmR%\x13\x1c\xbdr\x91\xcb`r\x96\x8c\xca\xc5\x17jRv@L\xb9 \xc7\xcd4.\x97\x80\x9d\x90\x17kR"\x15\x1e\xeeu\xc7\x9dd\x15\xa1' # Key_hash key_hash = bytes.fromhex('b9aff474083115232a8c10a4fc5617a33d00c5e8b943e52bf32e2780b76917bd') # Hàm XOR def xor_bytes(a, b): return bytes(x ^ y for x, y in zip(a, b)) # Giải mã block_size = 16 plaintext = b'' for i in range(0, len(encrypted), block_size): block = encrypted[i:i + block_size] plain_block = xor_bytes(block, key_hash[:16]) # Lấy 16 byte đầu của key_hash plaintext += plain_block # In kết quả plaintext print("Plaintext (bytes):", plaintext) ``` Sau khi chạy ta được kết quả: Plaintext (bytes): b'f82dc16ad052440c2fb3c6b4035e5dad28d697ec40a3517d44225fb0fe03498e-0050c42901e09c08e3ceb3bbb02e6e404640c6b4e0746b05fc339886449c6c97-009c76cb0cae2a7921bca75313920b71picoCTF{block_3SRhViRbT1qcX_XUjM0r49cH_qCzmJZzBK_8bb7bc38}565779e7be6dc1cfc3024ba71ab4b3de-008d7d0b388a3b4bed873ac3965d6841fb03e65cf8bb0517458369e449da694e-00c3e1aaa7e2e6ee980b50ec0061b576e55e1cbcccf50c1b9492dccc764beca2\x02\x02' Flag: picoCTF{block_3SRhViRbT1qcX_XUjM0r49cH_qCzmJZzBK_8bb7bc38}