Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-43499-warhol-root — Exploit de escalonamento de privilégio local direcionado à CVE-2026-43499 para o Xiaomi 17T Pro (warhol) no Android 16 com SoC MediaTek MT6993. | Kitploit
Ferramentas/GitHubGitHub/soralis0912/cve-2026-43499-warhol-root
Segurança AndroidEscalada de PrivilégiosAnálise de VulnerabilidadesExploraçãoExploração de Binários
GitHubsoralis0912/cve-2026-43499-warhol-root

CVE-2026-43499-warhol-root

Exploit de escalonamento de privilégio local direcionado à CVE-2026-43499 para o Xiaomi 17T Pro (warhol) no Android 16 com SoC MediaTek MT6993.

Ver Repositório

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
1145há 1 mêsAinda não revisado

warhol-root

Escalada de privilégios local CVE-2026-43499 (IonStack), portada para o Xiaomi 17T Pro (warhol) — MediaTek MT6993, Android 16.

Apenas GKI 6.12 / android16. O overlay do waiter, o layout da pilha do pselect e todos os offsets de struct estão fixados a esse branch, então nada aqui é transferível para 6.6, 6.1 ou 5.10 — esses precisam de uma base construída para eles. generate_target.py recusa qualquer outro banner em vez de emitir um header que causaria fault no dispositivo.

Status: funcionando. Verificado no dispositivo em 2026-07-26 a partir de uma inicialização limpa, com ambas as variantes de preloader — uid=0(root) context=u:r:kernel:s0, SELinux permissivo, su instalado. O root não é persistente: execute novamente a linha LD_PRELOAD após cada boot. A corrida do pselect não é 100%: uma execução com falha pode causar panic no telefone, e uma nova tentativa após o reboot é normal. Consulte WARHOL_PORT.md para o registro completo.

Este dispositivo precisa da correção do kernel-MTE. O popsicle upstream padrão não consegue fazer root nele — ele fica em loop em kernel page retry N/12 para sempre. Consulte Kernel MTE.

Os builds vêm em duas variantes de preloader, PRELOADER=retail (padrão) e PRELOADER=eng. Elas selecionam diretórios de target diferentes para que nenhuma possa sobrescrever os endereços da outra — consulte Variante de preloader.


Dispositivo alvo

Os fatos abaixo foram lidos do pacote full-OTA retail — metadados, o manifesto do payload A/B e as imagens boot/vendor_boot/dtbo extraídas do payload.bin.

Aqui o kernel importa mais do que o SoC: o warhol está no mesmo branch GKI do popsicle upstream (android16-5, páginas de 4K), com um patchlevel de diferença — 6.12.38 contra o 6.12.23 verificado do popsicle. Os offsets de struct ainda precisam ser regenerados por build; apenas o formato do exploit é reaproveitado. Um build OS3.0.x diferente precisa do seu próprio target.h.


Por que esta base

A cadeia do exploit está travada por versão ao branch GKI, não ao SoC. O layout do waiter do rt_mutex, o overlay de pilha do pselect e os offsets da struct pipe_buffer acompanham o kernel, então uma base 6.12/android16 supera uma base do mesmo fornecedor em um branch mais antigo.

x-spy/CVE-2026-43499-popsicle é a única implementação pública verificada na linha GKI 6.12/android16 (Xiaomi 17 / Pro / Ultra, kernel 6.12.23-android16-5), então source/ foi retirada dela e mantida o mais próxima possível do upstream — com exceção de duas linhas (consulte Kernel MTE, sem a qual este dispositivo simplesmente não funciona).

A maior parte do delta da MediaTek está limitada à geração de target em tempo de build, em duas partes:

  • o upstream lê p0_phys_offset e p0_kernel_phys_load de uma partição xbl_config da Qualcomm, que o warhol não possui. generate_target.py --dtb lê a base da DRAM do nó /memory do FDT do vendor_boot em vez disso, arredondando para baixo da mesma forma que arm64_memblock_init faz. O endereço de carga física do kernel é lido da reserva mb_kernel do preloader com --preloader; o delta resulta em 0 para este dispositivo, e o lk se recusa a dar boot em um kernel colocado em qualquer outro lugar.
  • a MediaTek distribui o kernel compactado em LZ4-legacy dentro de boot.img, em vez de um Image arm64 puro, então o gerador o descompacta antes da análise.

