RetSpill: Igniting User-Controlled Data to Burn Away Linux Kernel Protections



tải về 0.65 Mb.
Chế độ xem pdf
trang2/10
Chuyển đổi dữ liệu15.12.2023
Kích0.65 Mb.
#56016
1   2   3   4   5   6   7   8   9   10
retspill


§


CR-Pinning
run_cmd [24]
CFHP+codebase leak+heap info leak+rdi control
kernel heap




-
pivot to heap [19]
CFHP+codebase leak+heap info leak+register control
kernel heap



-
KEPLER [70]
CFHP+codebase leak+physmap leak+register control
physmap



-
set_memory_x [15]
CFHP+codebase leak+heap info leak+rdi&rsi control
kernel heap

§


-
RetSpill
CFHP+codebase leak
kernel stack



-
Table 1: With the development of modern protections in the Linux kernel, exploiting CFH vulnerabilities requires many
primitives and becomes brittle. Our work, RetSpill, is a powerful exploitation technique that requires fewer primitives and yet
is still reliable. * Given all the required primitives, whether the technique can derive the target primitive without failures.

ret2dir is reliable only if given a page frame info leak primitive.
§
need to obtain CFHP twice.

run_cmd function can get
inlined, thus not exist, in some kernel builds.
stack gr
owth
pt_regs
stack frames
pt_regs
random
padding
stack frames
stack
bottom
Normal Stack
Randomized Stack
Figure 1: Kernel Stack Layout With and Without RAND-
KSTACK Protection
CFH vulnerabilities has become difficult. In a modern Linux kernel,
obtaining CFHP does not imply the ability to obtain root or even
carry out Return-Oriented-Programming (ROP) or arbitrary code
execution because of modern kernel hardening techniques.
Most protections aim to prevent attackers from accessing user
space data improperly. SMEP [47] and KPTI [64] prohibit executing
user space code from kernel space. SMAP [12] disallows the kernel
from reading/writing user space data directly. NX-physmap [31]
marks the physmap region as not executable. These protections limit
attackers’ capability to turn CFHP into arbitrary code execution.
Other protections were designed to limit attackers’ capabilities
despite limited code execution: CR Pinning [63] prevents unautho-
rized modification to the CR4 register (which contains bits to en-
able certain mitigations), thus preventing attackers from disabling
mitigations. STATIC_USERMODE_HELPER [35] prohibit abusing “user
mode helpers” to perform privilege escalation. RKP [56] disallows
directly modifying process credentials. pt-rand [14] invalidates
the technique of directly modifying kernel page tables.
Notably, RANDKSTACK [53] is a protection that aims to randomize
kernel stack layout, preventing attackers from exploiting use-of-
uninitialized-variable vulnerabilities. Its change to kernel stack
layout is shown in Figure 1. Similar to their use in user space ap-
plications, STACK CANARY mitigates stack-overflow vulnerabilities,
removing the possibility of overwriting the return address (and
higher memory addresses) to achieve ROP.
Bypassing exploitation protections.
Because of strong stack
protections, most modern CFHPs happen as a result of kernel heap
misuse. Typically, an attacker overwrites (e.g., via heap overflow)
a function pointer in a victim object in the heap. The attacker
then invokes a trigger system call that calls the overwritten func-
tion pointer and obtains CFHP. As direct shellcode execution is no
longer viable (due to NX-physmap and SMEP), and stack control is
elusive (due to the use of stack canaries and death of stack overflow
vulnerabilities), a typical CFH exploit needs to combine the CFHP
with other primitives, such as a heap address disclosure, to obtain
stack control and start an ROP chain [13, 19, 29, 46] as shown in
Table 1.
Imperfect bypass: “pivot to heap”.
Anecdotally, we observed
that most modern kernel exploits use heap-related vulnerabilities
and must prepare and trigger attack payloads on the heap. For
example, all 15 public kCTF CFHP exploits pivot to a fake stack in
the heap to achieve ROP. This has drawbacks: it does not support
rewriting payloads directly because the payload is in the kernel
heap, a region users do not have direct access. In other words, to
execute a different payload, the attacker needs to swap the heap
object containing the payload or even trigger the vulnerability
again, which significantly reduces reliability for exploits that need
to trigger different payloads to achieve privilege escalation [21, 33].
Additionally, these exploits rely on either specific kernel memory
layouts, the existence of precise bespoke gadgets, or additional
primitives (such as register control). As shown in Table 1, “pivot to
heap” requires more primitives than RetSpill, which significantly
increases the difficulty of developing exploits.
Kernel ROP.
Kernel ROP, similar to that in user space, grants
attackers the ability to perform arbitrary execution by chaining
ROP gadgets together. Compared to user space ROP, kernel ROP
has two additional requirements. First, leaked information in the
ROP chain needs to be transferred back to user space. This can be
done by using the fact that registers are not cleared during CPU
privilege transition [38]. Attackers can load the leaked information
into a register, perform a privilege transition back to user space,
and obtain the leaked value. Second, ROP chains in kernel space
need to end gracefully to avoid panic. Currently, there are three
existing ways to achieve this: 1. return back to user space, such as
using KPTI trampoline [38]; 2. sleep indefinitely [74], which freezes
the current task; 3. kill the current task by invoking do_task_dead
function.


