cve-2015-3636

Source: Internet
Author: User
Tags root access cve

This year, it has become increasingly difficult to find a generic root exploit vulnerability on an Android system, on the one hand because of the serious fragmentation of the Android system and the ongoing introduction of vulnerability buffering mechanisms on Android systems. In this article I will give you a brief account of the cve-2015-3636 of the loophole of the POC and exploit. In fact, to stabilize and effectively use such a loophole is not an easy thing, we step by step to see.

0. Vulnerability Overview:

The vulnerability is a Linux kernel-level use-after-free vulnerability that exists in the ping.c file of the Linux kernel. When a user tries to invoke a socket file descriptor that is returned by a socket (AF_INET,SOCK_DGRAM,IPPROTO_ICMP) two times a sa_family==af_ Unspec Connect () will cause system crash because of access to the 0x200200 address. In addition, if an attacker cleverly fills in or overwrites a ping socket object, it can achieve root access. And, it is because the vulnerability exists in the basic part of the Android system Linux kernel, so that the vulnerability can be used in general use of the possibility.

1. Vulnerability Analysis &POC

The flaw was discovered and tried to exploit by keen team Wen Xu and Wu Shi, which has now been patched with the CVE number: cve-2015-3636.

We analyze the vulnerability from a patch of vulnerability:


We can see from the patch source, the inside added Sk_nulls_node_init (sk->nulls_node), such a sentence code. So good, take this sentence as an entry point, combined with the POC concept mentioned in the previous overview to analyze the vulnerability principle.

By exploring the specific implementation of the Sk_nulls_node_init (Hlist_nulls_node *node) function in the kernel code, it is found that the function is to assign NULL to the next member and the Pprev member of the node passed in by the parameter.


In the overview we talked about using the socket file descriptor returned by the socket (AF_INET,SOCK_DGRAM,IPPROTO_ICMP) to call two times a sa_family==af_ Unspec Connect () will cause system crash because of access to the 0x200200 address. Next we follow the code execution process.

The first call to connect with Sa_family==af_unspec enters into the Inet_dgram_connect () function,

We can see from the patch source, the inside added Sk_nulls_node_init (sk->nulls_node), such a sentence code. So good, take this sentence as an entry point, combined with the POC concept mentioned in the previous overview to analyze the vulnerability principle.

By exploring the specific implementation of the Sk_nulls_node_init (Hlist_nulls_node *n) function in the kernel code, it is found that this function is actually the Hlist_null_ of the parameters passed in. The next member and the Pprev member of node are assigned null.

In the overview we talked about using the socket file descriptor returned by the socket (AF_INET,SOCK_DGRAM,IPPROTO_ICMP) to call two times a sa_family==af_ Unspec Connect () will cause system crash because of access to the 0x200200 address. Next we follow the code execution process.

The first call to connect using Sa_family==af_unspec enters into the Inet_dgram_connect () function, which we can see because Sa_family==af_unspec causes the program to execute the red box

Logic, and the Sk->sk_prot->disconnect (sk,flags) function is eventually called in this statement, Sk_prot is a member of the SK object, pointing to a pointer table that contains a pointer to the number function. The specifics of where these functions are performed depend on the protocol type, which includes TCP, UDP, and so on. So the Sk->sk_prot_disconnect (Sk,flag) statement is ultimately the function called the Udp_disconnect (struct sock *sk,int flag):

>

And in the case that the socket object does not bind the port, the Sk->sk_prot->unhash (SK) statement is executed, and we find the corresponding function: Ping_unhash (struct sock* sk)


At this point, we see that the program logic into the location of the vulnerability, after analysis of our focus on the 41 and 42 lines of the two code, 41 sentence is actually the SK object in its corresponding kernel hlist deleted. Specific implementations we can look at:


In fact, the Hlist_nulls_node type node corresponding to the linked list is deleted, and the N-node forward to the two-level pointer Pprev assigned to the value of List_poison2, further we search the kernel source of this macro discovery, its corresponding value is 0x200200.

