Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-43499-warhol-root — Exploit d'élévation locale de privilèges ciblant CVE-2026-43499 pour le Xiaomi 17T Pro (warhol) sous Android 16 avec le SoC MediaTek MT6993. | Kitploit
Outils/GitHubGitHub/soralis0912/cve-2026-43499-warhol-root
Sécurité AndroidEscalade de PrivilègesAnalyse des VulnérabilitésExploitationExploitation de Binaires
GitHubsoralis0912/cve-2026-43499-warhol-root

CVE-2026-43499-warhol-root

Exploit d'élévation locale de privilèges ciblant CVE-2026-43499 pour le Xiaomi 17T Pro (warhol) sous Android 16 avec le SoC MediaTek MT6993.

Voir le dépôt

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
11il y a 25 joursPas encore vérifié

warhol-root

CVE-2026-43499 (IonStack) — élévation de privilèges locale, portée sur le Xiaomi 17T Pro (warhol) — MediaTek MT6993, Android 16.

GKI 6.12 / android16 uniquement. L'overlay waiter, la disposition de pile pselect et chaque offset de structure sont épinglés à cette branche, donc rien ici ne se transfère vers 6.6, 6.1 ou 5.10 — ceux-ci nécessitent une base construite pour eux. generate_target.py refuse tout autre banner plutôt que d'émettre un en-tête qui planterait sur l'appareil.

Statut : fonctionnel. Vérifié sur l'appareil le 2026-07-26 depuis un démarrage propre, avec les deux variantes de preloader — uid=0(root) context=u:r:kernel:s0, SELinux permissif, su installé. Le root n'est pas persistant : relancez la ligne LD_PRELOAD après chaque démarrage. La course pselect n'est pas fiable à 100 % : un échec peut faire paniquer le téléphone, et une nouvelle tentative après le redémarrage est normale. Voir WARHOL_PORT.md pour le registre complet.

Cet appareil nécessite le correctif kernel-MTE. Le popsicle upstream standard ne peut pas le rooter — il boucle dans kernel page retry N/12 indéfiniment. Voir MTE du kernel.

Les builds existent en deux variantes de preloader, PRELOADER=retail (défaut) et PRELOADER=eng. Elles sélectionnent des répertoires cibles différents afin que l'une ne puisse pas écraser les adresses de l'autre — voir Variante de preloader.


Appareil cible

Les informations ci-dessous ont été lues dans le package full-OTA retail — métadonnées, manifeste de charge utile A/B, et images boot/vendor_boot/dtbo extraites de payload.bin.

Le kernel importe plus que le SoC ici : warhol se trouve sur la même branche GKI que popsicle upstream (android16-5, pages 4K), à un niveau de patch près — 6.12.38 contre le 6.12.23 vérifié de popsicle. Les offsets de structure doivent quand même être régénérés pour chaque build ; seule la forme de l'exploit se transmet. Un build OS3.0.x différent nécessite son propre target.h.


Pourquoi cette base

La chaîne d'exploit est verrouillée en version sur la branche GKI, pas sur le SoC. La disposition du waiter rt_mutex, l'overlay de pile pselect et les offsets de la structure pipe_buffer suivent tous le kernel, donc une base 6.12/android16 bat une base du même fournisseur sur une branche plus ancienne.

x-spy/CVE-2026-43499-popsicle est la seule implémentation publique vérifiée sur la ligne GKI 6.12/android16 (Xiaomi 17 / Pro / Ultra, kernel 6.12.23-android16-5), donc source/ en est tiré et conservé aussi proche d'upstream que possible — deux lignes mises à part (voir MTE du kernel, dont cet appareil a besoin pour fonctionner tout court).

L'essentiel du delta MediaTek se limite à la génération de cible au moment du build, en deux morceaux :

  • upstream lit p0_phys_offset et p0_kernel_phys_load dans une partition Qualcomm xbl_config, que warhol ne possède pas. generate_target.py --dtb lit la base DRAM depuis le nœud /memory du FDT vendor_boot à la place, en l'arrondissant à l'inférieur comme le fait arm64_memblock_init. L'adresse de chargement physique du kernel est lue dans la réservation mb_kernel du preloader avec --preloader ; le delta sort à 0 pour cet appareil, et lk refuse de démarrer un kernel placé ailleurs.
  • MediaTek fournit le kernel compressé LZ4-legacy dans boot.img plutôt que comme une image arm64 Image nue, donc le générateur le décompresse avant analyse.

WARHOL_PORT.md §2 contient la dérivation complète.


