Description
Welcome to VR school.
Setup
Connect to the challenge server with netcat.
Download the binary and libc if provided for local testing.
nc <challenge_host> <PORT_FROM_INSTANCE>wget <challenge_url>/vr-school # binary for local analysisSolution
Walk me through it- Step 1Analyze binary protections and heap behaviorUse
checksecto enumerate binary mitigations, then run the binary locally under GDB with pwndbg/peda to understand the heap allocation pattern and identify the vulnerability.bashchecksec --file=vr-schoolbashgdb -q ./vr-schoolbash# Inside GDB with pwndbg:bash# run, heap, bins, vis_heap_chunksLearn more
checksec reports which binary hardening features are enabled: NX (non-executable stack), PIE (position-independent executable), stack canaries, RELRO (relocation read-only), and FORTIFY. These determine which exploitation techniques are viable. For heap challenges, PIE and full RELRO are the most impactful - they prevent leaking code addresses and overwriting the GOT, respectively.
pwndbg is a GDB plug-in that adds heap-aware commands:
heaplists all allocated chunks,binsshows the tcache/fastbin/unsorted bin contents, andvis_heap_chunksrenders the heap layout as a color-coded diagram. These tools make it easy to visualize the heap state at any point in execution. - Step 2Identify and trigger the heap vulnerabilityInteract with the program's menu to understand what heap operations are exposed. Look for a use-after-free (UAF) or tcache poisoning opportunity - allocate chunks, free them, and observe whether freed pointers can still be accessed.
Learn more
Tcache poisoning is an attack against glibc's per-thread caching mechanism introduced in glibc 2.26. Each tcache bin stores a singly-linked list of freed chunks of the same size. The forward pointer (
fd) of each freed chunk points to the next chunk in the bin. By overwriting a freed chunk'sfdpointer with an arbitrary address, the attacker causesmalloc()to return that address on a subsequent allocation - achieving arbitrary write.Use-After-Free (UAF) occurs when a program continues to use a pointer after the memory it points to has been freed. In glibc, freed heap chunks' first 8 bytes become the
fdpointer. If the program lets you write to a freed chunk, you can overwrite this pointer. The nextmalloc()of the same size returns the poisoned address. - Step 3Leak libc base and overwrite a function pointerUse the heap vulnerability to leak a libc address (by reading the fd of an unsorted bin chunk), calculate the libc base, then overwrite
__free_hookor a GOT entry with the address ofsystem. Pass/bin/shas the next freed chunk to pop a shell.bash# pwntools skeletonpythonfrom pwn import *bashp = process('./vr-school')bash# ... exploit steps ...bashp.interactive()Learn more
ASLR randomizes the base address of libc each run, so hard-coding addresses fails. To defeat ASLR, leak a runtime libc pointer first. Chunks freed into the unsorted bin (size > 0x408) have their
fdandbkpointers set to an address insidemain_arenain libc - reading these leaks the libc base.__free_hookis a glibc function pointer that, if non-NULL, is called byfree()instead of the real deallocation logic. Overwriting it withsystemand then callingfree(ptr)where*ptr = "/bin/sh"effectively callssystem("/bin/sh"). Note: in glibc ≥ 2.34,__free_hookwas removed - alternative targets include the_IO_FILEvtable or the tcache struct itself.
Flag
picoCTF{...}
Heap exploitation via tcache poisoning or UAF - leak a libc address from the unsorted bin, calculate offsets, overwrite a hook with system, and trigger it with a /bin/sh pointer.