The first time you call sin_family== Af_unspec Connect, the program produces no exceptions, just to make the Pprev value of the corresponding node member of the sock object's SK be assigned 0x200200.

The second call to sin_family== Af_unspec Connect is the hope that the real triggering of the vulnerability of the system crash. Because when the second invocation of the program logic according to the previous process to walk to 42 lines of code will delete the corresponding node again, and when executed to *pprev=next this sentence will cause the system crash. This is because *pprev=next this statement is actually the first node after the deletion operation List_poison2 this pointer dereference, let it be next, and in the kernel, this list_poison2 address is not accessible, so it will cause the system crash.

In fact, there is a little bit of a problem here, to clarify, after the second attempt to call is not as we imagined crash, this is because to enter the IF (sk_hashed ()) logic must be called in two times sin_family== Af_unspec Connect () uses Sin_family==af_inet to invoke connect () First, so that the SK object is hashed in the kernel (which is actually added to the kernel hlist).

In summary, the complete POC (or this should actually be called the Vulnerability Detection code) is as follows:

#include <unistd.h> #include <sys/socket.h> #include <errno.h> #include <linux/netlink.h># Include <linux/if.h> #include <linux/filter.h> #include <linux/if_pppox.h> #include <linux/sock_ diag.h> #include <linux/inet_diag.h> #include <linux/unix_diag.h> #include <string.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #include <jni.h> #define Mmap_base 0x200000 #define List_poison 0x200200#define mmap_size 0x200000int checkisvulnerable () {void * magic = MMAP (void *) Mmap_base, Mmap_size, Prot_read | Prot_write, map_shared | map_fixed |    Map_anonymous,-1, 0);//0x20000 to 0x40000 This virtual memory address mapping, and all values in this address segment are set to 0 memset (magic, 0, mmap_size); * ((long *) (List_poison)) = 0xfefefefe;//to 0x200200 This virtual memory address is assigned a value of 0xfefefefe; int sock = socket (af_inet, SOCK_DGRAM, Ipproto    _ICMP);    struct sockaddr_in sa;    memset (&sa, 0, sizeof (SA));    sa.sin_family = af_inet; Connect (sock, const struct SOCKADDR *) &sa, sizeof (SA));//The first time with af_inet sin_family to connect is to let SK (Sock object) in the kernel hashed sa.sin_family = Af_unspec;     Connect (sock, (const struct sockaddr *) &sa, sizeof (SA)); /* Each call to connect with AF_UNSPEC triggers the Sk->sk_prot->disconnect () logic in Inet_dgram_connect () where the specific implementation of disconnect is determined by the protocol type, The specific implementation of the PING (ICMP) socket disconnect () is a udp_disconnect () unbound port that triggers the Sk->sk_prot->unhash (SK) Logic */Connect (sock,       const struct SOCKADDR *) &sa, sizeof (SA));//If the vulnerability exists, the second call will trigger the vulnerability if (* ((LONG *) (List_poison)) = 0xfefefefe) {       printf ("Device is vulnerable\n");    return 1;      }else{printf ("Device is not vulnerable\n");    return 0; }}
2. Exploit:


We said earlier that this is a use-after-free loophole, but in the POC we don't see where the use-after-free is going. Let's take a closer look at the code where the vulnerability exists:


Let's take a look at line 42 sock_put (SK), what exactly does this code do:


In fact, the sock object is the SK reference count to reduce one operation, and determine whether its value is 0, if it is 0, the memory of the SK object is released. It also means that when we call sin_family== Af_unspec Connect for the second time, we go into the sock_put (struct Sock*sk) function in the If logic and release the memory of the SK object. However, this SK object is created in the user space, its file descriptor is also in the user space in our control, and use free to tell the kernel to release the memory of this object, but does not erase the memory of the data, this is a typical use-after-free vulnerability.

To get root access through this vulnerability we have to accomplish the following goals:

1. Overwrite the contents of the Use-after-free ping sock object;

2. In the user space to use the already free ping sock object, try to get the ability to execute code in the kernel in some way;

3. Having the ability to invoke kernel code in the user state, you can modify the corresponding process permissions and elevate to the root privilege.


Take a first step, with our controllable data to cover Use-after-free Ping sock object, that is re-filling operation, is also the most difficult and most critical, related to exploit can be stable and effective operation success,

We know that the current heap management mechanism used by the Linux kernel is to allocate kernel objects using the Slub/slab allocator, different sizes of kernel objects correspond to different slabs, in which case we want to do something like

Using kernel objects of type A to populate kernel objects of type B is almost impossible in a multi-process Linux kernel because there are too many factors affecting the memory layout that can easily be affected by other processes.

Finally, a good choice is to use PHYSMAP (the direct mapping area of the internal nuclear physics), Physmap is a piece of kernel space in order to improve the performance of the area set, which allows the direct mapping of user space address to the kernel space. And in the kernel space Physmap area and ping sock slabs one at the higher address, one at the lower address, through lifting may produce overlap.


We see that after a certain number of lifting operations, overlapping areas of our user space mapping are the ping sock objects that we can use, located at relatively high addresses in kernel space. We populate the mapped user-space area with the same data so that we can later determine if we have a ping sock object we have control of, and decide whether to stop lifting, we will make this data magic value.

After judging that we have a ping sock object that we can control, we stop lifting and release the Ping sock object created during the lifting, preserving only the object handles that we have already controlled.

Let's start by looking at what the value of our magic value is:


As you can see, the space in which we map through Mmap is populated with a value of 8 bytes, where the first four bytes fill the current address, and the next four bytes populate a 32-bit value that we define.

This is because we judge by the IOCTL (Sockfd,siocgstampns, struct timespec*) This system call when judging whether or not the overlap has occurred:


What is the execution result of this function, through the source code we can analyze, in fact, this function is the SOCKFD corresponding socket object in the Sk_stamp member of the value of the return to the user space, and the value of this member is the timestamp when the object was created.

Just think, when lifting a certain number of times, now our hands of the control of the Ping sock object in fact, we have been filled with the previous 8-byte magic value, call this function will return a 8-byte timestamp value, and this value corresponding to the first four bytes is Sk_ Stamp the address in the Ping sock object, and the latter four bytes are used to determine the correctness of the returned result.

Once we have determined that there is already a controllable ping sock object in the Mmap mapped area, we stop lifting and release the useless ping sock object.

At this point we have finished the work of covering, that is, the first step is finished.


After getting a ping sock object that is controllable by the user space, it is easy for us to analyze the contents of the Ping sock object to control the value of the PC register in the kernel context.

First look at the structure of the Ping sock object:



As we can see, a ping sock object corresponds to a struct pointer called Sk_prot, which holds a series of function pointers, and the data in the whole object is controllable, and the function pointers are stored

Address we can calculate according to its offset in the Ping sock object, so now a PC register in the kernel context is what we can control. For example, we can use the simple close (SOCKFD) to control the flow to the function address we want. However, this can only be a jump from kernel space to user-space functions. (since the kernel can jump to both user space and kernel space, but we have no way to know the address of a function in the kernel, what we most want to know is the commit_creds,prepare_kernel_cred address, Because the traditional shellcode is directly through the kernel of these two symbolic addresses. )

So what can we do to achieve the purpose of elevation to root?

One of the methods used here is to use the method of leaking kernel stack top pointer sp to overwrite the Addr_limit value de-limit, and calculate the address of thread_info based on SP, and then calculate task_struct address according to Thread_info, because Task_ The struct structure holds all the information of the current process, including the permissions, and then resolves the corresponding permission-related members according to the structure of the task_struct, and modifies the value that the root permission process should have:


At this point, we have completed the purpose of using cve-2015-3636 for root power.

The results are as follows:



cve-2015-3636

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.