Thursday, November 21, 2019

Bad Binder: Android In-The-Wild Exploit

Posted by Maddie Stone, Project Zero

Introduction
On October 3, 2019, we disclosed issue 1942 (CVE-2019-2215), which is a use-after-free in Binder in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android kernel. The bug is a local privilege escalation vulnerability that allows for a full compromise of a vulnerable device. If chained with a browser renderer exploit, this bug could fully compromise a device through a malicious website.

We reported this bug under a 7-day disclosure deadline racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 normal 90-day disclosure deadline. We made this decision based on credible evidence that an exploit for this vulnerability exists in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild and that it's highly likely that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit was being actively used against users.

In May 2019, Project Zero published a blog post and spreadsheet for tracking “in-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-wild” 0-day exploits. In July 2019, I joined Project Zero to focus on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of 0-day exploits in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild. We expect our approach to this work will change and mature as we gain more experience with studying 0-days, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mission stays cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same: to “make zero-day hard”. 

So far cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are a few key approaches that we have started with:
  • Hunt for bugs based on rumors/leads that a 0-day is currently in use. We will use our bug hunting expertise to find and patch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug, rendering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit benign.
  • Perform variant analysis on 0-days used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild. When looking for bugs, you often find more than one of a similar type at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same time. However, an exploit usually uses one instance of a possible pattern or variant. If we can find and resolve all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 similar variant bugs, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effort involved in creating a new exploit will be higher.
  • Complete detailed analysis of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 0-days from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point of view of bug hunters and exploit developers and share it back with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 community. Transparency and collaboration are key. We want to share detailed root cause analysis to inform developers and defenders on how to prevent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se types of bugs in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 future and improve detection. We hope that by publishing details about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit and its methodology, this can inform threat intelligence and incident responders. Overall, we want to make information that’s often kept in silos accessible to all. 

This is just cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 starting point of how we’re thinking about tactical work around 0-day exploits used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild, but we won’t make much progress if we try to do this alone. Whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r you’re a vendor, defender, researcher, journalist, threat analyst, policy specialist, victims’ advocate, or someone else, we all have a role we can play to make it hard to exploit 0-days in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild. Please feel free to reach out to me to explore how we may be able to work togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r.

The rest of this post is to drive this conversation forward by sharing one instance of such work: CVE-2019-2215. This blog post will explain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 methodology for finding it, how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 proof-of-concept exploit we released works, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 evidence and commentary on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of this bug for in-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-wild exploitation.

Hunting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bug

In late summer 2019, Google’s Threat Analysis Group (TAG), Android Security, and Project Zero team received information suggesting that NSO had a 0-day exploit for Android that was part of an attack chain that installed Pegasus spyware on target devices. We received details about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 marketed “capability”. These details included facts about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug and exploit methodology, including:
  • It is a kernel privilege escalation using a use-after-free vulnerability, reachable from inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Chrome sandbox.
  • It works on Pixel 1 and 2, but not Pixel 3 and 3a. 
  • It was patched in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel >= 4.14 without a CVE. 
  • CONFIG_DEBUG_LIST breaks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitive.
  • CONFIG_ARM64_UAO hinders exploitation.
  • The vulnerability is exploitable in Chrome's renderer processes under Android's isolated_app SELinux domain.
  • The exploit requires little or no per-device customization.
  • A list of affected and unaffected devices and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir versions, and more. A non-exhaustive list is available in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 description of issue 1942.

Each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se facts gave us important information to scope down cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential bug that we were looking for.
  • “It is a kernel privilege escalation using a use-after-free vulnerability, accessible from inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Chrome sandbox.”
We know that it’s a use-after-free in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel.

  • "It works on Pixel 1 and 2, but not Pixel 3 and 3a."
We can diff cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Pixel 2 and Pixel 3 kernels looking for changes.

  • "It was patched in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel >= 4.14 without a CVE."
The Pixel 3 is based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel 4.9 and doesn’t include cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fix is not in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 4.9 Linux kernel, only 4.14.

  • "CONFIG_DEBUG_LIST breaks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitive."
This was an extremely helpful tip. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are only two actions (three functions) whose behavior changes based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CONFIG_DEBUG_LIST flag: adding (__list_add) and deleting (__list_del_entry and list_del) from a doubly linked list. Therefore, we could infer that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed obj is a linked list and has an add or delete performed on it after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 free occurs.

  • "CONFIG_ARM64_UAO hinders exploitation."
