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-2026-43499-warhol-root — Exploit de escalada de privilegios local dirigido a CVE-2026-43499 para el Xiaomi 17T Pro (warhol) en Android 16 con SoC MediaTek MT6993. | Kitploit
Herramientas/GitHubGitHub/soralis0912/cve-2026-43499-warhol-root
Seguridad AndroidEscalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónExplotación de Binarios
GitHubsoralis0912/cve-2026-43499-warhol-root

CVE-2026-43499-warhol-root

Exploit de escalada de privilegios local dirigido a CVE-2026-43499 para el Xiaomi 17T Pro (warhol) en Android 16 con SoC MediaTek MT6993.

Ver Repositorio

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
11hace 25 díasAún no revisado

warhol-root

Escalada de privilegios local CVE-2026-43499 (IonStack), portada al Xiaomi 17T Pro (warhol) — MediaTek MT6993, Android 16.

Solo GKI 6.12 / android16. El overlay de waiter, el layout de la pila pselect y cada offset de struct están anclados a esa rama, así que nada de esto se transfiere a 6.6, 6.1 o 5.10 — esos necesitan una base construida para ellos. generate_target.py rechaza cualquier otro banner en lugar de emitir un header que fallaría en el dispositivo.

Estado: funcionando. Verificado en dispositivo el 2026-07-26 desde un arranque limpio, bajo ambas variantes de preloader — uid=0(root) context=u:r:kernel:s0, SELinux permisivo, su instalado. Root no es persistente: vuelve a ejecutar la línea LD_PRELOAD después de cada arranque. La carrera de pselect no es 100%: una ejecución fallida puede causar un panic en el teléfono, y reintentar después del reinicio es normal. Consulta WARHOL_PORT.md para el registro completo.

Este dispositivo necesita el fix de kernel-MTE. El popsicle upstream de serie no puede rootearlo — se queda atascado en kernel page retry N/12 para siempre. Ver Kernel MTE.

Las builds vienen en dos variantes de preloader, PRELOADER=retail (por defecto) y PRELOADER=eng. Seleccionan directorios de target distintos para que ninguna pueda sobrescribir las direcciones de la otra — ver Variante de preloader.


Dispositivo objetivo

Los datos siguientes se leyeron del paquete retail full-OTA — metadatos, el manifest del payload A/B y las imágenes boot/vendor_boot/dtbo extraídas de payload.bin.

El kernel importa más que el SoC aquí: warhol está en la misma rama GKI que el popsicle upstream (android16-5, páginas de 4K), a un patchlevel de distancia — 6.12.38 frente al 6.12.23 verificado de popsicle. Los offsets de struct todavía tienen que regenerarse por build; solo la forma del exploit se traslada. Una build distinta de OS3.0.x necesita su propio target.h.


Por qué esta base

La cadena del exploit está bloqueada por versión a la rama GKI, no al SoC. El layout del waiter de rt_mutex, el overlay de pila pselect y los offsets del struct pipe_buffer siguen todos al kernel, así que una base 6.12/android16 supera a una base del mismo vendor en una rama más antigua.

x-spy/CVE-2026-43499-popsicle es la única implementación pública verificada en la línea GKI 6.12/android16 (Xiaomi 17 / Pro / Ultra, kernel 6.12.23-android16-5), así que source/ se toma de ella y se mantiene lo más cerca posible de upstream — salvo dos líneas (ver Kernel MTE, que este dispositivo necesita para funcionar en absoluto).

La mayor parte del delta MediaTek se limita a la generación de target en tiempo de build, en dos piezas:

  • upstream lee p0_phys_offset y p0_kernel_phys_load de una partición Qualcomm xbl_config, que warhol no tiene. generate_target.py --dtb lee la base de DRAM del nodo /memory del FDT de vendor_boot en su lugar, redondeándola hacia abajo igual que hace arm64_memblock_init. La dirección física de carga del kernel se lee de la reserva mb_kernel del preloader con --preloader; el delta sale 0 para este dispositivo, y lk se niega a arrancar un kernel colocado en cualquier otro sitio.

  • MediaTek distribuye el kernel comprimido en LZ4-legacy dentro de boot.img en lugar de como un Image arm64 puro, así que el generador lo descomprime antes del análisis.

