In a recent Exploit of CVE-2016-8655, found and developed by Philip Pettersson, I found an interesting strategy of exploitation on Linux which is worth to be noted and written down.
About the Vul?
The vulnerability is quite straightforward, and has been explained very detailed in the original post. There is an race cond in AF_PACKET socket handling in setsockopt syscall, which will lead to an UAF in the timer_list structure (in socket structure) when closing (/releasing) the socket. The timer_list structure looks as follows, with a function filed as a callback when the timer expires.
With the UAF, overriding the function field by suitable payloads will serve the control flow hijacking.
About the Exploit
An interesting part of the exploit is that, instead of using the sendmsg to fill the UAF timer, add_key is used. With len and payload as arguments, add_key is allowed to create SLAB chunks in any length in fully controlled data.
The code of this syscall can be found in security/keys/keyctl.c . Note that in the following snippet, we can see how add_key can help to fill the UAF.
After hijacking the control flow by overriding the function field. The exploit sets the vsyscall page as r/w. The vsyscall page is a feature for x64 Linux PC distributions. A note-worthy background of it is that vsyscall page is placed at a fixed address 0xFFFFFFFFFF600000, and is accessible from both kernel and user code. By setting the page as r/w, user code can directly write the vsyscall page which is in the kernel memory space, so as to bypass SMEP/SMAP.
The rest of the exploit fakes a ctl_table structure in the vsyscall page, and triggers again the vulnerability, calling the register_sysctl_table to register sysctl entry for modprobe. The idea is to overwrite the modprobe_path global variable with the callback function in ctl_table structure. After overwriting the modprobe_path to the path of the process itself, a new socket is created to call request_module, which will start a new privileged process at the modprobe_path variable.
In conclusion, the techniques I found interesting to note down is:
1) use add_key to fill the UAF;
2) use vsyscall page to bypass SMEP/SMAP;
3) use modprobe_path to escalate the privilege.
BTW. I found a very comprehensive summery of Linux exploitation and mitigation bypass techniques by x82 at http://powerofcommunity.net/poc2016/x82.pdf