WARHOL_PORT.md §2 tem a derivação completa.


Preloader variant

O lk da MediaTek não carrega o kernel para uma constante de tempo de compilação — ele procura uma reserva de DRAM chamada mb_kernel e valida que ela caiu exatamente nela. Essa reserva é feita pelo preloader, e é por isso que o build do preloader que o telefone está executando é uma entrada de build aqui em primeiro lugar: é a única coisa fora do boot.img que pode mover P0_KERNEL_PHYS_LOAD, e um valor errado ali significa um alias errado do mapa linear e um telefone morto, em vez de um exploit com falha.

Daí duas variantes, mantidas como diretórios 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 os artefatos são mantidos lado a lado com nomes distintos. Neste firmware eles saem idênticos byte a byte — esse é o resultado da análise abaixo, não um atalho para contorná-la, então os dois ainda são compilados e nomeados separadamente.

Leia as tabelas de layout de memória dos dois preloaders você mesmo com:

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

Neste firmware as duas tabelas são idênticas, mb_kernel.start = 0x80000000 em ambas, então o target.h do eng sai idêntico byte a byte ao do retail e ambos os builds produzem o mesmo preload.so.

O que de fato chega ao exploit é a diferença P0_KERNEL_PHYS_LOAD − P0_PHYS_OFFSET, e seus dois termos não se apoiam em evidências igualmente sólidas:

  • P0_KERNEL_PHYS_LOAD — medido a partir da imagem eng, como mb_kernel.start acima.
  • P0_PHYS_OFFSET — foi argumentado em vez de medido, já que é memstart_addr, que o kernel obtém do nó /memory que o lk emite em tempo de execução a partir do que o preloader reporta após a inicialização da DRAM, não do FDT estático que o gerador lê. O argumento foi que os dois builds compartilham todo o caminho da DRAM — mesmas fontes dramc/emi/mblock/memory_layout, nenhum código de layout de memória entre as strings exclusivas do eng — e que a única reserva extra do preloader eng, uma security_fe_rsv dinâmica de 3 MiB com mapping=1, não pode deslocar uma entrada de endereço fixo nem abrir um buraco no fundo da DRAM. A execução no dispositivo resolveu a questão: os aliases do mapa linear bateram com o eng, então o termo está correto.

Derivação completa em targets/warhol-OS3.0.304.0.WPSJPXM-eng/NOTES.md.

Notas da execução no dispositivo:

  • O BootROM aceita este preloader eng — ele iniciou normalmente até o Android, com ro.boot.verifiedbootstate=green e flash.locked=1 inalterados. Essa era uma questão em aberto até ser testada; ela é decidida pelo hash da chave raiz gravado no efuse, e este build é assinado com as mesmas chaves do retail.
  • O preloader eng mantém o modo META / download de fábrica ativo: %s META DIS é uma string exclusiva do retail, enquanto o eng carrega uma implementação META completa que o retail não tem (Enable fastmeta., FAST META GPIO: %d, META_COM PORT: %d, read_meta_proinfo, …). Aqui ele iniciou direto no Android, mas se um telefone gravado com o eng algum dia cair em outro lugar, essa é a causa provável e nenhum valor de target.h está envolvido.
  • Se um firmware posterior mover mb_kernel, os dois targets divergem — mantê-los como diretórios separados é o que impede que isso passe despercebido.

Kernel MTE

Este kernel executa KASAN_HW_TAGS — /proc/cmdline carrega kasan.stack_ring_size=524288 — então ponteiros de slab carregam uma tag de alocação nos bits 59:56. O popsicle upstream assume ponteiros sem tag e, portanto, não consegue fazer root neste dispositivo de forma alguma: ele fica em loop em [-] kernel page retry N/12 mode=1 indefinidamente, sem nada no log explicando o motivo.

Duas linhas em source/ corrigem isso, e ambas estão em warhol-mte-fix.patch:

Apenas as verificações removem a tag. Os ponteiros em si permanecem com tag, porque a tag é a correta para a memória para a qual apontam — que é exatamente o que uma dereferência deles pelo kernel precisa.