WARHOL_PORT.md §2 tiene la derivación completa.


Variante de preloader

El lk de MediaTek no carga el kernel en una constante de tiempo de compilación — busca una reserva de DRAM llamada mb_kernel y comprueba que ha caído exactamente en ella. Esa reserva la hace el preloader, razón por la cual la build de preloader que ejecuta el teléfono es una entrada de build aquí: es la única cosa fuera de boot.img que puede mover P0_KERNEL_PHYS_LOAD, y un valor incorrecto ahí significa un alias de linear-map incorrecto y un teléfono muerto en lugar de un exploit fallido.

De ahí dos variantes, mantenidas como directorios de target separados:

root@kitploit:~
make preload                  # PRELOADER=retail -> out/preload-<device>.so
make PRELOADER=eng preload    #                  -> out/preload-<device>-eng.so
make both                     # both of the above, and print their sha256

Ambos artefactos se mantienen lado a lado con nombres distintos. En este firmware salen byte-idénticos — eso es el resultado del análisis siguiente, no un atajo para evitarlo, así que los dos se siguen compilando y nombrando por separado.

Lee tú mismo las tablas de memory-layout de los dos preloaders con:

root@kitploit:~
python3 tools/preloader_memlayout.py <preloader.bin> --diff <preloader_eng.bin>

Para este firmware las dos tablas son idénticas, mb_kernel.start = 0x80000000 en ambas, así que el target.h de eng sale byte-idéntico al de retail y ambas builds producen el mismo preload.so.

Lo que realmente llega al exploit es la diferencia P0_KERNEL_PHYS_LOAD − P0_PHYS_OFFSET, y sus dos términos no se apoyan en evidencia igualmente sólida:

  • P0_KERNEL_PHYS_LOAD — medido a partir de la imagen eng, como mb_kernel.start arriba.

  • P0_PHYS_OFFSET — fue argumentado más que medido, ya que es memstart_addr, que el kernel toma del nodo /memory que lk emite en runtime a partir de lo que el preloader reporta tras el init de DRAM, no del FDT estático que lee el generador. El argumento fue que las dos builds comparten todo el camino de DRAM — mismas fuentes dramc/emi/mblock/memory_layout, sin código de memory-layout entre las cadenas exclusivas de eng — y que la única reserva extra del preloader eng, una security_fe_rsv dinámica de 3 MiB con mapping=1, no puede desplazar una entrada de dirección fija ni tallar un hueco en el fondo de la DRAM. La ejecución en el dispositivo lo zanjó: los alias de linear-map cayeron bajo eng, así que el término es correcto.

Derivación completa en targets/warhol-OS3.0.304.0.WPSJPXM-eng/NOTES.md.

Notas de la ejecución en el dispositivo:

  • El BootROM acepta este preloader eng — arrancó con normalidad hasta Android, con ro.boot.verifiedbootstate=green y flash.locked=1 sin cambios. Esa era una cuestión abierta hasta que se probó; la decide el hash de la root key en efuse, y esta build está firmada con las mismas claves que retail.

  • El preloader eng mantiene META / factory download mode vivo: %s META DIS es una cadena solo de retail, mientras que eng lleva una implementación META completa que retail no tiene (Enable fastmeta., FAST META GPIO: %d, META_COM PORT: %d, read_meta_proinfo, …). Aquí arrancó directo a Android, pero si un teléfono con eng flasheado termina en algún otro sitio, esa es la causa probable y ningún valor de target.h está implicado.

  • Si un firmware posterior mueve mb_kernel, los dos targets divergen — mantenerlos como directorios separados es lo que impide que eso pase en silencio.


