Exploiting a Linux Kernel Infoleak to bypass Linux kASLR
Preliminary note
This has been patched here so there should be no problem talking about it: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=b2f73922d119686323f14fbbe46587f863852328
Also kASLR is not enabled yet by default on popular distribution as far as I know.
I hope that in the recent future it will become mainstream, and much stronger, both on Linux distros and Android devices, since it makes kernel exploitation likely to require also a infoleak, and the other popular mainstream OS like Windows or OS X/iOS are already adopting it, why Linux is always lagging behind?
ASLR anyway it’s not the holy grail of security, as we will see in the post, it can be bypassed even with a simple leak. You can read this post by spender on the topic and some thoughts about the limitations.
I saw several time @grsecurity mentioning a similar vulnerability on Twitter, so it was most likely very well known also by other people before me. But unfortunately, the Linux kernel community attitude towards Security is not the best one, so infoleaks are probably getting very low attention, if any.
Post
Time ago while reading on /proc filesystem for Android, the wchan
field caught my attention:
You can peek into a process wchan
value from userspace reading into /proc/pid_of_interest/stat
.
So this wchan
value will return the address of where our program is “waiting”. That’s pretty vague. What about if our process is in kernel space, will it return us a kernel address?
The answer is yes, as you can see here:
The value 18446744071579755915
it’s obviously a kernel code location since in hex is:
kASLR is not enabled by default on Ubuntu, at least 14.04, so we will have to add a “kaslr” to the kernel command line to enable it, you can find how to add stuff into the kernel command line on Google.
After we have booted the system, we can run our PoC:
How does it works?
The PoC is very simple, dirty and quick, and in python since we just need to fork and read stuff. Like we said before, in /proc/pid/stat the wchan will tell us where the code is waiting in kernel space so we can:
- Find a way to make stable this “wait” location
- Leak the ASLR’d value via the wchan
- Diff this leaked value with a known non slided value
- Output the kernel slide
For (1)
we can leverage that if we fork a process and make it sleep, we can both read his /proc/sleeping-pid/stat
and it will be a stable value, since that process will be stuck to sleep in kernel space, waiting to be rescheduled when his sleep is finished.
(2)
was already covered how to do it, it’s one of the fields in the stat at a known position.
(3)
we can get the non slid value by running the kernel without kASLR enabled on our test machine.
PoC
You will have to edit the NON_SLID_VALUE
by running the PoC on your target kernel with kASLR disabled, putting the hex value that you get in leak: 0xffffffffb70de58b
.
Final Note
Feel free to contact me if there is any error/mistake/question or suggestion. The bug nowadays since kASLR is not enabled by default was not really useful so I didn’t spend much time and efforts verifying everything and check the kernel code.
The kASLR slide seems quite weak in terms of randomization, I haven’t checked how much bits, but it’s better than nothing if we can get this on our Android devices, it’s a start. :)
Take aways:
- The Linux kernel maintainers should show a more friendly attitude to the security community, at the end we all like and use Linux, and we would both like to make it even better.