Não consulte arm64.memtag.bootctl para isso: essa propriedade é o controle de MTE do userspace e não diz nada sobre se o kernel está aplicando tags às próprias alocações.


Upstream / referências

Este repositório é um port. O crédito pela cadeia do exploit pertence ao 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)

Compilação

Nada é compilado até que um target.h exista — o Makefile falha ruidosamente em vez de emitir um binário contra o kernel errado.

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

Sem uma imagem de preloader em mãos, --kernel-phys-delta 0 é a forma mais antiga e gera o mesmo header para este firmware — mas é uma afirmação em vez de uma leitura, então prefira --preloader. Passar ambos faz o gerador fazer a verificação cruzada e falhar em caso de divergência.

--base 5081 é o offset do header local do payload.bin para este OTA específico; leia-o de ota-property-files em META-INF/com/android/metadata para qualquer outro pacote.

Requer um Android NDK (NDK_ROOT / ANDROID_NDK_HOME) e llvm-objdump.

Execução

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 e o estado do SELinux são alterados em memória, então isso precisa ser repetido após cada boot. Não é necessário desbloquear o bootloader.


Aviso de responsabilidade

Para pesquisa em hardware que você possui. Executar isso pode causar bootloop ou brickar um dispositivo e invalidará a garantia. Nenhuma garantia de qualquer tipo.

Os projetos upstream são licenciados por seus respectivos autores; este port carrega seus termos.

Baixar ferramenta
ItemValorFonte
Codinomewarholpre-device=warhol
Fingerprint do buildXiaomi/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
Patch de segurança2026-05-01post-security-patch-level
Tipo de OTAA/B (payload.bin, CrAU, 39 partições)ota-type=AB
SoCMediaTek MT6993 (Dimensity 9500)compatíveis mediatek,mt6993-* no DTB do vendor_boot; cmdline bootopt=64S3,32N2,64N2
Kernel6.12.38-android16-5-g1d46253471dd-ab15048002-4k, clang 19.0.1banner lido do boot.img extraído
Imagem de bootheader v4, kernel 18,898,125 B, compactado com LZ4-legacy, sem ramdisktools/bootinfo.py
PRELOADER=Preloader no telefoneDiretório de targetStatus
retail (padrão)o preloader_<device>.bin de fábrica, byte idêntico ao preloader_raw.img da ROM de fastboottargets/warhol-OS3.0.304.0.WPSJPXM/✅ verificado no dispositivo em 2026-07-26
engo build de engenharia, preloader_<device>_eng.bintargets/warhol-OS3.0.304.0.WPSJPXM-eng/✅ verificado no dispositivo em 2026-07-26
ArquivoAlteraçãoMotivo
src/util.ckernelsnitch_setup(..., mte_enabled=1)com 0, a busca do mm_struct só tenta candidatos sem tag e nunca alcança um ponteiro com tag — um erro estrutural, não azar
src/util.cis_kernel_ptr() / is_direct_ptr() removem a tag antes da verificação de intervaloum ponteiro com tag lido da memória do kernel é, caso contrário, rejeitado como fora do mapa linear (direct-entry-fatal reason=bad-task-or-cpu)
src/kernelsnitch/kernelsnitch.hvarredura de tag < 15 → < 16a tag 0xf é o ponteiro sem tag/que casa com tudo, então a varredura agora também cobre um kernel sem MTE — mte_enabled=1 é seguro de qualquer forma
RepositórioPapel aqui
https://github.com/MobiusM/CVE-2026-43499PoC / disparador de crash original do CVE-2026-43499
https://github.com/x-spy/CVE-2026-43499-popsicleBase deste port. Xiaomi 17 Pro Max (popsicle), kernel 6.12.23-android16-5; source/ e tools/generate_target.py vêm daqui
https://github.com/Kananosa/CVE-2026-43499-For-Xiaomi-17T-chagallDispositivo irmão mais próximo (Xiaomi 17T, chagall, também MediaTek). Derivado do popsicle, traz um preload.so pré-compilado — suas constantes embutidas confirmaram o offset de carga física
https://github.com/MiCode/Xiaomi_Kernel_OpenSourceFontes do kernel da Xiaomi, para verificação cruzada do layout das structs