# Write Up 1337UP CTF 2024 ![image](https://hackmd.io/_uploads/B1SwtHjMyl.png) --- ## Warmup ### 1. Socials ![image](https://hackmd.io/_uploads/BJBRKBsfyg.png) Bài cho flag chia 3 phần ở 3 nền tảng: ![image](https://hackmd.io/_uploads/r1NdorsGyg.png) ![image](https://hackmd.io/_uploads/ryk9qrsGye.png) ![image](https://hackmd.io/_uploads/SkFgiSiMJe.png) Decode và mình có flag: > INTIGRITI{h0p3_y0u_3nj0y_d4_c7f} --- ### 2. In Plain Sight ![image](https://hackmd.io/_uploads/BJ8V3Biz1g.png) Bài stego cho ảnh: ![image](https://hackmd.io/_uploads/HJIF2Bszye.png) Binwalk với pass trên mình có ảnh `flag.png`, chỉnh 1 chút có flag: ![image](https://hackmd.io/_uploads/SJerpHoMkl.png) > INTIGRITI{w4rmup_fl46z} --- ### 3. Layers ![image](https://hackmd.io/_uploads/r1g96Bjf1e.png) Bài cho folder chưa các file thứ tự từ 0-55, lúc đầu mình lấy theo nội dung từ 0-55 nhưng decode không đem lại gì, sau mới phát hiện author không chia flag theo tên file mà theo thời gian tạo: ![image](https://hackmd.io/_uploads/ry3WABszke.png) ![image](https://hackmd.io/_uploads/B1lNRHsf1l.png) > INTIGRITI{7h3r35_l4y3r5_70_7h15_ch4ll3n63} --- ### 4. BabyFlow ![image](https://hackmd.io/_uploads/ByykyUjMyg.png) ![image](https://hackmd.io/_uploads/B1Y1JLsf1e.png) ![image](https://hackmd.io/_uploads/r1Afy8jGyg.png) > INTIGRITI{b4bypwn_9cdfb439c7876e703e307864c9167a15} --- ## Web ### 1. Pizza Paradise ![image](https://hackmd.io/_uploads/SJjokUjzJg.png) ![image](https://hackmd.io/_uploads/HJg1e8oGkl.png) > https://pizzaparadise.ctf.intigriti.io/robots.txt ![image](https://hackmd.io/_uploads/HJuGgUjfye.png) > https://pizzaparadise.ctf.intigriti.io/secret_172346606e1d24062e891d537e917a90.html ![image](https://hackmd.io/_uploads/Sk24e8iM1x.png) ```python! curl --path-as-is "https://pizzaparadise.ctf.intigriti.io/topsecret_a9aedc6c39f654e55275ad8e65e316b3.php?download=/assets/images/../../../../../../var/www/html/topsecret_a9aedc6c39f654e55275ad8e65e316b3.php" ``` ![image](https://hackmd.io/_uploads/S1-3xUsfye.png) >INTIGRITI{70p_53cr37_m15510n_c0mpl373} --- ## OSINT ### 1. Trackdown ![image](https://hackmd.io/_uploads/rytMbIjMkl.png) ![image](https://hackmd.io/_uploads/r15wWIofyg.png) > INTIGRITI{Si_Cuisine_&_Mixology} --- ### 2. Trackdown 2 ![image](https://hackmd.io/_uploads/HkwTbUiG1g.png) > INTIGRITI{Express_By_M_Village} --- ### 3. Bob L'éponge ![image](https://hackmd.io/_uploads/HkVueOofyx.png) Wu tham khảo: > https://ctftime.org/writeup/22610 ![image](https://hackmd.io/_uploads/HJUI-OsMJl.png) Tool: https://mattw.io/youtube-metadata/ ![image](https://hackmd.io/_uploads/HkphW_iM1e.png) > INTIGRITI{t4gs_4r3_m0stly_0bs0l3t3_zMlH7RH6psw} --- ### 4. No Comment ![image](https://hackmd.io/_uploads/ByUgz_jfJe.png) ![image](https://hackmd.io/_uploads/r1aUzuoz1x.png) ![image](https://hackmd.io/_uploads/By0yXOifJe.png) Ta có `/a/pq6TgwS`, khả năng là đường dẫn của 1 link trang nào đó, sau 1 hồi thử thì mình phát hiện: `https://imgur.com/a/pq6TgwS` ![image](https://hackmd.io/_uploads/SyCD7Oizkg.png) ![image](https://hackmd.io/_uploads/ryRK7uozyg.png) Được 1 link pastebin kèm pass để mở: ![image](https://hackmd.io/_uploads/Bk6pQuifyg.png) Có được: >25213a2e18213d2628150e0b2c00130e020d024004301e5b00040b0b4a1c430a302304052304094309 Mình thử giải mã bình thường nhưng không được, quay lại profile thì phát hiện author có để xor + pass: ```py! # Given hexadecimal ciphertext hex_ciphertext = "25213a2e18213d2628150e0b2c00130e020d024004301e5b00040b0b4a1c430a302304052304094309" # Convert the hex string to bytes ciphertext_bytes = bytes.fromhex(hex_ciphertext) # Known flag format to use as a crib for XORing crib =b"long_strange_trip" # XOR function to apply crib-dragging def xor_bytes(data, key): return bytes([data[i] ^ key[i % len(key)] for i in range(len(data))]) # Apply XOR with the crib to see if any patterns emerge resulting_plaintext = xor_bytes(ciphertext_bytes, crib) print(resulting_plaintext) ``` > INTIGRITI{instagram.com/reel/C7xYShjMcV0} --- ### 5. Private Github Repository ![image](https://hackmd.io/_uploads/HJpHEuifJl.png) ![image](https://hackmd.io/_uploads/H1PJL_ifye.png) ![image](https://hackmd.io/_uploads/SyN-IujG1e.png) ![image](https://hackmd.io/_uploads/SJ0G8_ifyl.png) Có thể thấy được dấu hiệu là file zip: Mở ra chứa file: ![image](https://hackmd.io/_uploads/H1ZO8usMyg.png) ```bash! ┌──(kali㉿kali)-[~/Desktop] └─$ chmod 600 id_rsa ┌──(kali㉿kali)-[~/Desktop] └─$ ssh-add id_rsa Identity added: id_rsa (1337up) ┌──(kali㉿kali)-[~/Desktop] └─$ ssh -T git@github.com Hi nitrofany! You've successfully authenticated, but GitHub does not provide shell access. ``` ![image](https://hackmd.io/_uploads/SkUmvdjfJx.png) ![image](https://hackmd.io/_uploads/rJK7w_oGye.png) ```bash! ┌──(kali㉿kali)-[~] └─$ git clone git@github.com:nitrofany/1337up.git Cloning into '1337up'... remote: Enumerating objects: 13, done. remote: Counting objects: 100% (13/13), done. remote: Compressing objects: 100% (9/9), done. Receiving objects: 100% (13/13), done. remote: Total 13 (delta 0), reused 10 (delta 0), pack-reused 0 (from 0) ┌──(kali㉿kali)-[~] └─$ cd 1337up ls -la total 20 drwxrwxr-x 4 kali kali 4096 Nov 15 22:18 . drwx------ 29 kali kali 4096 Nov 15 22:18 .. drwxrwxr-x 2 kali kali 4096 Nov 15 22:18 config drwxrwxr-x 8 kali kali 4096 Nov 15 22:18 .git -rw-rw-r-- 1 kali kali 106 Nov 15 22:18 readme.md ┌──(kali㉿kali)-[~/1337up] └─$ cat readme.md Hey, Tiffany! You will need to save this repo in your user space and implement changes we agreed earlier. ┌──(kali㉿kali)-[~/1337up] └─$ ls -la config total 12 drwxrwxr-x 2 kali kali 4096 Nov 15 22:18 . drwxrwxr-x 4 kali kali 4096 Nov 15 22:18 .. -rw-rw-r-- 1 kali kali 44 Nov 15 22:18 .env ┌──(kali㉿kali)-[~/1337up] └─$ cat config/.env flag=replace with production INTIGRITI{...} ``` ```py= ┌──(kali㉿kali)-[~/1337up] └─$ git clone git@github.com:nitrofany/01189998819991197253.git Cloning into '01189998819991197253'... remote: Enumerating objects: 3, done. remote: Counting objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) Receiving objects: 100% (3/3), done. ┌──(kali㉿kali)-[~/1337up] └─$ ls 01189998819991197253 config readme.md ┌──(kali㉿kali)-[~/1337up] └─$ cd 01189998819991197253 ┌──(kali㉿kali)-[~/1337up/01189998819991197253] └─$ ls flag.md ┌──(kali㉿kali)-[~/1337up/01189998819991197253] └─$ cat flag.md # INTIGRITI{9e0121bb8bce15ead3d7f529a81b77b4} ``` ![image](https://hackmd.io/_uploads/SJalOOoGke.png) > INTIGRITI{9e0121bb8bce15ead3d7f529a81b77b4} --- ## Misc ### 1. Triage Bot v2 ![image](https://hackmd.io/_uploads/HkSEdujGJe.png) ![image](https://hackmd.io/_uploads/rJkD_dsMkg.png) Lấy ID bot, đưa về server riêng mình: > https://discord.com/oauth2/authorize?client_id=1301271615426007175&permissions=0&scope=botapplications.commands ![image](https://hackmd.io/_uploads/r1l3duif1g.png) ![image](https://hackmd.io/_uploads/rJ9eK_iMJx.png) Bot được update tính năng mới là `!read_report`, nhưng khi mình chọn, nó trả lời: > You don't have permissions to run this command! If you are a triager, please contact IT to be assigned the triage role. Điều đó có nghĩa là chỉ khi là `triage`, mình mới có thể đọc được report, vì đã cho bot vào server của riêng mình nên mình có thể tự set role luôn: ![image](https://hackmd.io/_uploads/SJQcYujMJg.png) ![image](https://hackmd.io/_uploads/BJj2F_oGyg.png) Vì nó random nên có thể thử từng số report, mình thử 0 thì có được flag luôn: > INTIGRITI{4n07h3r_y34r_4n07h3r_7r1463_b07} --- ### 2. Quick Recovery ![image](https://hackmd.io/_uploads/H1Krz9izkg.png) Bài cho ảnh và file python: ![image](https://hackmd.io/_uploads/SJC8z5iGJx.png) ```python= from PIL import Image, ImageDraw from itertools import permutations import subprocess qr_code_image = Image.open("qr_code.png") width, height = qr_code_image.size half_width, half_height = width // 2, height // 2 squares = { "1": (0, 0, half_width, half_height), "2": (half_width, 0, width, half_height), "3": (0, half_height, half_width, height), "4": (half_width, half_height, width, height) } def split_square_into_triangles(img, box): x0, y0, x1, y1 = box a_triangle_points = [(x0, y0), (x1, y0), (x0, y1)] b_triangle_points = [(x1, y1), (x1, y0), (x0, y1)] def crop_triangle(points): mask = Image.new("L", img.size, 0) draw = ImageDraw.Draw(mask) draw.polygon(points, fill=255) triangle_img = Image.new("RGBA", img.size) triangle_img.paste(img, (0, 0), mask) return triangle_img.crop((x0, y0, x1, y1)) return crop_triangle(a_triangle_points), crop_triangle(b_triangle_points) triangle_images = {} for key, box in squares.items(): triangle_images[f"{key}a"], triangle_images[f"{key}b"] = split_square_into_triangles( qr_code_image, box) a_order = ["1", "2", "3", "4"] # UPDATE ME b_order = ["1", "2", "3", "4"] # UPDATE ME final_positions = [ (0, 0), (half_width, 0), (0, half_height), (half_width, half_height) ] reconstructed_image = Image.new("RGBA", qr_code_image.size) for i in range(4): a_triangle = triangle_images[f"{a_order[i]}a"] b_triangle = triangle_images[f"{b_order[i]}b"] combined_square = Image.new("RGBA", (half_width, half_height)) combined_square.paste(a_triangle, (0, 0)) combined_square.paste(b_triangle, (0, 0), b_triangle) reconstructed_image.paste(combined_square, final_positions[i]) reconstructed_image.save("obscured.png") print("Reconstructed QR code saved as 'obscured.png'") ``` Script fix: ```python= from PIL import Image, ImageDraw # Load the uploaded QR code image uploaded_qr_path = "/mnt/data/obscured.png" qr_code_image = Image.open(uploaded_qr_path) # Image dimensions and partition points width, height = qr_code_image.size half_width, half_height = width // 2, height // 2 # Define quadrants for splitting the image squares = { "1": (0, 0, half_width, half_height), "2": (half_width, 0, width, half_height), "3": (0, half_height, half_width, height), "4": (half_width, half_height, width, height) } # Function to split a square into two triangles def split_square_into_triangles(img, box): x0, y0, x1, y1 = box a_triangle_points = [(x0, y0), (x1, y0), (x0, y1)] b_triangle_points = [(x1, y1), (x1, y0), (x0, y1)] def crop_triangle(points): mask = Image.new("L", img.size, 0) draw = ImageDraw.Draw(mask) draw.polygon(points, fill=255) triangle_img = Image.new("RGBA", img.size) triangle_img.paste(img, (0, 0), mask) return triangle_img.crop((x0, y0, x1, y1)) return crop_triangle(a_triangle_points), crop_triangle(b_triangle_points) # Split all quadrants into triangles triangle_images = {} for key, box in squares.items(): triangle_images[f"{key}a"], triangle_images[f"{key}b"] = split_square_into_triangles( qr_code_image, box) # Define order (assuming a PIN of 1234 for testing) a_order = ["1", "2", "3", "4"] # Example PIN order b_order = ["4", "3", "2", "1"] # Reverse of the above # Positions for pasting the reconstructed squares final_positions = [ (0, 0), (half_width, 0), (0, half_height), (half_width, half_height) ] # Reconstruct the QR code reconstructed_image = Image.new("RGBA", qr_code_image.size) for i in range(4): a_triangle = triangle_images[f"{a_order[i]}a"] b_triangle = triangle_images[f"{b_order[i]}b"] combined_square = Image.new("RGBA", (half_width, half_height)) combined_square.paste(a_triangle, (0, 0)) combined_square.paste(b_triangle, (0, 0), b_triangle) reconstructed_image.paste(combined_square, final_positions[i]) # Save the reconstructed QR code reconstructed_path = "/mnt/data/reconstructed_qr.png" reconstructed_image.save(reconstructed_path) reconstructed_path ``` ![reconstructed_qr](https://hackmd.io/_uploads/HyZjz9sfyx.png) Vẫn cần fix tay lại 1 chút: ![image](https://hackmd.io/_uploads/HJV6Gqjfyg.png) > INTIGRITI{7h475_h0w_y0u_r3c0n57ruc7_qr_c0d3} --- ## Forensics ### 1. Logging ![image](https://hackmd.io/_uploads/HyW25Oszke.png) ![image](https://hackmd.io/_uploads/rkzKjuifke.png) ```python= ┌──(kali㉿kali)-[~/Desktop] └─$ grep -oP 'GET .*?(?= HTTP/1.1)' app.log > extracted_urls.txt ┌──(kali㉿kali)-[~/Desktop] └─$ cat extracted_urls.txt | python3 -c " import sys from urllib.parse import unquote for line in sys.stdin: print(unquote(line.strip())) " > url_decode.log ┌──(kali㉿kali)-[~/Desktop] └─$ strings url_decode.log | grep -E "IMIT 0,1" | grep "!=CHAR" | grep -oP "!=CHAR\(\K[0-9,]+(?=\))" ``` ![image](https://hackmd.io/_uploads/Hk112usG1l.png) > INTIGRITI{5q1_log_analys1s_f0r_7h3_w1n!} --- ### 2. CTF Mind Tricks ![image](https://hackmd.io/_uploads/HyNG2_sG1g.png) ![image](https://hackmd.io/_uploads/H1gC73_oGJg.png) ![image](https://hackmd.io/_uploads/ByhInuiG1e.png) > INTIGRITI{hidden_in_music_1337} --- ### 3. Hoarded Flag ![image](https://hackmd.io/_uploads/SkzohusMJg.png) ![image](https://hackmd.io/_uploads/Hk35pdjMyl.png) ![image](https://hackmd.io/_uploads/SJTyAusfJl.png) Có thể thấy được ta đã có file flag, nhưng nó đã bị mã hoá bằng pass, cần tìm được pass đúng: Strings với cú pháp: ```python= strings memory_dump.raw | grep -i "flag.7z" ``` Có được pass: ![image](https://hackmd.io/_uploads/r1II5P2fke.png) > ScaredToDeathScaredToLook1312 Giải nén file `flag.zip` với pass vừa tìm được, mình có flag cuối: ![image](https://hackmd.io/_uploads/Hk1hqv3M1x.png) > INTIGRITI{7h3_m3m0ry_h0ld5_7h3_53cr375} --- ### 4. Password Management ![image](https://hackmd.io/_uploads/Bk9fiwnMyg.png) Bài cho file `.E01`, đề cập đến việc file bị xóa, đầu tiên mình load file vào `ftkimager`, kiểm tra trong các thư mục như `bin`, `deleted`, có được 1 số ảnh, trong đó có 1 ảnh này khả nghi: ![image](https://hackmd.io/_uploads/S1Qm3whz1l.png) Có thể thấy được ta đã tìm được pass `SevenSuns397260`, nhưng để làm gì thì mình tiếp tục tìm kiếm trong file, Dạng này giống như bài `ilikemedw` từ `KMACTF2024`, mình kiểm tra các browser, phát hiện được thông tin ở trình duyệt `firefox`: Ở đường dẫn: ```bash= root/Users/cat/AppData/Roaming/Mozilla/Firefox/Profiles/0wzgz3ay.default-release/logins.json ``` Mình phát hiện thông tin này: >{"nextId":2,"logins":[{"id":1,"hostname":"https://super-really-real-bank.com","httpRealm":null,"formSubmitURL":"","usernameField":"","passwordField":"","encryptedUsername":"MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECPe0E72Bq278BAiGUkKH0HzoSg==","encryptedPassword":"MFoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECNF/qseckS4/BDBYcrwEBJ5T2lxluEtiFPFfypt58TEfdDyZBaUN/7HFp4I02jsv/XKzazHG/NOHFNk=","guid":"{c3899385-98e9-4900-b9de-1fabf67ed153}","encType":1,"timeCreated":1728583953428,"timeLastUsed":1728583953428,"timePasswordChanged":1728583953428,"timesUsed":1,"syncCounter":1,"everSynced":false,"encryptedUnknownFields":"MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECN2bf71w2iK/BAiWVos1I88Zqw=="}],"potentiallyVulnerablePasswords":[],"dismissedBreachAlertsByLoginGUID":{},"version":3} ![image](https://hackmd.io/_uploads/HJTzTDhGkx.png) Đây là lịch sử đăng nhập web `https://super-really-real-bank.com` thế nhưng vấn đề là nó đã bị mã hóa, giờ mình cần giải mã được: Để decrypt được, mình sử dụng tool này: > https://github.com/unode/firefox_decrypt > python3 firefox_decrypt.py 0wzgz3ay.default-release ![image](https://hackmd.io/_uploads/SJEW1u3G1l.png) Để decrypt được, ta cần mật khẩu, có lẽ mật khẩu mình tìm được lúc đầu sẽ áp dụng vào đầy: `SevenSuns397260` ![image](https://hackmd.io/_uploads/SkgRJOhG1g.png) >INTIGRITI{4n_unf0r7un473_53r135_0f_m1574k35} --- ### 5. The Puzzled Protocol ![image](https://hackmd.io/_uploads/SkKN6HxQJl.png) Bài cho file `pcap`, mở file đọc qua mình thấy có một số dãy nhìn có vẻ như là `base64`, thế nhưng khi decode lại không có nghĩa: ![image](https://hackmd.io/_uploads/BJFKaBgmJl.png) Sau 1 lúc với GPT, mình biết được đó là `xor+bas64`, key là `0xaa`: Để lọc ra các gói chứa các đoạn đó, mình sort theo length packet: ![image](https://hackmd.io/_uploads/rJHun5pXye.png) Có thể thấy 6 gói chứa các đoạn mã hóa đó: ```bash= w6PDpMO+w6PDrcO4w6PDvsOjw5HDp8Olw67DqMO/w7nDtcOlw7zCmcO4w7jDo8OuwpnDtQ== w6PDpMO+w6PDrcO4w6PDvsOjw5HDrMKew6HCmcO1w6zDpsKew63Dlw== w6PDpMO+w6PDrcO4w6PDvsOjw5HDrMKew6HCmcO1w6zDpsKew63Dlw== w6PDpMO+w6PDrcO4w6PDvsOjw5HDrMKew6HCmcO1w6zDpsKew63Dlw== w77CmcO4w6fCm8Okwp7DpsO1w6nCmsOkw77DuMKaw6bDlw== w67DpMO6wpnDtcKZw7nDqcKew7rCmcO1 ``` Script giải mã: ```python= import base64 # Hàm giải mã XOR def xor_decrypt(data, key): return ''.join(chr(ord(c) ^ key) for c in data) # Giải mã Base64 def decode_base64(encoded_data): return base64.b64decode(encoded_data).decode('utf-8') # Giải mã với khóa XOR def decrypt_with_key(encoded_data, key): encrypted_data = decode_base64(encoded_data) return xor_decrypt(encrypted_data, key) # Giải mã danh sách các chuỗi Base64 với khóa đã biết def decrypt_multiple(encoded_list, key, output_file): with open(output_file, 'w', encoding='utf-8') as file: # Mở file để ghi for encoded_data in encoded_list: decrypted_data = decrypt_with_key(encoded_data, key) result = f"Encoded: {encoded_data} | Decrypted: {decrypted_data}\n" file.write(result) # Ghi kết quả vào file print(result) # Hiển thị kết quả ra console # Danh sách các chuỗi mã hóa encoded_list = [ "w6PDpMO+w6PDrcO4w6PDvsOjw5HDp8Olw67DqMO/w7nDtcOlw7zCmcO4w7jDo8OuwpnDtQ==", "w6PDpMO+w6PDrcO4w6PDvsOjw5HDrMKew6HCmcO1w6zDpsKew63Dlw==", "w6PDpMO+w6PDrcO4w6PDvsOjw5HDrMKew6HCmcO1w6zDpsKew63Dlw==", "w6PDpMO+w6PDrcO4w6PDvsOjw5HDrMKew6HCmcO1w6zDpsKew63Dlw==", "w77CmcO4w6fCm8Okwp7DpsO1w6nCmsOkw77DuMKaw6bDlw==", "w67DpMO6wpnDtcKZw7nDqcKew7rCmcO1" ] # Khóa XOR đúng key = 0xaa # Ghi kết quả vào file output_multiple.txt decrypt_multiple(encoded_list, key, "output_multiple.txt") ``` ![image](https://hackmd.io/_uploads/BkjlaqTQyx.png) > Flag: INTIGRITI{MODBUS_OV3RRID3_DNP3_3SC4P3_T3RM1N4L_C0NTR0L} ---