Skip to content

Latest commit

 

History

History

CVE-2014-3153

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
-----------------------------[CVE-2014-3153]-----------------------------------
-------------------------------------------------------------------------------

CVE-2014-3153 is one of the most known CVEs in the Linux kernel.
It was exposed in May 2014 .
It was extensively used to root Android devices < 2014.
Towelroot is an exploit that "works" using this CVE, but it's closed source and
yet obfuscated against reverse engineering as it was compiled using 
llvm-obfuscator.


CVE Details Description:
The futex_requeue function in kernel/futex.c in the Linux kernel through 3.14.5
does not ensure that calls have two different futex addresses, which allows local 
users to gain privileges via a crafted FUTEX_REQUEUE command that facilitates unsafe 
waiter modification.

From the description above we can tell that this CVE is about:

1 - Futexes - futex system call.
2 - FUTEX_REQUEUE is the vulnerable command.
3 - waiter modifications is our target.


First futex() is a system of synchoronization between threads or processes kind 
of mutexes but here the majority of the synchronization operations are perform-
ed in user-space. We need the help of the kernel only in one case when the thr-
ead is believed to hang for a very long time that userspace can't handle it, so 
it wait in the kernel.

futex() is a system call without a wrappers (cs it's rarely used I guess
only pthread use it internaly).

The bug:
Vulnerability researchers found that if you execute these sequence of steps one
after the other a kernel crash will occur:

1 - FUTEX_LOCK_PI
2 - FUTEX_WAIT_REQUEUE_PI
3 - FUTEX_CMP_REQUEUE_PI
4 - "Make PI futex = 0"
5 - FUTEX_CMP_REQUEUE_PI

I tested it and it crashed my kernel, and I knew this bug is exploitable so I
wanted to see why it crashed.

The vulnerability:
The vulnerability is that you can create a thread waiting on a futex, requeue 
it to another one (using the 5 steps above) like that you will be having its 
waiter (struct rt_mutex_waiter rt_waiter) linked but out of scope (it can be
changed in the stack).


The interesting struct here is this (we can corrupt it):

futex_wait_requeue_pi() will let this important struct in the stack but still 
linked.

struct rt_mutex_waiter {
	struct plist_node	list_entry;
	struct plist_node	pi_list_entry;
	struct task_struct	*task;
	struct rt_mutex		*lock;
#ifdef CONFIG_DEBUG_RT_MUTEXES
	unsigned long		ip;
	struct pid		*deadlock_task_pid;
	struct rt_mutex		*deadlock_lock;
#endif
};

The first two elements are interesting pointers that we can use to achieve
(Write kernel pointer Where) and that would result in an exploitable condition.

Everytime we lock the PI futex a new waiter will be added to the doubly linked
list, and with corrupted pointers we can put kernel pointers in critical places
that can lead to LPE.

If you can corrupt the rt_mutex->list_entry->node_list->next and then add another
waiter, it will be interpreted like this : 
*(rt_mutex->list_entry->node_list->next) = waiter <- kernel address

The rt_waiter is in the stack, so what syscall should we use to corrupt it
with the data we want?

We will be using this script that comes with the linux source tree.

$ objdump -d vmlinux | ./scripts/checkstack.pl i386 | grep -E "(futex_wait_requeue_pi|sys)"

0xc1092524 do_sys_poll [vmlinux]:			928
0xc10925dd do_sys_poll [vmlinux]:			928
0xc10929a8 do_sys_poll [vmlinux]:			928
0xc1091fc4 core_sys_select [vmlinux]:			288
0xc109209a core_sys_select [vmlinux]:			288
0xc111cc58 ___sys_sendmsg [vmlinux]:			244
0xc111cd88 ___sys_sendmsg [vmlinux]:			244
0xc111d5ea ___sys_recvmsg [vmlinux]:			216
0xc111d722 ___sys_recvmsg [vmlinux]:			216
0xc111e51b __sys_sendmmsg [vmlinux]:			184
0xc111e5c9 __sys_sendmmsg [vmlinux]:			184
0xc111e5e4 __sys_sendmmsg [vmlinux]:			184
0xc104d474 futex_wait_requeue_pi.constprop.27 [vmlinux]:180
0xc104d5a8 futex_wait_requeue_pi.constprop.27 [vmlinux]:180
0xc10096b1 syscall_trace_leave [vmlinux]:		128
0xc1009705 syscall_trace_leave [vmlinux]:		128

From the output we know that we can use __sys_sendmmsg and __sys_recvmsg
All the exploits that I've seen are using __sys_sendmmsg and I tried it at first
but it didn't work for me for some reason that I don't know. I was 0x30 away from
the struct.
__sys_recvmsg did the trick for me.

So now we know that we can write a kernel address where.
What to do with this primitive.

First we need the leaks, to get the leaks all you have to do is corrupt the next
pointer with a userland address and link a waiter and you will be having a kernel
stack address in a userland address (we can do it because SMAP isn't present).

Now we have a kernel stack address what to do with it?
We can reveal thread_info which is in the stack, and from that we know the address
of addr_limit. Now all left to do is corrupt addr_limit (write kernel address where)
and now we're in the situation of addr_limit > &addr_limit.

Now we can read and write to and from the kernel.

We will be reading pointers like this:

thread_info -> task_struct -> group_leader -> cred

And because we can write to kernel addresses we will patch *ID to 0 and pop a shell.

This was a really short wu, I can't even call it a wu, but I'm not leaving
you here, here are some of the interesting wus I found, especially the one
from elongl, I liked it a lot.

Links:
https://elongl.github.io/exploitation/2021/01/08/cve-2014-3153.html
https://tinyhack.com/2014/07/07/exploiting-the-futex-bug-and-uncovering-towelroot/
https://www.programmersought.com/article/95265451595/
https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part4.html
https://elixir.bootlin.com/linux/v3.11.4/source/kernel/futex.c#L2643