# ISITDTU CTF QUALS 2024 ### Yapping (GPT generated) In this writeup, I'm presenting (not so) detailed breakdown of two challenges I created for ISITDTU Qualification 2024: **unexpected**, **swatted** I'm open to any feedback you might have, as I'm always looking to improve both the design and clarity of my challenge writeups. BTW, I am not a native English speaker, so I appreciate your understanding and any feedback you have on my writing. Now, let’s get into the details of each challenge and explore the solutions. ## [Forensics] unexpected Before creating this challenge, I encountered some info-stealer cases online, and one that inspired it was Lumma Stealer. These stealers will be distributed through various methods to lure gamers and kids into downloading hack tools which is malwares. ![image](https://hackmd.io/_uploads/BJphMrjgkg.png) They used platforms like GitHub, phishing websites, or even YouTube to lure the victim in. ![image](https://hackmd.io/_uploads/By9zXSie1g.png) Those are just some small cases. One of them using mediafire to host malwares in a folder like this: ![image](https://hackmd.io/_uploads/S1C_7Sog1g.png) I thought it would be "icet" to create a challenge based on this. I provided two pieces of evidence as follows: ``` ├── challenge.pcapng ├── MaliciousPID.dmp ├── sslkeylog.txt (use in pcap) ``` Mostly, SSL key log will be generated by some browsers because they support the environment variable SSLKEYLOGFILE. This feature also supported by Wireshark in order to decrypt TLS sessions (which was generated by browsers). To decrypt TLS with these keys, you can follow steps in this [blog](https://www.packetsafari.com/blog/2022/10/07/wireshark-decryption/). Here is the result after decrypt those sessions: ![image](https://hackmd.io/_uploads/BkGWY59e1l.png) Since the browsers support this functionality, we can infer that this pcap captures user's browser activities. ### Identify the browser victim is using By looking into some HTTP or HTTP2 or HTTP3 request packets, we can easily identify the browser which is Edge. ![image](https://hackmd.io/_uploads/SkXm9cqeJl.png) User-Agent: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0` ### Activities What would you typically do when using a browser? Most likely, you’d search for something. Since we know this is Microsoft Edge, we can look for search terms in the Wireshark. Let's filter http3 and search for "search?q=" string. ![image](https://hackmd.io/_uploads/SJy_1sqlke.png) The result contains what the user searched for: "roblox" And you can also search for "search?pglt" for more results ![image](https://hackmd.io/_uploads/r15BWj9lyg.png) Or "qbox?query" ![image](https://hackmd.io/_uploads/BkBjGoce1e.png) Here is some of the search terms you can extract from the pcap. ``` best game 2024 roblox roblox download roblox hack roblox execute youtube.com ``` Now we know what's going on. ### Where is the malware? When tracking in the capture, you may notice this request to mediafire. ![image](https://hackmd.io/_uploads/r14hrj5xyl.png) According to whatever we got at the moment with the order of the packets, we can assume this is the malicious file that victim downloaded. Here's the extracted file from the pcap. ![image](https://hackmd.io/_uploads/Hk4kPo9lke.png) But the zip was password-protected so we need to find the pass. Let's look back the mediafire traffic again. For mediafire, you can search for "/file" or "/folder" to get what user are looking at. ![image](https://hackmd.io/_uploads/SJARKocxkx.png) And then if you search for the files, you will bump into this: ![image](https://hackmd.io/_uploads/Sk3H9o5lke.png) URL: `https://www.mediafire.com/file/ap30ok09ae3gtt0/p%2540ss_-_UHeuYKpnz17YUj8N.txt/file` which is `p@ss_-_UHeuYKpnz17YUj8N.txt` So we got the password is: ***UHeuYKpnz17YUj8N*** ### Reverse this executable DIE detect the executable is C# dotnet with Confuser Obfuscator ![image](https://hackmd.io/_uploads/B1o1K2ce1g.png) The code when loaded into DNSpy is a freaking mess ![image](https://hackmd.io/_uploads/S13Etn5eye.png) In order to deobfuscate this, we can use de4dot. ![image](https://hackmd.io/_uploads/H1Jctnql1l.png) Yup, its better now I guess. ![image](https://hackmd.io/_uploads/B1rAK2qeJg.png) From `Class1` code, you can see its calling Assembly.Load() to load malicious code. But before that `Class0.smethod_0()` called to decrypt 2 parameter and its just a xor function: ![image](https://hackmd.io/_uploads/Byf75n5gJe.png) The parameters are the key (array3) and the buffer (array2) ![image](https://hackmd.io/_uploads/r1xNchclkx.png) Here is the key, just decode the hex. ![image](https://hackmd.io/_uploads/HJMrch5eyl.png) And here is the buffer, you can extract it directly from DNSpy. ![image](https://hackmd.io/_uploads/SJbPc2cxyg.png) Xor them together, we got the malware. ![image](https://hackmd.io/_uploads/Hy2F5h5l1l.png) I noticed many players had dumped the exe out of the memory too. That's still a cool way to retrieve the binary. If you tried dumping the binary and it got corrupted, yall need to realign PE sections. Unmapping from the virtual to raw should be good. ### C2 traffic decryption Here is the simple flowchart that I created. I made modfications to the agent's code so the challenge could be more interesting. In the original, DNS traffic wouldn't be encrypted by the second random AES key. It shared the same key with the decrypting process. ![Untitled Diagram](https://hackmd.io/_uploads/HkWhYp5x1x.jpg) In the `main` function there is an API URL to get videos from youtube. ![image](https://hackmd.io/_uploads/SyryeNoeye.png) You can access the private playlist from the ID. These are the commands from the server. ![image](https://hackmd.io/_uploads/S1gm9T9lkx.png) The malware will listening for new videos, get its ID and extract its thumbnail. However, it will send the second AES key to the server first. The second AES key was encrypted by a hardcoded RSA public key before sending to the server. Probably there is no way to recover the private key. Also, the interval will be 120 seconds for each videos. ![image](https://hackmd.io/_uploads/rkB8c6cxyl.png) The code will use this key to decrypt the command. ![image](https://hackmd.io/_uploads/H1fE5p5gyx.png) Here is one simple script to decrypt the videos. ```py from pyzbar.pyzbar import decode import numpy as np import cv2 from base64 import b64decode from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import requests key = bytes.fromhex('c4530e2eeb9ea61d57910fe9ec86f47e25359840bf430c3ce78e4c363c5d24ef') iv = bytes.fromhex('6c44f45102fdd739cbc6b572ed8698db') def decode_qr(data): nparr = np.frombuffer(data, np.uint8) img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) decoded_objects = decode(img) qr_data = [obj.data.decode('utf-8') for obj in decoded_objects] return qr_data[0] video_ids = [ 'qzbLU-X4aAc', 'iOs_wfWd3ns', 'aAUhhzXaakI', 'Ft_TtTMNvdg', 'Ny4Hp9Jdm-g', 'FU5jR09A3oM' ] for id in video_ids[::-1]: url = f'https://i.ytimg.com/vi/{id}/hqdefault.jpg' r = requests.get(url) image = r.content data = decode_qr(image) enc = b64decode(b64decode(data)) cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = cipher.decrypt(enc) print(unpad(plaintext, AES.block_size).decode()) ``` Here is the result: ``` dir whoami echo 'part2: _c0uLd_B3_u5' > dir C:\ type C:\Users\flag3.txt echo "part2: _c0uLd_B3_u5" > NULL ``` For the third part, you need to decrypt the output from those commands. The output will be converted to base64 then encrypted with the second AES key and exfiltrated over DNS. ![image](https://hackmd.io/_uploads/SyqNcpcxJx.png) Let's extract DNS records from Wireshark! ![image](https://hackmd.io/_uploads/SJ1MLEoeye.png) As you can see, the queries are duplicated so we need to filter those out. You can use this command to extract the time and queries. ![image](https://hackmd.io/_uploads/SJUwP4ol1x.png) Time gap is quite big between each commands so this should be no problems. It should be 120, the same with the interval. ![image](https://hackmd.io/_uploads/BJiFvViekx.png) We can write a simple script to decrypt these. ```py from Crypto.Cipher import AES from Crypto.Util.Padding import unpad from base64 import b64decode key = bytes.fromhex('1f687a50da70e4741e7d2ba42e0a1b9cd4567179d78ac655afa3297e507cfbc8') with open('dns.txt', 'r') as f: data = f.readlines() block = '' for i in range(len(data) - 1): curr_time, dns_query = (data[i].strip().split(' ')) next_time, _ = (data[i + 1].strip().split(' ')) if dns_query == _: continue curr_time = round(float(curr_time)) next_time = round(float(next_time)) block += dns_query.replace('.wallpaperzn.store', '') try: if (next_time - curr_time) >= 120: block = block.replace('-', '/').replace('_', '+') enc = None try: enc = b64decode(block) except: enc = b64decode(block + '=') iv = enc[-16:] enc = enc[:-16] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = cipher.decrypt(enc) print(unpad(plaintext, AES.block_size).decode()) block = '' except Exception as e: print(e) block = '' pass ``` Result: ``` Volume in drive C has no label. Volume Serial Number is 5860-2D7D Directory of C:\game\SolaraExecutor 15/10/2024 09:34 pm <DIR> . 15/10/2024 09:34 pm <DIR> .. 15/10/2024 09:14 pm 248,832 SolaraExecutor.exe 1 File(s) 248,832 bytes 2 Dir(s) 31,158,628,352 bytes free --- desktop-7d9f3au\miku --- null --- Volume in drive C has no label. Volume Serial Number is 5860-2D7D Directory of C:\ 15/10/2024 09:34 pm <DIR> game 07/12/2019 02:14 am <DIR> PerfLogs 15/10/2024 07:40 pm <DIR> Program Files 05/05/2023 05:27 am <DIR> Program Files (x86) 15/10/2024 06:31 pm <DIR> Users 06/10/2024 07:49 am <DIR> Windows 0 File(s) 0 bytes 6 Dir(s) 31,211,749,376 bytes free --- ed_4s_c2-chAnNe|~} --- ``` How I got the second AES key? Just use `aeskeyfind` on the dump. However you can debug the dump too. And the first part of the flag will be in the config of the malware. ![image](https://hackmd.io/_uploads/SkAU5T9lkx.png) There you go! That's all. #### FLAG: ISITDTU\{3vEry7h!n9_c0uLd_B3_u5ed_4s_c2-chAnNe|~\} (I made a mistake where the flag in the challenge ended up being one character too long. ISITDTU\{3vEry7h!n9__c0uLd_B3_u5ed_4s_c2-chAnNe|~\}) ___ ## [Forensics] swatted I expected this challenge should be easier than the previous one. It focuses on Linux forensics and involves multiple artifacts. Players will need to map these records together to get a complete picture. Artifacts related: - Elektra Database - Wire Messaging app - Linux shell history (.bash_history) - Linux user & groups information - Docker - Git log - GPG ### [1]. What is the credential used to login to the machine? To solve this, you just need to crack shadow file in the system **Answer: imsadboi:qwerty** ### [2]. The criminal used a messaging app to communicate with his partner. What is the name of the app? Look into .bash_history of the current user which is *imsadboi*, we can know what app he installed. ![image](https://hackmd.io/_uploads/H1n6rHox1x.png) **Answer: Wire** ### [3]. What is the username of the criminal (The app username)? If we want to retrieve information related to this app, there's a way to recover data from IndexedDB. There are many tools on the Internet that we can use to do this process. Or you can follow this [blog](https://velog.io/@hunjison/Forensic-Analysis-of-Wire-Messenger-in-Windows-OS). Or you can strings the whole directory and grep the data. It's your choice. Here is the conversation log: ![image](https://hackmd.io/_uploads/BJcDOBil1x.png) Here is the handles. Our criminal is the first one. ![image](https://hackmd.io/_uploads/r1SROrsgJx.png) **Answer: anonymous69420** ### [4]. What is his partner's username? **Answer: clowncz123** ### [5]. His partner sent him a file. What is the URL used to download the file? By following the conversation, we can easily see this record. ![image](https://hackmd.io/_uploads/rJxZuBslkg.png) **Answer: https://file.io/lIPzLAvhF5n4** ### [6]. When did the partner send the URL (UTC)? The original question is "[6]. What is the timestamp of the file sent by his partner (UTC)?". But this one is not clear and confused some players. This is my another mistake. The time is in the above record. **Answer: 2024-10-24 09:59:12** ### [7]. What is the timestamp when the criminal downloaded the file (UTC)? For this timestamp, we need to look up in `places.sqlite` of Firefox. ![image](https://hackmd.io/_uploads/SklEqPig1x.png) The reason why we don't take the timestamp of the `https://file.io/lIPzLAvhF5n4` because its just a home page to display file name, file size, etc. When user clicked into download button, it will redirect to the second url which is `https://www.file.io/Eh9e/download/lIPzLAvhF5n4`. Use epochconverter or alternatives will give you the answer. **Answer: 2024-10-24 10:01:12** ### [8]. His partner accidentally leaked his email. What is the email address? ``` C: btw, do you have the website? P: which one? C: the one i told you two weeks ago P: ahhh i see P: let me check P: https://file.io/lIPzLAvhF5n4 here it is ``` According to the conversation, the criminal downloaded the file that his partner gave to him. Its name is `final_app.zip`. You can the it in `places.sqlite` ![image](https://hackmd.io/_uploads/rJhwbOoxJl.png) Back to the history, we can see the criminal unzipped this file in ~/Downloads/ and installed docker to run an app in it. ![image](https://hackmd.io/_uploads/SyxAqHilke.png) ![image](https://hackmd.io/_uploads/Sk0R5Bsx1e.png) ![image](https://hackmd.io/_uploads/ByGJiBieyx.png) In the end, he deleted all of the files. ![image](https://hackmd.io/_uploads/S1qxG_igye.png) So now we've already known that the app is using docker. We can come to this path `/var/lib/docker/overlay2` to browse all of the layers of the image. Extract one of the layers which has the app, we can see it has some of git config files in it. ![image](https://hackmd.io/_uploads/Hym6QuoeJe.png) Using git log and we will have the email. ![image](https://hackmd.io/_uploads/rJ6xEdsg1g.png) **Answer: theclownz723@gmail.com** ### [9]. Luckily, we caught the criminal before he could send the sensitive information. How many credentials did he manage to steal? In this question, we have to decrypt `credentials.txt.gpg` file. Actually you can carve this file out of the disk without decrypting it either (again, another mistake when I did not shred this file). For the decrypting way, here's how we do it. As you can see in the history, the criminal get the creds file from ~\Downloads path then encrypt it using gpg. However, we neither know what the password is nor how to crack this file (the password was not in any dictionary). ![image](https://hackmd.io/_uploads/rJBEsHixJl.png) But when we scrolling up, we can see him used kdb to mount secret/password. Assuming that he took the random string from $a and used it as the password then stored in `user:/secret/password`, we can try to decrypt this and get that password back. ![image](https://hackmd.io/_uploads/ry1BoSog1l.png) You can see the file was mounted in `/root/.config` path when ran those commands as sudo. ![image](https://hackmd.io/_uploads/S1eLoBig1e.png) `kdb` is Elektra Database, which simply mount user file into a hierarchy database like registry. kdb has many plugins, one of them is `fcrypt` which will encrypt the mounted configuration by using gpg or gpg2. You can look up elektra [document](https://doc.libelektra.org/api/0.9.4/html/doc_tutorials_crypto_md.html) to find more about this. ![image](https://hackmd.io/_uploads/rkYF2Diekl.png) When decrypting this file, you will be prompted password to decrypt the private key/the encrypt file. You can take the criminal's login password as the input. ![image](https://hackmd.io/_uploads/r1gc0vje1e.png) **Answer: 23** ### [10]. What is the email address and the password of user 'blistery'? Read the file then we will have the final answer. **Answer: blistery@yahoo.com:HDTSy0C7ZBCj** #### FLAG: ISITDTU{https://www.youtube.com/watch?v=H3d26v9TciI}