UniVsThreats CTF 2025

比赛地址:UniVsThreats CTF 2025

比赛时间:2025-05-03 18:00 - 2025-05-04 18:00

Forensics

Dark Web Stories

Challenge

You were running a Tor exit node on dark web to intercept some traffic from different .onion websites. It was pretty boring, until, at some point, you got something interesting. It seems that somebody was trying to penetrate an illegal website in order to find something about an underground organization. You saved the dump of the traffic and now it’s time to analyze it more in depth. Find out what this is all about.

Solution

UniVsThreatsCTF2025-1

There were a lot of /send requests at the end, go back to Wireshark to extract them.

First, filter out the traffic that meets the criteria.

1
http.request.method == "POST" && http.request.uri == "/send"

UniVsThreatsCTF2025-2

Open one of them and find that it contains chat records.

UniVsThreatsCTF2025-3

Then select all and export as dump.json, and write a Python script to extract the conversations from it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json

file_path = r"E:\Desktop\conversation_dump\dump.json"

keys_list = []

with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)

for item in data:
try:
# 提取 urlencoded-form.key
key_value = item['_source']['layers']['urlencoded-form'].popitem()[1]['urlencoded-form.key']
keys_list.append(key_value)
except (KeyError, IndexError):
continue

for _, key in enumerate(keys_list, start=1):
print(key)

The extraction results are as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
R1kS: Yo, are you here? Got something for you.
Charon VI: Hey, what's up?
R1kS: Was crawling on their website, 68b36d42880c527fb70086b1b97f4f34e49bc0d538f52607ec4009c552c2a63b.onion, or BlackVault as they call it. Managed to retrieve their sensitive documents, but somehow it's password protected and i cannot crack it using my regular tools.
Charon VI: Great job. Thought since the begining that they encrypt their files in case of a breakout.
Charon VI: Luckily, more or less, they were holding some of their passowrds in a database located on another server. Glad I was able to find it.
R1kS: That's very good. So, will you give me the password for this secret archive?
Charon VI: I will, but something is not right. There are multiple strings, and I don't understand what to do with them. Maybe you can find out.
R1kS: Sure. Drop 'em here. Those guys will finally learn Dark Web is not for everyone. They will not even know what struck them.
Charon VI: I will drop 'em one by one.
Charon VI: 5dbc98dcc983a70728bd082d1a47546e
Charon VI: f72c915d8f575a5c0999b5f37b6d99b7
Charon VI: a20bba554bfa1580a9d4aa2b6879ed46
Charon VI: 02beeea47ee3cfe212e6bd843b9ce7d3
Charon VI: 3112c7a8b6cd1677db0e3173e140fc05
Charon VI: 50f4646135205fd4a5417e460cf71d3c
Charon VI: eb22cfa0890a2df3177966854a7176bc
Charon VI: 845f49aa19c955b849d57593bf09d224
Charon VI: 87f63931da79aa969ac4a776ce6cfb03
Charon VI: 9793d9d6041c80f46ad7c1f530c8bbf8
Charon VI: 2f88d89a8f50426a6285449be3286708
Charon VI: 61bd22f017588208a0cacdf9a1a7ca1e
Charon VI: a7623c8b76316e10538782371b709415
Charon VI: c6cca42180caba17e9e6882dc66cc6ee
Charon VI: 7c854900e46ebc5ee5680032b3e334de
Charon VI: ac81882b848b7673d73777ca22908c0d
Charon VI: 4ce97d67963edca55cdd21d46a68f5bb
Charon VI: 4abb62a00bccb775321f2720f2c7750b
Charon VI: 67e00e8ef738fe75afdb42b22e50371e
Charon VI: b561052e5697ee5f1491b5e350fb78e1
Charon VI: That's all.
R1kS: Wow, that's a lot of them! I'll see what I can do.
Charon VI: You are on your own. I feel like someone is listening to us right now. We've never met, bye!
R1kS: Yeah, I feel the same. Even this channel ain't secure no more. Bye!