Kernel Stack and System Calls.
In the Linux kernel, each
task has its own kernel space stack to facilitate the execution of
system calls invoked from user space. The kernel stack is allocated
as a fixed-size buffer at the creation of each kernel task [61]. The
kernel stack layout is shown in Figure 1. When the user space
invokes a system call, the program counter will switch to kernel
space functions and the stack pointer will be set to the kernel stack.
Then, the kernel will push the user space context, including all
user space registers, onto the bottom of the stack, and invoke the
corresponding system call handler. The saved user space context
is named pt_regs. When returning back to user space, the kernel
will restore the user space context and resume the execution of the
user space program.
Due to the fixed-sized nature of the kernel stack, developers
usually store large chunks of data in dynamically allocated mem-
ory regions (e.g., heap) to avoid stack exhaustion. However, for
performance considerations, some performance-critical system
calls [66, 67] still store large amounts of data on the kernel stack.
3
THREAT MODEL
In our threat model, the target Linux kernel has all the protections
as the model in Kepler [70], in addition to Function-Granular Kernel
Address Space Layout Randomization (FG-KASLR) [34], which is a
cutting-edge kernel hardening technique implemented recently.
Specifically, we allow the target Linux kernel enabling SMEP,
SMAP
, KPTI, NX-physmap, CR Pinning, STATIC_USERMODE_HELPER,
RKP
, pt-rand, RANDKSTACK, STACK CANARY, and FG-KASLR.
In terms of exploitation primitives, our model requires two primi-
tives: control-flow hijacking and kernel image base address leakage.
Both primitives are reasonable and can be achieved through a rea-
sonable number of Linux vulnerabilities (Table 4). Our required
primitives are fewer than all existing work (Table 1), as well as
many latest real-world kernel exploitation techniques such as those
published through Google kCTF [23].
4
EXPLOITATION TECHNIQUE DESIGN
A modern CFH exploit has two steps: 1) injecting user-controlled
data into kernel memory, and 2) using this controlled data for
ROP. Modern protections prevent attackers from directly accessing
user space data, leaving physmap and kernel heap the only known
choices for storing user-controlled ROP chains. The difficulty of
accessing these two regions induces the requirement of additional
exploitation primitives (such as register control or additional ad-
dress disclosures) onto modern CFH exploits.
Our proposed technique, RetSpill, is based on the insight that
potentially attacker-controlled user data is loaded, by design, onto
the kernel stack during system calls. When PC-control is obtained,
which happens inside the triggering system call after the attacker
sets up the conditions for the Control Flow Hijacking Primitive
(CFHP), the attacker can use this controlled user data readily on
the kernel stack to launch code reuse attacks (e.g., ROP).
However, this is not enough for full exploits: the individual re-
sulting ROP attacks are limited, and our study of 22 kernel vulnera-
bilities (§7.1) shows that some triggering system calls have as few as
seven controllable gadgets for ROP payload. This leads to RetSpill’s
other contribution: because stack layouts of functions are fixed
during compilation, attackers can repeatedly invoke the triggering
system call unlimited times to trigger different ROP payloads.
With this, RetSpill can obtain unlimited arbitrary read/write/exec
in kernel space, thus completely breaking the security boundary
between user and kernel space despite the presence of modern
kernel protections. This is more severe than existing “single-shot”
exploitation techniques [70]: as shown in §7.3, RetSpill can bypass
more protections than existing techniques.
4.1
Data Spillage
Attacker-controlled user space data can spill onto the kernel stack
either directly or indirectly.
Direct Data Spillage refers to the situation where user data is
loaded directly onto the kernel stack in one system call. The poll
system call shown in Listing 1 performs direct data spillage when
it uses copy_from_user to copy user space data onto the kernel
stack directly.
Indirect Data Spillage happens when data is loaded onto the ker-
nel stack through multiple system calls. For example, with carefully
crafted arguments, a call to the open system call stores data from
user space to the kernel heap, and a subsequent call to readlink
loads this controlled data to the kernel stack.
In this work, we mainly focus on systematically analyzing direct
data spillage. We first investigate how user space data can flow into
kernel space during system calls. We identify two methods: 1) user
space registers and 2) user space memory. More specifically, when
a user space program invokes a system call, its general-purpose
registers contain data that can potentially flow into kernel space.
During the lifetime of a system call, the kernel may need additional
information from user space memory to complete the system call,
which leads to userspace data flowing into kernel space.
To comprehensively discover direct user data spillage causes, we
perform taint analysis on user space data (both user space registers
and memory) and observe the traces on kernel stack in triggering
system calls to identify data spillage causes as detailed in §6.2. By
manually analyzing the taint analysis results, we identify three
causes of direct user data spillage.
Depending on where user data is temporarily stored, there are
potentially many variants of indirect data spillage methods. In this
work, we empirically identify one general case of indirect data
spillage where user data is temporarily stored on the kernel stack
and shared across system calls because of uninitialized memory.
We leave the systematic study of indirect data spillage as future
work.
4.2
Data Spillage Sources
We identified four data spillage sources as follows:
Valid Data.
In a Linux kernel, user space data is sometimes
directly copied onto the kernel stack for performance reasons. Take
the simplified poll system call handler in Listing 1 as an example. It
copies a considerable amount (0x1e0 bytes in our build) of user space
data into stack_pps, which is on the kernel stack. If an attacker
controls a file object in user space, when CFHP is obtained through
the file->f_op->poll call, they will have control of 0x1e0 bytes
on the kernel stack. The attacker can then use an add rsp, X; ret


1

tải về 0.65 Mb.

Chia sẻ với bạn bè của bạn:
1   2   3   4   5   6   7   8   9   10




Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2024
được sử dụng cho việc quản lý

    Quê hương