UofTCTF 2025!
I participated in UofTCTF 2025, organized by the University of Toronto Capture the Flag team, as a member of my institute’s club, InfoSecIITR. These writeups cover the Miscellaneous, Web and Forensics challenges that I personally solved during the competition.
Forensics
Poof
Challenge Description
Yet another pcap, no usb traffic in this one so I’m lost. Can you help me out? :)
Author: 0x157
Solution
This year, we only received one challenge from 0x157 because he was sick. We were given a poof.pcapng file for this challenge. My excitement from the previous pcap challenges, like Skat’s challenge in IrisCTF ‘25, hadn’t worn off yet.
This challenge was solved by my teammate during the competition while I was working on another one. I attempted this challenge later.
I began analyzing the pcapng file in Wireshark. First, I checked the Protocol Hierarchy Statistics, and this was the result:
Next, I examined the TCP packets and found this packet, which contained a listing of the files:
I proceeded to export all the files that were shared:
Only kcaswqcd.ps1 turned out to be useful, so I started analyzing it.
What This Script Does:
Variable and Object Creation:
The script dynamically creates variables using Set-Variable and Set-Item.
It utilizes PowerShell’s -f string format operator to concatenate strings and obfuscate key values.Decryption Logic:
The script initializes cryptographic objects (e.g., AES decryption) and sets up parameters such as keys, initialization vectors (IVs), cipher mode, and padding.
It reads encrypted content and decrypts it using the specified cryptographic parameters.Memory Stream Operations:
The decrypted data is streamed through memory, likely preparing it for writing to a file.
File Creation:
The decrypted content is written to an executable file (.exe) in a temporary directory.
Execution:
The script invokes the newly created executable file using Start-Process.
I extracted the useful part from the ps code:
From this, we obtained the CV, IV, and KEY. Let’s decrypt it on CyberChef as we already had 82nvdkandf.bin:
After decrypting the file, I downloaded the PE file named poof.exe.
I initially attempted to analyze it using IDA and Ghidra but was unsuccessful. Then, I tried using dnSpy, which allowed me to view the desired code.
1 | Imports System |
As you can see, it was performing an XOR operation, so I wrote a script to decode it:
1 | # Given encrypted byte array |
I ran the script and obtained the following output:
1 | $ python3 decode.py |
We got our flag!
Flag:
1 | uoftctf{W4s_1T_R3ally_aN_Impl4nt??} |
Decrypt Me
Challenge Description
I encrypted my encryption script, but I forgot the password. Can you help me decrypt it?
Author: SteakEnthusiast
Solution
In this challenge, we received a password-protected RAR file using version 5.
I examined the file’s hex using the bvi hex editor and noticed that it contained flag.py and another file, flag.enc, stored as Alternate Data Streams (ADS), as shown below:
As expected, we needed to brute-force the password using Hashcat with a dictionary attack. To start, we needed the hash for the password of the file, so I used John the Ripper’s tool rar2john:
1 | $ ./rar2john flag.rar > hash_rar.txt |
For brute-forcing with Hashcat, we need to remove everything before the colon in the output. The remaining content of hash_rar.txt was:
1 | $rar5$16$1d7cb8859a6c3c8e30a9db7a501811ac$15$280234db9d29c6ab216b74e6a89ec226$8$d12d4ba211b9c642 |
Since flag.rar contained two files, we ended up with two hashes. Hashcat would first brute-force the first hash, and then proceed with the second one.
1 | $ hashcat -m 13000 -a 0 -w 4 hash_rar.txt ~/Downloads/rockyou.txt |
It took a considerable amount of time to brute-force the password since the author had set it at the 21.74% mark of the rockyou.txt file. The password turned out to be toronto416
.
Initially, I used unrar to extract the files, but it only retrieved flag.py and not flag.enc. To extract both files from the RAR archive, I switched to using 7z, which successfully extracted them.
1 | ./7z x flag.rar |
Content of the flag.py:
1 | from Crypto.Cipher import AES |
Next, I created a decryption script to decrypt flag.enc and retrieve the flag:
1 | from Crypto.Cipher import AES |
I ran the script and obtained the following output:
1 | $ python3 dec.py |
Finally, we got our flag.
Flag:
1 | uoftctf{ads_and_aes_are_one_letter_apart} |
Miscellaneous
Surgery
Challenge Description
I was thinking of getting some facial contouring plastic surgery done, but didn’t know who to go to. My friend said they had a recommendation for a doctor specializing in that, but only sent me this photo of some building. Who’s the doctor?
Before submitting, wrap the doctor’s name in uoftctf{}
. Special characters allowed, [First] [Last] format.
For example, if the name was Jean-Pierre Brehier, the flag would be uoftctf{Jean-Pierre Brehier}
Author: windex
Solution
We received the following image file:
I attempted a Google Image Search on this image with the prompt: “Where is this surgery place located?” and found this link: https://medtour.help/clinic/jk-plastic-surgery/. I confirmed that this was the correct building because the image matched perfectly.
On the same site, I found the names of several doctors:
I began checking them one by one. It’s worth noting that in South Korea, names are written with the last name first, followed by the first name. So, I reversed the name order for each doctor.
After some time, I identified the correct doctor: Kim Sung-Sik.
Flag:
1 | uoftctf{Sung-Sik Kim} |
Web
Scavenger Hunt
Challenge Description
You know what to do.
Visit the website here
Author: SteakEnthusiast
Solution
This was an easy web challenge and had many solves, so I decided to attempt it. On the main page, it was mentioned that there would be seven parts of the flag.
I inspected all the CSS and JavaScript files by viewing the page source. There was also a /hidden_admin_panel endpoint for the admin. I gained access by modifying the cookies to change the user. One part of the flag was hidden in the headers as a key-value pair: X-Flag-Part2: c4lm_4nd_.
Altogether, we managed to collect all seven parts of the flag.
part 1: uoftctf{ju57_k33p_
p_a_r_t_f_i_v_e=4pp5_
part4=411_7h3_
part7 c0d3!!}
part3 1n5p3c7_
Part 6: 50urc3_
Part2: c4lm_4nd_
Flag:
1 | uoftctf{ju57_k33p_c4lm_4nd_1n5p3c7_411_7h3_4pp5_50urc3_c0d3!!} |