Likely means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit is using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory corruption to overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address limit that is stored near cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 start of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct. (It would normally be stored at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bottom of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack on Linux <=4.9, but Android backported cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 change that moved it into task_struct to protect against stack overflows to older kernels.)

  • The exploit requires little or no per-device customization.
We can assume cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug and its exploitation methodology are in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 common kernel racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than in code that is often customized, like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 framework.

  • "A list of affected and unaffected devices and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir versions."
Whenever cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was a candidate bug that seemed to fit all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requirements above, I cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n vetted it against cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list of affected and unaffected devices.

Based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se details, I began combing through changelogs and patches looking for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential bug. Finding CVE-2019-2215 actually occured on my second attempt. I had originally thought cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential bug was a different issue, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n ruled it out based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information above.

A few weeks after my first attempt at tracking down this bug, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs recommended that I should look at Binder. Looking back, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 detail that states “The vulnerability is exploitable in Chrome's renderer processes under Android's isolated_app SELinux domain.” should have caused me to look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Binder driver first, but it didn’t.

When I diffed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Pixel 2 and Pixel 3 drivers/android/binder.c files and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir changelogs, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re were only a few significant changes. Commit 550c01d0e051461437d6e9d72f573759e7bc5047 stood out in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 log because:
  1. It discusses fixing a  “use-after-free” in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 commit message,
  2. It is a patch from upstream, and
  3. The upstream patch was only applied to 4.14.

I cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n began to evaluate this bug against cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r requirements of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 leads and found that it matched cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m perfectly. I also looked through every ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r change to Binder (~25) between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Pixel 2 and Pixel 3, and no ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r changes matched every detail.

We wrote a proof-of-concept of our own that demonstrates how this bug can be exploited. 

The Original Discovery of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bug 

This bug was originally found and reported in November 2017 and patched in February 2018. Syzbot, a syzkaller system that continuously fuzzes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel, originally reported cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free bug to Linux kernel mailing lists and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 syzkaller-bugs mailing list in November 2017. From this report, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug was patched in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux 4.14, Android 3.18, Android 4.4, and Android 4.9 kernels in February 2018. However, this fix was never included in an Android monthly security bulletin and thus cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug was never patched in many already released devices, such as Pixel and Pixel 2.

Android provided cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following statement on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original discovery of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug.

"Android was informed of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security implications of this bug by Project Zero on September 26, 2019. Android partners were notified of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug and provided updates to address it within 24 hours. Android also assigned CVE-2019-2215 to explicitly indicate that it represents a security vulnerability as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original report from syzkaller and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding Linux 4.14 patch did not highlight any security implications. 

Pixel 3 and 3a were already protected against cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se issues. Updates for affected Pixel devices were available to users as early as October 7th, 2019.”

Technical Details of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bug

The bug is a use-after-free (UAF) in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Binder driver. The binder_thread struct, defined in drivers/android/binder.c, has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 member wait of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait_queue_head_t struct type. wait is still referenced by a pointer in epoll, even after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct containing it is freed.

struct binder_thread {
        struct binder_proc *proc;
        struct rb_node rb_node;
        struct list_head waiting_thread_node;
        int pid;
        int looper;              /* only modified by this thread */
        bool looper_need_return; /* can be written by ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r thread */
        struct binder_transaction *transaction_stack;
        struct list_head todo;
        bool process_todo;
        struct binder_error return_error;
        struct binder_error reply_error;
        wait_queue_head_t wait;
        struct binder_stats stats;
        atomic_t tmp_ref;
        bool is_dead;
        struct task_struct *task;
};

