
Cadena de explotación completa para Chromium en Android que combina la fuga de información CVE-2026-11057 y el use-after-free CVE-2026-5281 para lograr el secuestro de la vtable y la ejecución arbitraria de código.
Pixel 7 Android 16 ARM64
commit 994c846bbd7a35241ba7c08158c13d66412a6993 (HEAD -> 146.0.7680.111, tag: 146.0.7680.111)
Author: Roger McFarlane <[email protected]>
Date: Mon Mar 9 12:48:07 2026 -0700
Este repositorio combina CVE-2026-11057 (memoria de imagen de glifo no inicializada en Skia) y CVE-2026-5281 (use-after-free de DeviceInfo en el servidor wire de Dawn) en una cadena completa. Todas las modificaciones son del lado del renderer; el código del proceso GPU no se modifica:
Fuga de información (CVE-2026-11057) — Activar un búfer de imagen de glifo no inicializado mediante el renderizado de texto en canvas, leer punteros del heap del proceso GPU, validarlos con ejecuciones aritméticas, derivar la base del pool de PartitionAlloc y calcular el objetivo falso de Server M = POOL + 0x202A08000 (offset calibrado).
Rocío de CC — createBuffer(label="CCM:<m>:<n>") provoca la inyección de 3000 ChunkedCommands incompletos (bucket de 10KB, remainingSize=1, mantenidos vivos en mChunkedCommands del servidor wire). El payload llena la región alrededor de M con un Server falso dispuesto para Android arm64: vptr de MutexProtected en +0xB20, ChunkedCommandSerializer en +0xB50/+0xB58, CommandSerializer/vtable falsos en +0xC00/+0xD00.
Disparo de 5281 + ocupación — queue.writeBuffer(buffer, 0x414141, ...) primero llama a Unregister(Device) para liberar el DeviceInfo de 16 bytes, luego inyecta un ChunkedCommand de ocupación de 16 bytes para reclamar esa ranura y sobrescribir info->server con M, y finalmente provoca un error de validación con un offset fuera de límites.
Callback colgante → secuestro de vtable — El callback de error no capturado desreferencia info->server = M (Server falso): los mutexes puestos a cero pasan, la ejecución llega a OnUncapturedError → SerializeCommand, y la llamada indirecta relativa a la vtable alcanza nuestra vtable falsa, dando pc = fake_vtable + offset int32 controlado, demostrado con pc = 0x7641414141.
Nota: Chromium para Android arm64 usa vtables relativas (
-fexperimental-relative-c++-abi-vtables); las entradas de la vtable son offsets relativos de 32 bits en lugar de punteros de función absolutos, por lo que el PoC usa un offset int32 controlado como marcador en el punto de secuestro de la vtable.
En el dispositivo de prueba, la cadena completa alcanza el crash por secuestro de vtable con una tasa de éxito de casi el 100%; la etapa de fuga puede requerir ocasionalmente varias recargas automáticas antes de tener éxito.
SkStrike.cpp.patch — Disparador de fuga de CVE-2026-11057. FlattenGlyphsByType() reescribe el payload del strike para que el proceso GPU cree un SkGlyph con fImage == nullptr, leyendo finalmente un búfer de imagen no inicializado para filtrar punteros del heap.Device.cpp.patch — Rocío de CC del cliente wire de Dawn. APICreateBuffer() analiza la etiqueta CCM:, construye el payload del Server falso para Android arm64 e inyecta N ChunkedCommands incompletos que permanecen vivos en el proceso GPU.ApiProcs.cpp.patch — Disparo de CVE-2026-5281 + ocupación. En el offset mágico 0x414141 de QueueWriteBuffer, llama a Unregister(Device) para liberar DeviceInfo, inyecta un ChunkedCommand de 16 bytes para reclamar la ranura y establecer info->server = M, y luego continúa con un offset fuera de límites para disparar el callback colgante.exploit.html — Orquestación de la página: primitiva de fuga (groom/draw/readCell/verifyRuns/derivePoolBase), rocío de CC y un disparador independiente exploit5281(); en caso de fallo, limpia el estado del rocío y recarga para que las etapas no interfieran.Este ExP solo se divulga hasta el paso de secuestro de vtable (objetivo de llamada indirecta controlado, pc = base+0x41414141). Los pasos a partir del salto controlado, así como la implementación de RCE, se mantienen confidenciales y no se incluyen en este repositorio.
Mi exploit difiere del enfoque del reportero original en un aspecto clave. El exploit original se logró modificando el código fuente de PartitionAlloc en el proceso GPU para deshabilitar la aleatorización de direcciones. Este enfoque solo es adecuado para fines de prueba de concepto. En cambio, mi exploit combina una vulnerabilidad de divulgación de información para eludir la aleatorización de direcciones, lo que permite un exploit totalmente funcional que funciona en entornos del mundo real.
# Set build arguments here. See `gn help buildargs`.
is_official_build = true
is_debug = false
symbol_level = 0
v8_symbol_level = 0
blink_symbol_level = 0
is_component_build = false
proprietary_codecs = true
ffmpeg_branding = "Chrome"
dcheck_always_on =false
optimize_webui = true
android_static_analysis = "off"
target_os = "android"
target_cpu = "arm64"
# Disable PartitionAllocEventuallyZeroFreedMemory
disable_fieldtrial_testing_config = true
treat_warnings_as_errors = false
adb logcat | grep DEBUG en el PC