Variante de preloader

lk de MediaTek ne charge pas le kernel vers une constante de compilation — il cherche une réservation DRAM nommée mb_kernel et exige qu'elle atterrisse exactement dessus. Cette réservation est faite par le preloader, c'est pourquoi le build de preloader que le téléphone exécute est une entrée de build ici : c'est la seule chose en dehors de boot.img qui puisse déplacer P0_KERNEL_PHYS_LOAD, et une mauvaise valeur là signifie un mauvais alias de carte linéaire et un téléphone mort plutôt qu'un exploit échoué.

D'où deux variantes, conservées comme des répertoires cibles séparés :

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

Les deux artefacts sont conservés côte à côte sous des noms distincts. Sur ce firmware, ils sortent identiques octet pour octet — c'est le résultat de l'analyse ci-dessous, pas un raccourci pour contourner cette analyse, donc les deux sont toujours construits et nommés séparément.

Lisez vous-même les tables de disposition mémoire des deux preloaders avec :

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

Pour ce firmware, les deux tables sont identiques, mb_kernel.start = 0x80000000 dans les deux, donc le target.h eng sort identique octet pour octet à celui retail et les deux builds produisent le même preload.so.

Ce qui atteint réellement l'exploit, c'est la différence P0_KERNEL_PHYS_LOAD − P0_PHYS_OFFSET, et ses deux termes ne reposent pas sur des preuves d'égale solidité :

  • P0_KERNEL_PHYS_LOAD — mesuré depuis l'image eng, comme mb_kernel.start ci-dessus.
  • P0_PHYS_OFFSET — a été argumenté plutôt que mesuré, puisque c'est memstart_addr, que le kernel prend depuis le nœud /memory que lk émet à l'exécution à partir de ce que le preloader rapporte après l'init DRAM, pas depuis le FDT statique que le générateur lit. L'argument était que les deux builds partagent tout le chemin DRAM — mêmes sources dramc/emi/mblock/memory_layout, aucun code de disposition mémoire parmi les chaînes propres à eng — et que la seule réservation supplémentaire du preloader eng, une security_fe_rsv dynamique de 3 Mio avec mapping=1, ne peut ni déplacer une entrée à adresse fixe ni creuser un trou en bas de la DRAM. L'exécution sur l'appareil a tranché : les alias de carte linéaire ont atterri pour la variante eng, donc le terme est correct.

Dérivation complète dans targets/warhol-OS3.0.304.0.WPSJPXM-eng/NOTES.md.

Notes de l'exécution sur l'appareil :

  • Le BootROM accepte ce preloader eng — il a démarré normalement vers Android, avec ro.boot.verifiedbootstate=green et flash.locked=1 inchangés. C'était une question ouverte jusqu'à l'essai ; c'est décidé par le hash de clé racine gravé en eFuse, et ce build est signé avec les mêmes clés que le retail.
  • Le preloader eng maintient le mode de téléchargement META / factory actif : %s META DIS est une chaîne propre au retail, tandis que eng emporte toute une implémentation META que retail n'a pas (Enable fastmeta., FAST META GPIO: %d, META_COM PORT: %d, read_meta_proinfo, …). Il a démarré directement vers Android ici, mais si un téléphone flashé en eng atterrit un jour ailleurs, c'est la cause probable et aucune valeur de target.h n'est impliquée.
  • Si un firmware ultérieur déplace mb_kernel, les deux cibles divergent — les garder comme répertoires séparés est ce qui empêche que cela se produise en silence.

MTE du kernel

Ce kernel exécute KASAN_HW_TAGS — /proc/cmdline porte kasan.stack_ring_size=524288 — donc les pointeurs slab portent une étiquette d'allocation dans les bits 59:56. popsicle upstream suppose des pointeurs non étiquetés et ne peut donc absolument pas rooter cet appareil : il boucle dans [-] kernel page retry N/12 mode=1 indéfiniment, sans rien dans le journal pour expliquer pourquoi.

Deux lignes dans source/ corrigent cela, et les deux sont dans warhol-mte-fix.patch :

Seules les vérifications retirent l'étiquette. Les pointeurs eux-mêmes restent étiquetés, car l'étiquette est la bonne pour la mémoire à laquelle ils pointent — ce dont un déréférencement kernel de ces pointeurs a besoin.

Ne lisez pas arm64.memtag.bootctl pour cela : cette propriété est le contrôle MTE espace utilisateur et ne dit rien sur le fait que le kernel étiquette ses propres allocations.