struct __wait_queue_head {
        spinlock_t              lock;
        struct list_head        task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

The BINDER_THREAD_EXIT ioctl calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread_release function which frees cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct. However, if epoll is called on this thread, binder_poll tells epoll to use wait, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait queue that is embedded in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct. Therefore, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct is freed, epoll is pointing to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 now freed wait queue. Normally, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait queue used for polling on a file is guaranteed to be alive until cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file’s release handler is called. Rare cases require cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of POLLFREE. In contrast, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Binder driver only worked if you constantly removed and re-added cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 epoll watch. This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying bug and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free is a symptom of that.

When we look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack trace from KASAN in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original report, we can see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free is in remove_wait_queue in kernel/sched/wait.c. The source code for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 remove_wait_queue is below. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 remove_wait_queue function, q is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed wait_queue_head_t in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct and wait is an entry in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait queue whose head has been freed. The use-after-free that triggered cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KASAN crash is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call to spin_lock_irqsave with argument &q->lock when q is pointing to freed memory.

However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 __remove_wait_queue call is more interesting for exploitation. As shown below, __remove_wait_queue simply calls list_del on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_list in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait queue, giving us an unlinking primitive.

void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
        unsigned long flags;
        spin_lock_irqsave(&q->lock, flags);
        __remove_wait_queue(q, wait);
        spin_unlock_irqrestore(&q->lock, flags);
}

__remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
{
        list_del(&old->task_list);
}

The bug can be triggered with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code, which was also in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original report from syzkaller.

#include
#include
#include
#include

#define BINDER_THREAD_EXIT 0x40046208ul

int main()
{
        int fd, epfd;
        struct epoll_event event = { .events = EPOLLIN };
                
        fd = open("/dev/binder", O_RDONLY);
        epfd = epoll_create(1000);
        epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
        ioctl(fd, BINDER_THREAD_EXIT, NULL);
}

I verified that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Pixel 2, running Android 10 with SPL September 2019, still included this bug. The KASAN output is included in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue tracker.

Exploiting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Use-After-Free

After confirming cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug and reporting to Android, I began working with fellow team member, Jann Horn, to write a proof-of-concept (PoC) exploit. The PoC we published on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue tracker in comment #7 used cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF described above to gain arbitrary kernel read and write from an unprivileged application context. In this section, I will explain how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC exploit that we wrote works. This section describes how we decided to exploit this bug and not necessarily how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 in-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-wild exploit works.

This exploit triggers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF twice in order to overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address limit to obtain arbitrary kernel read and write privileges. The first use of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF leaks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct, which contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process’s address limit (addr_limit). The second use of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF overwrites cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of addr_limit. The addr_limit value defines which address range may be accessed when dereferencing userspace pointers. Usercopy operations only access addresses below cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit. Therefore, by raising cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit by overwriting it, we will make kernel memory accessible to our unprivileged process.

To trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF, we use vectored (scatter/gacá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r) I/O in a somewhat similar way to what DiShen presented in his talk from Code Blue 2017, “The Art of Exploiting Unconventional Use-after-free Bugs in Android Kernel” [video].

Triggering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF

To exploit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF bug, we reallocate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed binder_thread memory as an I/O vector and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unlinking primitive to gain scoped kernel read to leak cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct address. We trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF again for scoped kernel write to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit. This section describes how we use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial read and write.

About Vectored I/O

Vectored I/O is also known as scatter/gacá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r I/O. Vectored reads move data from a data source (here a file) into a set of disparate buffers (scatter), moving onto cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next after each buffer is filled. A vectored write moves data from a set of buffers into a data sink (here a file) (gacá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r). readv and writev are syscalls for performing vectored I/O. Their definitions from fs/read_write.c are below. 

SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)

SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)

The vec arguments are arrays of iovec structs where each iovec struct describes a buffer. The iovec struct definition from include/uapi/linux/uio.h is below.

struct iovec
{
        void __user *iov_base; 
        __kernel_size_t iov_len; 
};

We use writev to leak cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first time we trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF. In addition to readv and writev, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 recvmsg syscall for receiving a message from a socket also uses vectored I/O. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 msghdr, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second argument to recvmsg, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a member named msg_iov that points to an array of iovec structs. We use recvmsg cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second time we trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF to overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit

Using vectored I/O for UAF write and read

We use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vectored I/O to gain UAF read (leaking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct address) and UAF write (overwriting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct). Vectored I/O operations (like readv, writev, and recvmsg) import cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user-space I/O vector array into kernel space and verify that all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vector elements are in userspace in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call to rw_copy_check_uvector. If rw_copy_check_uvector returns successfully, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec array is now in kernel space and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re will not be anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r verification on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer values in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iov_base fields. This means that while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 I/O is blocking, we can overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer pointers in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec array using our UAF read/write and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n read from or write to a place in kernel memory. 

The iovec struct is of size 16 bytes and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct is 408 bytes. Therefore, we will create an array of 25 iovec structs in order to make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec array a similar size to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed struct. The kernel allocates memory based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocations so if we can control a struct of almost cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same size as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed memory, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a good chance that our controlled struct will be allocated into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same place. The iovec array is 8 bytes smaller than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread in order to not overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct pointer value at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct, but that is still close enough to be allocated into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same slab, and thus cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same position in kernel memory as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed binder_thread struct. 

When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec array is allocated into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same memory as our freed binder_thread struct, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 struct members will line up as below.

binder_thread struct

iovec array
0x00

0x00: iovec[0].iov_base
...

0x08: iovec[0].iov_len
...

...
0xA0: wait.lock

0xA0: iovec[10].iov_base
0xA8: wait.task_list.next

0xA8: iovec[10].iov_len
0xB0: wait.task_list.prev

0xB0: iovec[11].iov_base
...

...

Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vectored I/O has copied our iovec structs into kernel memory, we cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n want cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 I/O operation to block so that ep_remove_wait_queue can run from a separate thread. When ep_remove_wait_queue runs, it will perform a list_del operation on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values at offsets 0xA8 and 0xB0 in our diagram since ep_remove_wait_queue still believes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se memory values to be a part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait_queue_head_t struct. 

ep_remove_wait_queue calls remove_wait_queue that calls __remove_wait_queue that calls list_del

static inline void __list_del(struct list_head * prev, struct list_head * next)
{
        next->prev = prev;
        WRITE_ONCE(prev->next, next);
}

#ifndef CONFIG_DEBUG_LIST
...
static inline void list_del(struct list_head *entry)
{
        __list_del(entry->prev, entry->next);
        entry->next = LIST_POISON1;
        entry->prev = LIST_POISON2;
}

The UAF exploitation technique described in this blog post is not successful when CONFIG_DEBUG_LIST is enabled because list_del is implemented differently when it’s enabled. The implementation when CONFIG_DEBUG_LIST is NOT enabled is shown above.

The debug implementation, shown below, is found in lib/list_debug.c. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug version, list_del calls __list_del_entry which includes checks to ensure that prev->next == entry && next->prev == entry. If any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se checks fail, BUG_ON will be called and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process will die (and on Android devices, which usually set kernel.panic_on_oops=1, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire device will reboot). This check is what prevents this exploitation method from working when CONFIG_DEBUG_LIST is enabled.

void __list_del_entry(struct list_head *entry)
{
        struct list_head *prev, *next;

        prev = entry->prev;
        next = entry->next;

        if (WARN(next == LIST_POISON1,
                "list_del corruption, %p->next is LIST_POISON1 (%p)\n",
                entry, LIST_POISON1) ||
            WARN(prev == LIST_POISON2,
                "list_del corruption, %p->prev is LIST_POISON2 (%p)\n",
                entry, LIST_POISON2) ||
            WARN(prev->next != entry,
                "list_del corruption. prev->next should be %p, "
                "but was %p\n", entry, prev->next) ||
            WARN(next->prev != entry,
                "list_del corruption. next->prev should be %p, "
                "but was %p\n", entry, next->prev)) {
                BUG_ON(PANIC_CORRUPTION);
                return;
        }

        __list_del(prev, next);
}
EXPORT_SYMBOL(__list_del_entry);

/**
 * list_del - deletes entry from list.
 * @entry: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 element to delete from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list.
 * Note: list_empty on entry does not return true after this, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entry is
 * in an undefined state.
 */
void list_del(struct list_head *entry)
{
        __list_del_entry(entry);
        entry->next = LIST_POISON1;
        entry->prev = LIST_POISON2;
}

The entry being passed to list_del is an entry in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait queue list. The freed wait_queue_head_t struct contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list head of which this entry is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only member. Prior to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list_del operation, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list looks like in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 diagram below.



After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list_del cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operation looks like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 diagram below. The list head prev and next pointers have been set to point to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list head. This means that iov_base has been overwritten with a kernel address and we can now perform scoped read and write operations from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel space beginning at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list head. 


Leaking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct pointer

We follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process outlined above to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free to leak cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task structure pointer. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel, and thus in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android kernel, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct includes most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 important information about a process. In this case, we want to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct because it includes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process’s address limit. 

The code to leak cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct pointer is in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function leak_task_struct in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC. The function starts by adding cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder file descriptor (fd) to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 epoll’s interest list. We cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n create an array of 25 iovec structs. Next, we set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values of each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec entries. For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first 10 entries, we set both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iov_base and iov_len to 0 so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel skips cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m when processing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vector. iovec[10].iov_base is set to a value that will look like an unlocked spinlock. iovec[10].iov_len is set to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same size as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe such that when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe will block after moving all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents from iovec[10].iov_base into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe. Once it unblocks, it will begin on iovec[11].

binder_thread struct

iovec array
0x00

0x00: iovec[0].iov_base
0x00000000 00000000
...

0x08: iovec[0].iov_len
0x00000000 00000000
...

...
0xA0: wait.lock

0xA0: iovec[10].iov_base
dummy_page_4g_aligned
0xA8: wait.task_list.next

0xA8: iovec[10].iov_len
0x1000
0xB0: wait.task_list.prev

0xB0: iovec[11].iov_base
0xDEADBEEF
...

0xB8: iovec[11].iov_len
0x1000
...

...

We set iovec[10].iov_base to dummy_page_4g_aligned because we need cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lower-half of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address value to be 0 for it to pass as a spinlock. In remove_wait_queue, we need spin_lock_irqsave to run successfully so that __remove_wait_queue is called.

For this to be successful, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call to remove_wait_queue from within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EPOLL_CTL_DEL execution must occur after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec array has been copied to kernel memory by rw_copy_check_uvector (called by writev) and iovec[10] has been processed (since its length will be clobbered by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF write), but before writev begins reading from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address at iovec[11].iov_base

Therefore, we need cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 writev call to block prior to trying to write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec[11] contents to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe. To do this, we fill cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole pipe with contents that we don’t care about. Because we completely fill cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe, writev will block until something begins to read from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe. Therefore, we set iovec[10].iov_base to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se filler contents and we set its length to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same size as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe size. writev will put all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dummy contents into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe and block, giving us time to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of iovec[11].iov_base with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unlinking primitive in remove_wait_queue. After remove_wait_queue finishes, we can read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dummy contents from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe, unblocking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 write. The now-unblocked writev will begin reading from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address in iovec[11].iov_base, which has now been changed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list head address, binder_thread + 0xa8, in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel.



Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 writev finishes, we read from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pipe. The value at offset 0xE8 is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct pointer. (The wait queue list head is at 0xa8 in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binder_thread struct and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct pointer is at 0x190.)

Overwriting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Address Limit

Now that we have saved off cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task_struct pointer, we trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAF again in order to overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address limit (at task_struct + 0x08), this time using recvmsg instead of writev. The process through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list_del is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iov_base ends up pointing to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list_head of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait_queue. At this point, though, instead of reading from that address, we begin to write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values below. 

  unsigned long second_write_chunk[] = {
    1, /* iov_len */ (already used) */
    0xdeadbeef, /* iov_base (already used) */
    0x8 + 2 * 0x10, /* iov_len (already used) */
    current_ptr + 0x8, /* next iov_base (addr_limit) */
    8, /* next iov_len (sizeof(addr_limit)) */
    0xfffffffffffffffe /* value to write - new addr_limit */
  };

To understand how this overwrites cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit, we need to remember how scatter I/O works: we will read from a unix domain socket to disparate buffers, filling up one before moving to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next. After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list_del, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scatter I/O is about to begin on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer at iovec[11].iov_base. The value at iovec[11].iov_base now points to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list head of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wait queue after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list_del operation. The first 5 values we are going to overwrite are our iovec structs. We originally set iovec[11].iov_len to 0x28 which means we write 0x28 bytes before moving to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer stored in iovec[12].iov_base. We want to overwrite iovec[12].iov_base to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit so that we can overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address limit without having to overwrite everything between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list head and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address limit. This is why we set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iovec[11] buffer to 0x28 bytes: 0x8 bytes each for iovec[10].iov_len, iovec[11].iov_base, iovec[11].iov_len, iovec[12].iov_base, and iovec[12].iovec_len. Then we move to write through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 newly-overwritten address in iovec[12].iov_base. This writes 0xFFFFFFFFFFFFFFFE (one less than KERNEL_DS to bypass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 segment_eq(get_fs(), KERNEL_DS) branch in iov_iter_init()) to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addr_limit, now making all memory (including kernel memory) accessible as part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user-space memory range in our process and thus granting arbitrary kernel read and write. 

Values after list_del operation, prior to recvmsg