Kernel MTE

Este kernel ejecuta KASAN_HW_TAGS — /proc/cmdline lleva kasan.stack_ring_size=524288 — así que los punteros de slab llevan un tag de asignación en los bits 59:56. El popsicle upstream asume punteros sin tag y por lo tanto no puede rootear este dispositivo en absoluto: se queda en bucle en [-] kernel page retry N/12 mode=1 indefinidamente, sin que el log diga nada del porqué.

Dos líneas en source/ lo arreglan, y ambas están en warhol-mte-fix.patch:

Solo las comprobaciones quitan el tag. Los punteros en sí se quedan con tag, porque el tag es el correcto para la memoria a la que apuntan — exactamente lo que necesita una desreferencia del kernel sobre ellos.

No leas arm64.memtag.bootctl para esto: esa propiedad es el control MTE de userspace y no dice nada sobre si el kernel está etiquetando sus propias asignaciones.


Upstream / referencias

Este repositorio es un port. El crédito de la cadena del exploit pertenece a upstream.


Layout

root@kitploit:~
source/          exploit core (upstream popsicle + the kernel-MTE fix; see warhol-mte-fix.patch)
  src/           main.c slide.c fops.c pipe.c util.c preload.c su_daemon.c + kernelsnitch/
targets/         per-build generated target.h, one dir per fingerprint x preloader variant
  warhol-OS3.0.304.0.WPSJPXM/       PRELOADER=retail
  warhol-OS3.0.304.0.WPSJPXM-eng/   PRELOADER=eng
tools/
  payload_dump.py          extract partitions from an A/B payload.bin (verifies size+sha256)
  kernel_banner.py         read the Linux banner out of a boot.img
  bootinfo.py              dump boot / vendor_boot header fields
  generate_target.py       target.h generator; upstream's, MediaTek-only, plus kernel decompression
  preloader_memlayout.py   dump/diff a MediaTek preloader's static DRAM reservation table
  lz4legacy.py             LZ4 legacy-frame decompressor (kernel images)
out/             build artifacts (gitignored)

Compilación

Nada se compila hasta que existe un target.h — el Makefile falla ruidosamente en lugar de emitir un binario contra el kernel equivocado.

root@kitploit:~
# 1. extract boot.img straight out of the OTA zip (payload.bin is stored uncompressed,
#    so --base seeks into the zip; no need to unpack 7.6 GB first)
python3 tools/payload_dump.py <ota.zip> --base 5081 -p boot,vendor_boot,dtbo -o <dir>

# 2. confirm the kernel banner — every offset downstream is pinned to it
python3 tools/kernel_banner.py <dir>/boot.img
python3 tools/bootinfo.py <dir>/boot.img

# 3. generate the target header. --preloader reads the kernel's physical load address
#    out of the preloader's mb_kernel reservation; pass the preloader the phone runs.
python3 tools/generate_target.py \
  --boot <dir>/boot.img --dtb <dir>/vendor_boot.img --preloader <preloader.bin> \
  -o targets/warhol-OS3.0.304.0.WPSJPXM/target.h

# 4. build
make preload            # DEVICE=warhol-OS3.0.304.0.WPSJPXM, PRELOADER=retail by default

Sin una imagen de preloader a mano, --kernel-phys-delta 0 es la forma anterior y da el mismo header para este firmware — pero es una afirmación más que una lectura, así que prefiere --preloader. Pasar ambos hace que el generador los verifique de forma cruzada y falle si no coinciden.

--base 5081 es el offset de local-header de payload.bin para este OTA en particular; léelo de ota-property-files en META-INF/com/android/metadata para cualquier otro paquete.

Requiere un Android NDK (NDK_ROOT / ANDROID_NDK_HOME) y llvm-objdump.

Ejecución

