Keen Lab • Android Kernel vulnerability hunting and exploitation since 2014 • Aim: to work out universal rooting exploit for Android • Trophy: • CVE-2016-6787 & CVE-2017-0403 (kernel/events/core.c) • CVE-2015-1805 (fs/pipe.c) ’s first working exploit • CVE-2015-4421,4422 (Huawei TrustZone) • KNOX Bypassing on Samsung Galaxy S7 (BHUSA 17’) • Exploiting Wireless Extension for all common Wi-Fi chipsets (BHEU 16’) • And more To Be Announced in the future • Available on https://github.com/retme7/My-Slides
socket (refilled) ops->ioctl(…) JOP gadgets • Free the victim object • Refill the object with malformed data by heap spraying or ret2dir • Let the function pointer point to ROP/JOP gadgets in kernel • Ask kernel reference this function pointer to achieve arbitrary kernel code execution ioctl(sockfd,…) kernel_sock_ioctl() JOP gadgets
that idealized • More unconventional situation to deal with… • The victim object may don’t have a function pointer • The kernel may crash soon after UAF triggered • The attacker may cannot fully controlled the freed object
all devices shipped with 3.10 or earlier Linux kernel • More than 14 million users of KingRoot gain root privilege on their smart phones • CVE-2016-6787 • Ever affected all Qualcomm-based devices. (Only Qucalcomm enabled hardware perf event…) • A part of my exploit chain to bypass Samsung KNOX 2.6
A description of what kind of performance event you need • Input: group_fd (optional) • Specify the group leader of new perf_event • Return the fd of perf_event to user space
performance event which is registered by user • perf_event_context • The container of all perf events created in one process • Each process has two contexts, one for software events, other one for hardware events • Perf group and group leader • Multiple events can form a group • One event is the leader perf_sw_context perf_hw_context task_struct event event event event_list event (group_leader) event (group_leader)
install it to hardware context Remove every event from software context, and then install it to new hardware context ’move_group‘ leads to reducing context’s refcont by one
due to race condition • Attacker trigger the move_group on same group leader simultaneously, • The ref count of group_leader->ctx may be reduced to zero • task_struct->perf_event_ctxp[perf_sw_context] will be freed accidently The object is freed
from me • Switch the status of attacker’s thread from running to (un)interruptible • The thread will be frozen and kernel won’t crash as soon as perf_event_context freed
hardware perf_event Main thread Sub thread-1 Sub thread-2 move_group, put_ctx() move_group, put_ctx() kfree_rcu(perf_event_context) futex_wait_queue_me() Phase 1 Phase 2 Spraying the heap by using ‘ret2dir’ trick, fill a malformed perf_event_context{} in every 1024 bytes Use futex_wake() wake up main thread Phase 4 schedule() finish_task_switch() perf_event_context_sched_in() ctx->pmu->pmu_disable() Phase 3
race, and trigger the bug • Hard to refill the freed object (no time) • Easy to control the code flow (corrupted object has function pointer) • Proposed an approach to freezing thread to gain more time to refill object
Group leader has a sibling_list • sibling_list is a list of perf events which belongs this group perf_sw_context perf_hw_context task_struct event event event event_list event (group_leader) event (group_leader)
buffers through pipe • Use an array of struct iovec{iov_base,iov_len} to describe user buffers • When no contents available from the write end, readv() may block in kernel • Then an array of struct iovec{} may stay in kernel’s heap
iov_base must points to userland space. • An array of struct iovec{} now is in heap. Nothing comes from the write end of pipe, so readv() block. • If you can somehow overwrite the iovec{}, modify the iov_base to a kernel address. Emmm… iov_base iov_len iov_base iov_len iov_base iov_len ….. kernel_addr iov_len kernel_addr iov_len kernel_addr iov_len
↓ the 1st freed object, address is A Solution: convert UAF to arbitrary R/W ↓the 2nd freed object, address is B = A + 0x400 Use iovec to spray the heap Freed Data Freed Data Freed Freed Data Freed Data ········· base len base len base base len base len ········· ·········· base len A + 0x20 A+0x20 base ·········· base len base len Write a buffer to pipe ,the buffer will be copied to (A + 0x20) ········· base len KADDR 8 KADDR ·········· KADDR 8 KADDR 8 ········· Write a buffer to pipe again,it will be copied to KADDR KADDR can be any address value, we achieved arbitrary kernel memory overwriting 1 2 3 4 5
descriptor of freed object • Cannot achieve code execution via refilling object’s function pointer • Only be able to write the address value of freed object twice to freed object • Proposed a new approach: compromising pipe system
may be another way • No idea? Put it down for a while, but do not let it go… • Be familiar with kernel’s source code, kernel’s own feature may help your exploitation (e.g. pipe for CVE- 2017-0403)