A brief introduction to the research and bypass Linux security mechanism of PXN
In recent years, due to the rise of Android system, the Linux kernel implemented as Android bottom is becoming more and more concerned about its security problem. In order to reduce the harm and loss caused by the vulnerability, the Linux kernel adds a series of vulnerability mitigation techniques. These include DEP,ASLR, stronger selinux, kernel snippet Read only, PXN, and so on.
The increase in these security features in Linux makes it increasingly difficult for hackers to exploit vulnerabilities. Among them, Dep,aslr,selinux and other technology in the PC age has been more mature. The kernel snippet is read-only and can be bypassed by modifying scenarios such as the Ptmx_fops pointer table. So, what is PXN? And how does it get around?
PXN Introduction
PXN is actually the abbreviation of Privilegedexecute-never, which translates literally as "privileged execution never". Its opening or not is mainly controlled by the PXN bit of the Page table property, as shown in 1.
Figure 1
On Android machines without PXN security, our general approach to power-up is broadly divided into the following steps:
1. Modify the Fsync pointer address of the Ptmx_fops table so that it points to our user-state power code.
2. The application layer invokes the Fsync function, which causes the system to trigger our power code.
3. Get root permissions.
4. Set the Fsync pointer of the Ptmx_fops table to NULL, primarily to prevent other processes from calling Fsync and causing the system to crash.
The right step mentioned above is a general idea under the influence of no PXN. What about the performance on a machine with PXN? After our multi-test, the performance varies on different models. On some machines will be stuck, Shellcode will not continue to execute, some machines will produce kernel Panic, the machine directly restart.
Therefore, the general principle of PXN is that in the kernel state, the system is unable to directly execute the user-state code. As a result, our usual approach to power-up is not feasible. What's more, the latest ROM in most of the arm64 system models (such as Samsung S6, Huawei P8), and some arm32-bit models (such as Samsung Note3, Samsung S5 and other mainstream models) has been PXN by default.
Preliminary study on PXN
In a cve-2015-3636 exploit, we can finally control the value of the Sk->sk_prot->close pointer in the Inet_release function. The corresponding assembly code 2 shows.
Figure 2
The value of the X2 register in Figure 2 is the address of the Sk->sk_prot->close pointer, where the X2 corresponds to the R2 in the 32-bit system. The BLR X2 instruction is to jump to the address where X2 is pointing.
On the PXN model, if we point the address of the Sk_prot->close pointer to the user-state power code, then the system is directly panic restart, error message 3. In this panic message you can see that the value of the PC register is 0x558d15a2a8, which is a user-State address.
Figure 3
Since the PXN mechanism in the kernel state can prevent the system from running the user-state code, will it prevent kernel-level code execution? We point the address of the Sk_prot->close pointer to the return of the Inet_release function. As shown in code 4.
Figure 4
At this point, the vulnerability is triggered again, the function returns to the user state correctly, and the system is not panic, thus verifying that PXN does not prevent kernel-state code from executing. This is consistent with the principle of PXN itself.
The basic idea of the re-war PXN
Although the user-state shellcode cannot be performed on a machine with PXN, the kernel-state code can still be executed. Therefore, our strategy is to use kernel ROP: Build the kernel gadget, let the stack pointer sp leak, and then calculate the address of thread_info structure through SP, then patch thread_info structure addr_limit field, In order to achieve the user state arbitrary read and write kernel state.
Build Gadget
Next, our main goal is to verify the feasibility of the above scenario. The first task is to find the right kernel gadget.
Suppose we now have the ability to control the value of the X1 register by exploiting the vulnerability, as shown in 5.
Figure 5
Therefore, when looking for the gadget required for ROP, we control the value of other registers based on the area of memory pointed to by X1. Before triggering the vulnerability, the MMAP function is used to create a memory space that the user state can control. As shown below:
void *map_addr_tmp= mmap ((void*) 0x30303000, 0x10000,prot_write| prot_read| Prot_exec,map_shared| map_anonymous| Map_fixed,-1, 0);
Having done the preparatory work above, I will then break down the above scenario into three steps to complete:
1. Leakage of SP values;
2. Calculate the address of the addr_limit;
3.patch Addr_limit.
First, use ROP to complete the SP leak. Because the address that the register X1 points to is the memory block that we assign in the user state, and we can control it arbitrarily, so we gadget the address of each jump by X1 in the first paragraph, and then jump to the next section of gadget to start execution.
The second paragraph gadget the value of the SP stack pointer to X0, and then jumps to the next section of gadget. In this example, the user state is not able to get the SP directly through the X0. So we're going to save the value of X0 to the user state in gadget3 with a str instruction. The general idea of ROP is shown in 6.
Looking for gadget is a physical activity in some way, and of course it's possible to make a life easier with some tools, and you can Google yourself. Note that the gadget described here is just a general idea, and there may be some differences in reality.
Figure 6
Once we have the SP's value, we can calculate the address of the Addr_limit field. On the arm64 system, the maximum depth of the stack is 16K. Second, the Addr_limit field is located in the position of the THREAD_INFO structure +8. Therefore, the calculation is as follows:
unsigned long thread_info_addr = SP & 0xffffffffffffc000;
unsigned long addr_limit_addr = thread_info_addr + 8;
printf ("Addr_limit_addr:%p\n", addr_limit_addr);
Finally, we use ROP to set the value of Addr_limit to 0xFFFFFFFFFFFFFFFF. Similarly, the X1 register allows us to control its contents at will. The first paragraph gadget is used to set the individual jump addresses. The second paragraph gadget completes the main task, which is to complete the patch addr_limit with a str instruction. Finally, jump to the function where Inet_release returns. The general idea of ROP is shown in 7.
Figure 7
Once the patch for the Addr_limit field has been completed, the user state can read and write the kernel state arbitrarily. The next choice is a lot, one way is to first determine the address of the task_struct, it is in the location of thread_info+0x10. After getting the task_struct address, you can locate the Cred field, then patch UID, GID, capability, selinux and so on.
In practice, by combining known vulnerabilities, the above scheme can be tested successfully on some of the 64 flagship models released recently, as shown in 8. Of course, this idea is also applicable on 32-bit models.
Figure 8
Assuming that we are using an arbitrarily written vulnerability, the way to bypass PXN is actually similar. First, a function pointer of kernel is controlled by an arbitrarily written hole, pointing to our gadget, revealing the value of the SP. Next, you can go to patch Addr_limit directly with any written ability (no need to go through the ROP patch again).
Summarize
In recent years, with more and more research on Android and Linux, the common Linux platform vulnerability, for example: cve-2013-6282, cve-2014-3153 (Towelroot) and the latest cve-2015-3636 (Pingpong) have been unveiled.
At the same time, the latest vulnerability mitigation mechanisms used on Linux make exploitation of system vulnerabilities more difficult, but the technology that bypasses these mitigation mechanisms is also evolving. The game of attack and defense will never end.
Reference article:
Http://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit/?id=1d4d37159d013a4c54d785407dd8902f901d7bc5
Http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.architecture.reference/index.html
https://bugzilla.redhat.com/show_bug.cgi?id=1218074
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Research and bypass of PXN protection technology