Skip to content

Kernel Exploit for CVE-2016-6187 (Local Privilege Escalation)

Notifications You must be signed in to change notification settings

Milo-D/CVE-2016-6187_LPE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CVE-2016-6187 - Linux Kernel Exploit

asciicast

Kernel Exploit for CVE-2016-6187 (Local Privilege Escalation) (affected versions: < 4.6.5)

Exploit was developed against a custom compiled 4.6 kernel + buildroot (kconfig coming soon) and defeats KASLR, SMEP, SMAP (KPTI not available for 4.6)

Vulnerability Details

The exploited vulnerability is a heap based single nullbyte overflow in one of AppArmor's LSM hooks (setprocattr). See https://nvd.nist.gov/vuln/detail/CVE-2016-6187

Exploit

Reliability

Initial measurements indicate a 94.44% chance of spawning a root shell. In 1 out of 18 cases, the exploit will oops the kernel. Further work is needed to fully stabilize the kernel after gaining root access.

Technique

We abuse the nullbyte overflow to corrupt the LSB of a freelist pointer in kmalloc-128, effectively letting it point to an already allocated object. After that, we free that allocated object, causing a double free scenario.

Now we can allocate two overlapping structures from the kmalloc-128 cache. The first structure is an object with content that can be read back by userspace. For that, I have chosen ip6_sf_socklist. The second structure, which will be allocated on top of ip6_sf_socklist should contain kernel pointers - rfkill_data is a good fit. It contains a heap pointer (empty rfkill_data.events list) and a global data pointer to rfkill_fds (rfkill_data.list.prev). Once rfkill_data is allocated on top of ip6_sf_socklist, we can retrieve the kernel pointers by calling getsockopt(sock, IPPROTO_IPV6, MCAST_MSFILTER, gsf, &optlen). The kernel text base can then be derived from rfkill_fds.

We then cause a second double free scenario, but this time we abuse the message queue's linking process to overwrite the freelist pointer and trick the allocator to return us a chunk from kmalloc-96 when we actually request a chunk from kmalloc-128.

We can then leverage the size mismatch to overflow into the freelist pointer of a kmalloc-96 chunk, giving us the primitive to allocate arbitrary addresses. In our case, we go for the ptmx_fops structure and overwrite the ptmx_fops.unlocked_ioctl callback with a pointer to our stack pivot gadget.

Calling ioctl on /dev/ptmx triggers the pivot gadget and we pivot the stack to a fake stack in kmalloc-128 where we already prepared our first stage rop chain.

Since we have limited space on the kmalloc-128 fake stack (we don't know if the next chunk will be on the same slab), the task of the first stage rop chain is to copy the second stage rop chain from userspace into the kernel dmesg log buffer (__log_buf) and to pivot the stack to __log_buf.

The second stage rop chain then tries to repair the kernel (restoring ptmx_fops, ...) before it calls commit_creds(prepare_kernel_cred(NULL)) to escalate privileges.

And finally it exits the kernelspace via iretq and we return, with elevated privileges, to our execve("/bin/sh", 0, 0) subroutine.

Requirements

/dev/rfkill

Unprivileged users must be able to at least open /dev/rfkill. Some distros might not permit that. I have checked Ubuntu and Fedora, both allow unprivileged users to open /dev/rfkill (although Fedora is using SELinux instead of AppArmor)

Reproducing the Exploit

The following section explains how to reproduce the local privilege escalation in qemu-x86_64.

First, you will have to obtain an initrd and bzImage kernel. There are two ways:

Method 1: Prebuilt

The easiest and quickest way. You can find all the required components in prebuilt/.

Method 2: DIY

Or, alternatively, you could also build the components yourself. Simply fetch the 4.6 kernel and use the provided x86_64_vuln_kern_defconfig in config/ to compile the bzImage.

For the initrd you could, for example, use buildroot. Just make sure to set the correct permissions for /dev/rfkill in your init

chmod 664 /dev/rfkill

This is the same as in Ubuntu-16.04 and many other distros. Also do not forget to compile the exploit and put it into your initrd

make

Dropping a root shell

Once you have obtained the components, boot the vulnerable machine

./boot.sh <path/to/bzImage> <path/to/rootfs.cpio>

and execute the exploit

./exploit

You may need to run the exploit several times, depending on whether we have nulled out a LSB that was already zero. Also note, that there is still a slight chance (maybe 10%-20%?) of crashing after gaining root access - I am working on it.

Have fun.

TODO's

  • repair ptmx_fops to increase stability
  • repair kmalloc-128 freelist to increase stability
  • repair message queue to increase stability
  • automatically restart exploit when detecting failure
  • add proper writeup
  • publish kconfig, build instructions, ...
  • code refactoring/cleanup

About

Kernel Exploit for CVE-2016-6187 (Local Privilege Escalation)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages