/ 3 min de lectura

RCE en V8 de una Samsung TV #2: por qué SDB fue un callejón

Hay R/W arbitrario sobre el proceso del navegador (post anterior). Suena a que ya está, pero para armar la cadena ROP falta lo más importante de todo: los offsets de libchrome.so. Esos offsets son las posiciones exactas, dentro de la librería, de las dos cosas que la cadena necesita: los gadgets (los pedacitos de código que ya existen en el .text) y el slot del GOT que apunta a mprotect. Con esos offsets más la dirección donde la librería quedó cargada en memoria se puede calcular la dirección real de cada pieza y recién ahí construir la cadena. Y para sacarlos hace falta el binario en una laptop, donde correr ROPgadget y análisis de símbolos offline.

El camino obvio, el que cualquiera intentaría primero: bajarlo por SDB, el Samsung Smart Development Bridge, el adb de Tizen. No se pudo, y el porqué dice mucho de contra qué se está jugando.

La idea obvia (que no funcionó)

Se bajó el SDB oficial (v4.2.36) del SDK de Tizen Studio y se conectó contra la TV:

/tmp/sdb_pkg/data/tools/sdb connect 192.168.100.76 # 192.168.100.76 = IP de la TV en mi LAN

La IP estaba whitelisteada en el modo desarrollador de la TV, así que la conexión se estableció sin problemas: el device aparecía prolijo en sdb devices. Hasta ahí, todo ilusión.

Dónde se choca

Porque a partir de ese punto, todo lo realmente útil está bloqueado:

sdb shell <cmd> -> conecta pero NO devuelve stdout
sdb root on -> "Permission denied"
sdb pull /usr/... -> "You cannot pull files from this path"

La causa es SMACK (Simplified Mandatory Access Control), el LSM que Tizen usa en firmware de producción. El daemon de SDB corre con una etiqueta SMACK que no tiene acceso a las rutas del sistema donde vive libchrome.so, y sin root (denegado) no hay forma de re-etiquetar ni de leer esos paths. El detalle importa, porque es la clave: no es un tema de permisos UNIX clásicos. Aunque se fuera root-equivalente, la política SMACK corta igual.

En un device de desarrollo (o con firmware engineering) SDB daría shell y pull sin chistar. En una TV de producción, extraer el binario por SDB es un callejón sin salida.

La consecuencia estratégica

Y acá está el punto que define todo el resto de la investigación. Sin el binario en disco no se puede portar la cadena ROP por análisis estático. La puerta de afuera está cerrada con llave. Pero ya hay acceso desde adentro:

Si no se puede sacar el .so desde afuera, se lee desde adentro: localizar libchrome.so en la memoria del propio render process y dumpearlo con read32().

Eso convierte el problema en uno puramente in-process, y reordena toda la serie en una lista de tareas concretas:

  1. Encontrar el ELF base de libchrome.so en memoria.
  2. Leer sus program headers para conocer tamaño y segmentos.
  3. Volcar [elf_base, elf_base + image_size) por chunks al server.py.
  4. Correr el análisis offline sobre ese dump.

El paso 1, encontrar el ELF base, resultó ser el verdadero problema difícil de todo el writeup, y es donde arranca la entrada 03: cómo conseguir, desde JavaScript, un puntero que caiga sí o sí adentro del mapeo de libchrome.so.