- A single bitflip in the kernel RW memory is allowed.
- Extract kallsyms.
- Attach with gdb, put a
breakpoint on
bprm_fill_uid
. - Run
/bin/iconv
, dumpbprm->file->f_path.dentry->d_inode
. Since the challenge uses initramfs,CONFIG_SMP
is disabled andnokaslr
is specified, the inode addresses are extremely stable. - Flip
inode->i_mode ^= S_ISUID
, run/bin/iconv /root/flag
. - Other possibilities, that were tried, but didn't work:
- Setting the setuid bit on
busybox
. While this works, busybox drops privileges on startup. - Creating a lot of small flag reading binaries (spraying) and randomly
flipping
inode->i_mode ^= S_ISUID
on one of them. While this works, it's not possible to create aroot
-owned binary, so the setuid bit obtained this way is useless. - Flipping a bit in IDT with the goal to have an interrupt handler in
userspace. Not possible, since the canonical kernel addresses start with
ffff
and the canonical userspace addresses start with0000
. - Flipping a bit in
user_addr_max()
with the goal of confusingcopy_from_user()
/copy_to_user()
. Not possible for the same reason. - Flipping a bit in a global function pointer, which is normally
NULL
, with the goal to have it point to userspace. No such pointers were located. - Flipping a bit in a global length variable bound to a
/proc
or/sys
file (e.g./sys/kernel/boot_params/data
), with the goal of dumping all memory using that file (since initramfs is used, the flag is in the kernel memory). Unfortunately all such variables are either copied to the heap during initialization or are marked as__ro_after_init
(gj, Kees! xD). - Flipping a bit in a page table. This is the correct solution, but one has to look into the physmap. I looked only into the kernel text, and there a single bit flip was not enough.
- Setting the setuid bit on