The MD5 hash values, when queried one by one, were found to correspond as follows: the first hash corresponds to the original string s, the second to Su, the third to Sup, and the fourth to Sup3. The next ones cannot be obtained through querying anymore. However, based on the message mentioned in the chat log — I will drop 'em one by one. — it is not difficult to infer that what we need to do next is perform a character-by-character incremental hash matching attack on this series of MD5 hash values in order to recover the original strings. We can write a Python script to carry out this brute-force cracking.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
hash_block = """Charon VI: 5dbc98dcc983a70728bd082d1a47546e
Charon VI: f72c915d8f575a5c0999b5f37b6d99b7
Charon VI: a20bba554bfa1580a9d4aa2b6879ed46
Charon VI: 02beeea47ee3cfe212e6bd843b9ce7d3
Charon VI: 3112c7a8b6cd1677db0e3173e140fc05
Charon VI: 50f4646135205fd4a5417e460cf71d3c
Charon VI: eb22cfa0890a2df3177966854a7176bc
Charon VI: 845f49aa19c955b849d57593bf09d224
Charon VI: 87f63931da79aa969ac4a776ce6cfb03
Charon VI: 9793d9d6041c80f46ad7c1f530c8bbf8
Charon VI: 2f88d89a8f50426a6285449be3286708
Charon VI: 61bd22f017588208a0cacdf9a1a7ca1e
Charon VI: a7623c8b76316e10538782371b709415
Charon VI: c6cca42180caba17e9e6882dc66cc6ee
Charon VI: 7c854900e46ebc5ee5680032b3e334de
Charon VI: ac81882b848b7673d73777ca22908c0d
Charon VI: 4ce97d67963edca55cdd21d46a68f5bb
Charon VI: 4abb62a00bccb775321f2720f2c7750b
Charon VI: 67e00e8ef738fe75afdb42b22e50371e
Charon VI: b561052e5697ee5f1491b5e350fb78e1"""

import hashlib

# Extract all hashes into a list
provided_hashes = [line.split(": ")[1].strip() for line in hash_block.strip().split('\n')]

# Define character set
charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()-_=+[]{}\\|;:\'",.<>/?'

# Initialize current string
current_string = ""

# Iterate over each hash
for i, target_hash in enumerate(provided_hashes):
print(f"[+] Cracking hash #{i + 1}: {target_hash}")
found = False
for char in charset:
# Construct candidate string
candidate = current_string + char
# Compute MD5 hash
md5_hash = hashlib.md5(candidate.encode()).hexdigest()
if md5_hash == target_hash:
current_string = candidate
print(f" Character found: '{char}' → Current string: '{current_string}'")
found = True
break
if not found:
print(" ❌ No matching character found. Stopping the cracking process.")
break

print("\nFinal decrypted result:")
print(current_string)

The password obtained through brute-force cracking is:

1
Sup3r$3cre7P4$Sw0rd!

According to the chat logs, this password was used to unlock a certain file. Then, using binwalk, an encrypted zip archive was extracted. Using this password, the archive was successfully decrypted, yielding a .png image.

UniVsThreatsCTF2025-4

The flag was obtained using LSB steganography.

1
UVT{4_l0T_0f_lay3r5_70_unc0v3r_1nn1t?}

Flag Shredder

Challenge

Our top operative was moments away from exfiltrating a critical piece of intel when their USB drive was hastily wiped. All that remains is this disk image: freeflags.img.

On it, you’ll find a suspicious executable that seems to be doing… something.

See if you can solve the case, we are counting on you!

Solution

The flag is in the deleted image.

UniVsThreatsCTF2025-5

1
UVT{D3l3t3d_But_N0t_D3stRoy3d}

RAMblings of Cornelia

Challenge

Our digital forensics team, Shell Access Without Authorization (SAWAT), requires your help. One of our top analysts, Cornelia Kernelescu, had a bit of a… meltdown. She’s vanished without a trace, but not before trashing her machine in what appears to be a very dramatic protest.

We believe Cornelia left behind an encrypted file containing sensitive internal data — likely SAWAT intel — along with some personal notes. Think you can recover Cornelia’s digital trail?

You can download the archive here: Download cornelias-memory-archived.7z

Solution

According to the problem description, search for cornelia in the scanned files.

UniVsThreatsCTF2025-6

Found the personal notes mentioned in the problem.

UniVsThreatsCTF2025-7

UniVsThreatsCTF2025-8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Cornelia's Master Plan (DRAFT)

✔️ Watch the team ignore every security recommendation
✔️ Collect receipts from the group chat
✔️ Archive everything
Save the password somewhere safe
Finish cleanup
Log out
Make a graceful exit

hey.

if you are reading this, then i did not get to finish cleaning up.
and if that is the case, i am guessing it s not one of my colleagues who
found these notes -- sawat probably paid you. they would have to because
nobody on that team could find their way out of /tmp

listen. do not trust them.
they will tell you i had some sort of meltdown and left but truth is
i saw too much of the internal stuff and they did not like it

the archive is still around here somewhere. take it. open it. run with it.
whatever you do, do not give it back to sawat.

they do not deserve it. you'll see why when you get it open.
1
2
3
4
5
6
7
8
Just in case I forget:

c4nN0L0ng3rIgn0r3Th1s@

this should probably go in binwarden or anywhere safe, but @rootbutcute committed the .env file
to git again..

I must deal with this later.

Next, an encrypted archive company-intel.7z was found under \Users\sawat, and the extraction password is indeed c4nN0L0ng3rIgn0r3Th1s@.

UniVsThreatsCTF2025-9

The flag is hidden in the image inside the archive.

1
UVT{C0rn3l1a_dUmPs_tH3_r4W_tRutH}