Upstream / références

Ce dépôt est un port. Le crédit pour la chaîne d'exploit revient à l'upstream.


Disposition

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)

Compilation

Rien ne se construit tant qu'un target.h n'existe pas — le Makefile échoue bruyamment plutôt que d'émettre un binaire contre le mauvais kernel.

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

Sans image de preloader sous la main, --kernel-phys-delta 0 est la forme plus ancienne et donne le même en-tête pour ce firmware — mais c'est une affirmation plutôt qu'une lecture, donc préférez --preloader. Passer les deux fait recouper le générateur et échouer sur une discordance.

--base 5081 est l'offset d'en-tête local de payload.bin pour cet OTA particulier ; lisez-le depuis ota-property-files dans META-INF/com/android/metadata pour tout autre package.

Nécessite un NDK Android (NDK_ROOT / ANDROID_NDK_HOME) et llvm-objdump.

Exécution

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 et l'état SELinux sont patchés en mémoire, donc cela doit être répété après chaque démarrage. Un déverrouillage du bootloader n'est pas requis.


Avertissement

Pour la recherche sur du matériel que vous possédez. L'exécuter peut provoquer un bootloop ou un brick de l'appareil et annulera la garantie. Aucune garantie d'aucune sorte.

Les projets upstream sont sous licence de leurs auteurs respectifs ; ce port reprend leurs conditions.

Télécharger l’outil
ObjetValeurSource
Nom de codewarholpre-device=warhol
Empreinte buildXiaomi/warhol_global/warhol:16/BP2A.250605.031.A3/OS3.0.304.0.WPSJPXM:user/release-keyspost-build
IncrémentaleOS3.0.304.0.WPSJPXM (JP global)post-build-incremental
Android16, SDK 36post-sdk-level=36
Correctif de sécurité2026-05-01post-security-patch-level
Type OTAA/B (payload.bin, CrAU, 39 partitions)ota-type=AB
SoCMediaTek MT6993 (Dimensity 9500)compatibles mediatek,mt6993-* dans le DTB vendor_boot ; cmdline bootopt=64S3,32N2,64N2
Kernel6.12.38-android16-5-g1d46253471dd-ab15048002-4k, clang 19.0.1bannière lue depuis le boot.img extrait
image booten-tête v4, kernel 18 898 125 B, compressé LZ4-legacy, pas de ramdisktools/bootinfo.py
PRELOADER=Preloader sur le téléphoneRépertoire cibleStatut
retail (défaut)le preloader_<device>.bin livré, identique octet pour octet au preloader_raw.img de la ROM fastboottargets/warhol-OS3.0.304.0.WPSJPXM/✅ vérifié sur l'appareil le 2026-07-26
engle build engineering, preloader_<device>_eng.bintargets/warhol-OS3.0.304.0.WPSJPXM-eng/✅ vérifié sur l'appareil le 2026-07-26
FichierChangementPourquoi
src/util.ckernelsnitch_setup(..., mte_enabled=1)avec 0, la recherche mm_struct ne tente que des candidats non étiquetés et ne peut jamais atteindre un pointeur étiqueté — un échec structurel, pas de la malchance
src/util.cis_kernel_ptr() / is_direct_ptr() retirent l'étiquette avant la vérification de plageun pointeur étiqueté lu depuis la mémoire kernel est sinon rejeté comme hors carte linéaire (direct-entry-fatal reason=bad-task-or-cpu)
src/kernelsnitch/kernelsnitch.hbalayage d'étiquettes < 15 → < 16l'étiquette 0xf est le pointeur non étiqueté/attrape-tout, donc le balayage couvre maintenant aussi un kernel sans MTE — mte_enabled=1 est sûr dans les deux cas
DépôtRôle ici
https://github.com/MobiusM/CVE-2026-43499PoC / déclencheur de crash original de CVE-2026-43499
https://github.com/x-spy/CVE-2026-43499-popsicleBase de ce port. Xiaomi 17 Pro Max (popsicle), kernel 6.12.23-android16-5 ; source/ et tools/generate_target.py viennent d'ici
https://github.com/Kananosa/CVE-2026-43499-For-Xiaomi-17T-chagallAppareil frère le plus proche (Xiaomi 17T, chagall, également MediaTek). Dérivé de popsicle, fournit un preload.so précompilé — ses constantes compilées ont confirmé l'offset de chargement physique
https://github.com/MiCode/Xiaomi_Kernel_OpenSourceSources du kernel Xiaomi, pour recouper la disposition des structures