Scenario
The Brine Signet lies shattered beneath the waves. Astrael has vanished into the upper storms. Only the Salt Crown remains -- heavy with the weight of a kingdom that drowns in its own blood. When the Seal broke, the Realm bled. The Cinderbound guard what remains. And the sea... the sea remembers everything.
Prerequisite Knowledge
To fully understand and solve this challenge, familiarity with the following concepts in Linux Kernel Exploitation is required:
- Linux SLUB/Slab Allocator: The kernel subsystem responsible for allocating memory for objects of similar sizes (e.g.,
kmalloc-32,kmalloc-512). Understanding freelists and object reuse in SLUB memory pools is key to controlling heap layouts. - Use-After-Free (UAF): A memory corruption vulnerability occurring when a program continues to use a pointer after the memory it references has been deallocated. In the kernel, a UAF allows an attacker to manipulate overlapping data structures.
- Kernel Address Space Layout Randomization (KASLR): A security mechanism that randomizes the base memory address of the kernel code and tables upon reboot to prevent hardcoded address exploitation.
- procfs &
seq_fileInterfaces: Virtual files under/proc(like/proc/self/mountinfo) allocate dedicated kernel structures (such asseq_fileor private mount iteration data) in specifickmallocslabs when opened. These structures frequently contain function pointers within the kernel code text segment, making them ideal targets for defeating KASLR. modprobe_pathExploitation Technique: An arbitrary write privilege elevation technique in Linux kernels. When the kernel encounters an executable file with an unrecognized binary format (unregistered magic bytes), it invokes a userland helper defined at the global kernel symbolmodprobe_path(defaulting to/sbin/modprobe) with root privileges. Overwriting this string with an arbitrary shell script path yields arbitrary command execution asroot.- Kernel Security Mitigations (SMEP / SMAP):
- SMEP (Supervisor Mode Execution Protection): Prevents the CPU from executing user-space code while running in ring 0 (kernel mode).
- SMAP (Supervisor Mode Access Prevention): Prevents ring 0 code from accessing user-space memory directly without explicit kernel accessor helpers (
copy_from_user/copy_to_user).
Enumeration
File Structure
The challenge archive provides a standard Linux kernel exploitation testing environment:
QEMU Boot Script (run.sh) Analysis
Examining run.sh highlights several active security mitigations and boot parameters:
- Active Mitigations:
kaslr,smep,smap,kpti=1(Kernel Page Table Isolation). - Debug Interface:
-sopens a GDB debugging stub onlocalhost:1234. - Serial Console:
console=ttyS0routes terminal input/output over serial, requiring base64 chunk uploading for binary deployment in remote exploits.
Init Script Analysis (initramfs)
Unpacking initramfs.cpio.gz reveals the initialization workflow in /init:
- The filesystem mounts essential pseudo-filesystems (
/proc,/sys,/dev). - The custom driver is loaded into the kernel:
insmod /lib/modules/krown.ko. - The device node is created:
/dev/krownwith read/write access (chmod 666 /dev/krown). - A standard low-privilege shell is spawned for the user, while
/flag.txtis owned byroot:rootwith strict permissions (chmod 400).
Tools Used
During analysis, reverse engineering, and exploit deployment, the following standard command-line tools were utilized:
r2(radare2) /objdump/nm: Used for disassembly, symbol reconstruction, and inspecting IOCTL dispatch handlers without requiring heavy IDEs like Ghidra or IDA Pro.gdb(GNU Debugger): Attached via QEMU's-sflag to analyze real-time kernel memory layouts, examine slab allocators, and calculate offsets from leakedseq_filestructures.musl-gcc(x86_64-linux-musl-gcc): Extremely lightweight C compiler used to compile static, self-contained exploit binaries (-static -O2), minimizing overall binary size (~59KBafterstrip) for fast transmission over slow serial interfaces.pwntools(Python): Orchestrates network interaction, automated chunked serial file transmission, payload deployment, and interactive shell handling.
Reverse Engineering & Code Analysis
By analyzing krown.ko using objdump and radare2, we reconstruct the functional characteristics of the module. The driver exposes a character device /dev/krown driven by an IOCTL handler.
Object Structures in Kernel Memory
The driver defines a feudalistic object management system in kernel memory based on two concepts: Lords and Vassals.
IMPORTANT
Both lord_obj and vassal_obj reside exactly inside the kmalloc-512 slab pool. Because both structures share the exact same allocator cache, freed Vassal slots can be directly reallocated as Lords or overlaid by standard Linux kernel subsystem structures of similar size!
IOCTL Command Dispatcher
The module supports five primary IOCTL commands:
ALLOC_LORD(0x10): Callskmalloc(512, GFP_KERNEL), initializes header metadata (magic = 1), assigns a unique ID, and returns the handle.ALLOC_VASSAL(0x20): Callskmalloc(512, GFP_KERNEL), initializes header metadata (magic = 2), and prepares the buffer.BIND_VASSAL(0x30): Takes a Lord ID and a Vassal ID. Stores a direct pointer to the Vassal inside the Lord's tracking arrays (lord->vassals[idx] = vassal_ptrandlord->ptr = vassal_ptr).BREAK_OBJ(0x40): Destroys an object by ID by callingkfree(obj_ptr)and removing it from the global lookup dictionary.EXAMINE/IMPRESS/INSCRIBE(0x50, 0x60, 0x70): Read and write operations operating on bound Vassal structures via their Lord's tracking array or primary pointer..
Vulnerability Analysis
The Vulnerability: Unsanitized Reference Deletion (Use-After-Free)
When BREAK_OBJ is invoked on a Vassal that has previously been bound to a Lord via BIND_VASSAL, the driver looks up the Vassal in the global table, removes the dictionary entry, and immediately executes kfree(vassal).
Why is it Vulnerable?
- Dangling Pointers: The Lord object remains completely unaffected by the breakage of the Vassal. The internal array
lord->vassals[idx]continues pointing directly to the memory address of the freed chunk in thekmalloc-512freelist. - Unvalidated Accessors: When invoking subsequent read (
EXAMINE) or write (IMPRESS/INSCRIBE) operations through the Lord, the driver follows the dangling pointer without verifying whether the underlying chunk is still an active Vassal. - Slab Hijacking & Overlap: If the kernel re-allocates that freed chunk to satisfy a request from another kernel subsystem (e.g., opening a procfs file) or for another driver structure (e.g., allocating a second Lord), the attacker gains arbitrary read and write capabilities over whatever new data occupies that memory space!
Exploitation
To transition from a primitive Use-After-Free condition in kmalloc-512 to a stable root flag extraction, we employ a 3-stage exploitation pipeline:
Stage 1: Defeating KASLR via Slab Hijacking
Because KASLR randomizes kernel memory addresses on boot, we cannot hardcode the target address of modprobe_path. We must defeat KASLR dynamically:
- Allocate
Lord AandVassal V, then bindVassal VtoLord A. - Free (
break)Vassal V, leaving a dangling pointer inLord A->vassals[0]. - Open various Linux kernel pseudo-files known to consume
512-bytestructures upon opening, specifically/proc/self/mountinfoor/proc/self/mounts(which allocate internal iteration state and file operation tables insidekmalloc-512). - Use
Lord Ato read (examine_obj) the contents of the memory pointed to byvassals[0]. - When
/proc/self/mountinfosuccessfully reuses our chunk, reading word offset0x18(bytes 24–31) yields a consistent kernel text function pointer ending in0x660(or0x2b0for/proc/self/mounts). - Subtracting the fixed static architectural offset (
0x2da660) directly revealskernel_base:
- We calculate the exact live location of
modprobe_path:
Stage 2: UAF Arbitrary Memory Write
Once we possess the absolute memory address of modprobe_path, we convert our UAF into an arbitrary write primitive:
- Allocate a new pair:
Lord AandVassal U, then bind them together. - Free (
break)Vassal U, pushing the chunk back to the head of thekmalloc-512freelist whileLord Aretains the dangling pointer. - Immediately allocate
Lord B. Because SLUB allocators operate on LIFO (Last-In-First-Out) principles,Lord Bis allocated directly inside the freed memory slot of Vassal U! - Now,
Lord A->vassals[0]points directly to the memory definingLord B. - We invoke an overwrite (
impress_obj) throughLord A->vassals[0]at byte offset0x10, replacingLord B->ptr(which normally expects a Vassal address) with the absolute memory address ofmodprobe_path(0xffffffff...). - Finally, we perform a write (
inscribe_obj) viaLord B. When the driver attempts to write data toLord B->ptr, it writes our payload string—"/home/run.sh\x00"—directly into the kernel'smodprobe_pathvariable!
Stage 3: Triggering Root Execution & Harvesting the Flag
With modprobe_path pointing to /home/run.sh, any unhandled executable type will instruct the Linux kernel to launch our script as root:
- Create a bash script at
/home/run.shcontaining: - Make
/home/run.shexecutable (chmod +x). - Create an invalid dummy binary
/home/dummycontaining bogus magic bytes (\xff\xff\xff\xff) and mark it executable. - Execute
/home/dummy. The kernel attempts to parse it, fails to recognize the ELF formatting, and immediately triggers/home/run.shwith ring-0 equivalent system privileges! - Our exploit simply opens
/home/flag_won.txt, prints the retrieved flag, and terminates cleanly.
Complete Solution Code
Static C Exploit (exploit.c)
This high-performance standalone C exploit implements all three exploitation stages:
Python Deployment Harness (exploit.py)
This script compiles the C binary statically, encodes it into small base64 chunks for safe transmission across QEMU serial console limitations, decodes it remotely, and monitors output for the captured flag:
Final Verification & Flag Capture
Running the solver against the challenge instance produces the following terminal output:
Conclusion
Heavy Is The Krown showcases how a single unchecked Use-After-Free in a custom kernel module can be escalated into a full ring‑0 compromise, even in the presence of KASLR, SMEP, SMAP, and KPTI. By turning dangling lord–vassal pointers into slab hijacking, leaking a kernel text address, and precisely overwriting modprobe_path to execute a controlled helper script, we reliably pivot from a constrained /dev/krown interface to root code execution and capture the flag.