root@kitploit:~
# <device> is the target name: <fingerprint> for PRELOADER=retail, <fingerprint>-eng for eng
adb push out/preload-<device>.so /data/local/tmp/preload.so
adb shell chmod 0644 /data/local/tmp/preload.so
adb shell "LD_PRELOAD=/data/local/tmp/preload.so /system/bin/true"
adb shell "/data/local/tmp/su -c id"

cred y el estado de SELinux se parchean en memoria, así que esto hay que repetirlo después de cada arranque. No se requiere desbloqueo del bootloader.


Aviso legal

Para investigación en hardware que poseas. Ejecutar esto puede causar bootloop o brickear un dispositivo y anulará la garantía. Sin garantía de ningún tipo.

Los proyectos upstream tienen licencia de sus respectivos autores; este port conserva sus términos.

Descargar herramienta
ElementoValorFuente
Codenamewarholpre-device=warhol
Build fingerprintXiaomi/warhol_global/warhol:16/BP2A.250605.031.A3/OS3.0.304.0.WPSJPXM:user/release-keyspost-build
IncrementalOS3.0.304.0.WPSJPXM (JP global)post-build-incremental
Android16, SDK 36post-sdk-level=36
Parche de seguridad2026-05-01post-security-patch-level
Tipo de OTAA/B (payload.bin, CrAU, 39 particiones)ota-type=AB
SoCMediaTek MT6993 (Dimensity 9500)mediatek,mt6993-* compatibles en el DTB de vendor_boot; cmdline bootopt=64S3,32N2,64N2
Kernel6.12.38-android16-5-g1d46253471dd-ab15048002-4k, clang 19.0.1banner leído de la boot.img extraída
Imagen bootheader v4, kernel 18.898.125 B, comprimida en LZ4-legacy, sin ramdisktools/bootinfo.py
PRELOADER=Preloader en el teléfonoDirectorio de targetEstado
retail (por defecto)el preloader_<device>.bin de fábrica, byte-idéntico al preloader_raw.img de la ROM fastboottargets/warhol-OS3.0.304.0.WPSJPXM/✅ verificado en dispositivo el 2026-07-26
engla build de ingeniería, preloader_<device>_eng.bintargets/warhol-OS3.0.304.0.WPSJPXM-eng/✅ verificado en dispositivo el 2026-07-26
ArchivoCambioPor qué
src/util.ckernelsnitch_setup(..., mte_enabled=1)con 0, la búsqueda de mm_struct solo prueba candidatos sin tag y nunca puede encontrar un puntero con tag — un fallo estructural, no mala suerte
src/util.cis_kernel_ptr() / is_direct_ptr() quitan el tag antes de la comprobación de rangoun puntero con tag leído de memoria del kernel se rechazaría por no estar en el linear-map (direct-entry-fatal reason=bad-task-or-cpu)
src/kernelsnitch/kernelsnitch.hbarrido de tags < 15 → < 16el tag 0xf es el puntero sin tag/match-all, así que el barrido ahora cubre también un kernel sin MTE — mte_enabled=1 es seguro en cualquier caso
RepositorioRol aquí
https://github.com/MobiusM/CVE-2026-43499PoC original de CVE-2026-43499 / disparador de crash
https://github.com/x-spy/CVE-2026-43499-popsicleBase de este port. Xiaomi 17 Pro Max (popsicle), kernel 6.12.23-android16-5; source/ y tools/generate_target.py vienen de aquí
https://github.com/Kananosa/CVE-2026-43499-For-Xiaomi-17T-chagallDispositivo hermano más cercano (Xiaomi 17T, chagall, también MediaTek). Derivado de popsicle, incluye un preload.so precompilado — sus constantes compiladas confirmaron el offset de carga físico
https://github.com/MiCode/Xiaomi_Kernel_OpenSourceFuentes del kernel de Xiaomi, para verificar de forma cruzada el layout de los structs