Values after recvmsg
0x00

0x00
...

...
0xA8: iovec[10].iov_len 
+0xA8 (points to itself)
list head
←            →
0xA8: iovec[10].iov_len
1
0xB0: iovec[11].iov_base
+0xA8 (points to previous element)

0xB0: iovec[11].iov_base
0xDEADBEEF
0xB8: iovec[11].iov_len
0x28

0xB8: iovec[11].iov_len
0x28
0xC0: iovec[12].iov_base
0xBEEFDEAD

0xC0: iovec[12].iov_base
task_struct + 0x8
0xC8: iovec[12].iov_len
0x8

0xC8: iovec[12].iov_len
0x8





task_struct + 0x8 (addr_limit): 0xFFFFFFFFFFFFFFFE

In-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-Wild Analysis

As stated in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 introduction, we deemed that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was enough credible evidence that CVE-2019-2215 was being used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild to support a 7-day disclosure deadline. This credible evidence included cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 leads and details outlined above in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “Hunting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bug” section, and how after a detailed review of kernel patches, all requirements perfectly aligned with one bug (and only one bug). The examined information included marketing materials for this exploit, and that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit was used to install a version of Pegasus. With this evidence, we decided that although we did not have an exploit sample, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 risk to users was too great to wait 90 days for a patch and disclosure, and thus reported this to Android under a 7-day deadline.

The 7-day deadline exists because “each day an actively exploited vulnerability remains undisclosed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 public and unpatched, more devices or accounts will be compromised.” Therefore, we decided that this vulnerability required disclosure to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 public as soon as possible.

Variant Analysis

I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most important “variant” that we can take away from this bug is that bugs are often patches in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 upstream Linux and/or Android kernels that are not flagged as security bugs (though have security impact), so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are not included in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android Security Bulletin and thus do not get patched in released devices. Sorting through Linux patches is a huge undertaking, so instead, one approach to address this issue could be addressed by regularly syncing with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 upstream stable kernels. 

In addition, we also looked for ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r variants where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 poll handler uses wait queues that are not tied to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lifetime of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file and no issues of similar significance have been discovered so far.

Conclusion

CVE-2019-2215 permits attackers to fully compromise a device with only untrusted app access or a browser renderer exploit and despite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch being available in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 upstream Linux kernel, it was left unpatched in Android devices for almost 2 years. In that time, we believe that attackers have been able to use this vulnerability to exploit users in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild. Given cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information in various public documents about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 services that NSO Group provides, it seems most likely that this vulnerability was chained with eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a browser renderer exploit or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r remote capability.

Kernel vulnerabilities in Android are especially dangerous because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are largely cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same across different devices, whereas ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r components on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device, such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 framework, SOC, or pre-installed apps, are often customized from one device to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r and across different manufactures. With this single kernel vulnerability, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 majority of Android devices manufactured prior to September 2018 were vulnerable. The patch gapping between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LTS Linux kernel, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android common kernel, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernels running on end-users’ devices leaves a ripe surface area for exploitation. To prevent issues like this, Android could force all devices to sync to both upstream Linux and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android common kernel at a regular cadence.

We publicly disclosed CVE-2019-2215 on October 3, 2019, 7-days after reporting to Android due to credible evidence of in-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-wild exploitation. We made this determination based on documents marketing and detailing an Android exploit “capability”. Our view is that it's often reasonable to infer that a vulnerability is being exploited in-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-wild from ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r forms of contextual information (such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 marketing materials seen in this case, combined with a deep analysis of patches) and that a binary/sample isn’t always required. Therefore, each day we waited to disclose meant anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r day that at-risk users were exposed to harm. 

On October 6, 2019, Android added updates to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 October Android Security Bulletin and addressed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue. Devices showing a security patch level on or after Oct 6, 2019 should be patched against CVE-2019-2215.

This bug highlights that in order to “make zero-day hard”, we need to work to learn as much as we can from 0-days used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild AND share it back with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 community so that we can all work togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r to make this kind of exploitation that much harder. Please reach out and let’s collaborate!

tl;dr

  1. Leads, even without samples, can help us find bugs and get security vulnerabilities patched. 
  2. The patch gap between released devices and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel leaves a ripe area for exploitation. The kernel is a key layer in Android’s security model.
  3. Project Zero is ramping up its in-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-wild 0day analysis work, and we're very open to collaboration. Please reach out!