Magic Scrolls
hackthebox
Task: glibc 2.37 menu-based heap pwn where a global magic_numbers[] array overlaps the spells[] pointer table, giving an arbitrary 8-byte write into two heap-pointer slots. Solution: build arbitrary read/free primitives from the overlap, leak heap (safe-linking) and libc (unsorted bin), perform a double-free-key-safe overlap-poison tcache write of _IO_list_all, and trigger House of Apple 2 FSOP via exit() for a shell.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Magic Scrolls — HackTheBox
Description
Legends say that if magical numbers align in the right sequence, magic will happen.
A medium-difficulty heap-exploitation challenge. We are given a PIE ELF64 binary magic
(not stripped) bundled with its own loader and libc (Debian GLIBC 2.37-7), plus a Dockerfile
(ubuntu:22.04 + socat). The remote service runs:
socat tcp-l:1337,reuseaddr,fork EXEC:./magic
Goal: pop a shell on the remote and read flag.txt.
Analysis
Protections
Full RELRO | Stack Canary | NX | PIE
Crucially the libc is glibc 2.37, where __free_hook and __malloc_hook have been
removed (the symbols may still exist but are never dereferenced by the allocator). That kills
the classic hook-overwrite RCE path — code execution must come from FSOP (we use
House of Apple 2).
Program behavior
main first reads a "magic charm":
read(0, buf, 0x40); if (strcmp(buf, "Alohomora") == 0) power = 4; // unlocks the bug
Then a 6-option menu loops:
| Opt | Name | Effect |
|---|---|---|
| 1 | update_magic_numbers | write a magic number, and (if power!=0) project two of them onto spells[0]/[1] |
| 2 | create_spell | size=read(0,buf,0x1ff); spells[c]=malloc(size); memcpy; c++ |
| 3 | remove_spell | free(spells[idx]); spells[idx]=0; spell_len[idx]=0 |
| 4 | read_spell | print super_spell_len-1 bytes from super_spell (arbitrary read) |
| 5 | set_favorite_spell | first call selects a spell; later calls only refresh the pointer |
| 6 | exit | exit() |
Global memory map (offsets from PIE base)
...
$ grep --similar
Similar writeups
- [pwn][free]Ox78— tjctf
- [pwn][free]Funkynator— hackthebox
- [pwn][Pro]iz_heap_lv1 — BSS-pointer overlap + tcache poisoning— spbctf
- [pwn][free]Portaloo— hackthebox
- [pwn][free]priority-queue— b01lersc