
Porta de pesquisa de CVE-2026-98260 do Android específica para o alvo, para o Xiaomi 17 (pudding)
针对小米 17(代号
pudding)一个精确内核构建的 Android AArch64 利用链:从普通 ADB shell 出发,依次把 SELinux 置为 Permissive、把本进程 UID/GID 归零、补齐完整 Linux capabilities,并在当前开机周期内提供 root 服务。
Este projeto é baseado e portado de CVE-2026-98260-popsicle-android (Xiaomi 17 Pro Max / popsicle), não é uma pesquisa independente implementada do zero.
非主线程 execve() 会先执行 de_thread() 交换线程身份。若 exec 在这之后失败(例如 exec_mmap() 被 SIGKILL 打断而返回 -EINTR),任务会在清理 POSIX timer 之前退出:k_itimer 被释放,但它的 timerqueue 节点仍留在存活任务的树里。父进程之后回收该任务时,cleanup_timerqueue() 再次操作这个已释放节点,形成 use-after-free。
利用把这次 UAF 变成一次受限的八字节零写,再按 SELinux → UID/GID → 完整 capabilities 三步推进。面向入门的完整讲解见 docs/VULNERABILITY.md。
| 项目 | 实测值 |
|---|---|
| 设备 | Xiaomi 17,型号 25113PN0EC,代号 pudding |
| 系统 | 小米澎湃 OS 4 OS4.0.5.0.XPCCNXM,Android 17 |
| 内核 | 6.12.69-android16-6-g43b5ab7e247d-abogki561813157-4k |
| 页大小 | 4 KiB |
| 起点 | 已授权的普通 ADB shell,UID 2000,SELinux Enforcing,bootloader 锁定 |
| 成功结果 | UID/GID 0、SELinux Permissive、CapPrm/CapEff/CapBnd=000001ffffffffff |
| 生命周期 | root 服务可供本次开机后续的新 ADB shell 使用;重启后需要重新运行 |
成功后的独立验证(新开的 ADB shell):
uid=0(root) gid=0(root)
CapInh: 000001ffffffffff
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
getenforce: Permissive
Isto não é um root persistente. Nada foi gravado em boot/init_boot ou em qualquer partição, o bootloader permanece bloqueado; após reiniciar, o SELinux volta para Enforcing e o serviço de root desaparece.
Sem promessa de taxa de sucesso. Nos testes, foi necessário um total de 9 inicializações para completar uma sequência completa A→B→C. As condições de aprovação das três fases são independentes entre si:
| Fase | Programa no dispositivo | Condição de aprovação |
|---|---|---|
| 1. SELinux | exploit-android-perf | getenforce retorna Permissive, e os demais campos da palavra de status permanecem conforme o esperado |
| 2. Identidade | exploit-android-perf-chain | O UID/GID do mesmo processo passa a 0, seguido de exec fullcap |
| 3. Permissões completas | exploit-android-key-ptr + pc98260_rootd.c | Capabilities completas, o serviço root pode ser acessado por um novo shell |
Se qualquer etapa não for atingida, será exibido [PARKED] e o estado perigoso será mantido; é obrigatório reiniciar, não é possível tentar novamente à força dentro desta mesma inicialização.
--aio 16384 é o valor de ajuste desta máquina (a execução bem-sucedida acertou na 3903ª página de metadados perf).
| Local | popsicle | pudding |
|---|---|---|
LINK_SELINUX_STATE | 0xffffffc08289aba0 | 0xffffffc0827f9ba0 |
LINK_GETPID | 0xffffffc080074eac | 0xffffffc080102e10 |
| Vazamento de endereço do timer | sonda de retorno de alloc_posix_timer | esse símbolo foi inlined, passando a usar a entrada $arg1 de posix_cpu_timer_create |
PERF_MAX | 8192 | 16384 (aumenta a chance de acerto de página) |
Fundamentação e evidências em docs/ADAPTATION.md.
É necessário um Android NDK. O bin/ no repositório foi compilado com NDK 26.3.11579264 / API 34:
powershell -NoProfile -ExecutionPolicy Bypass -File .\build.ps1 -NdkHome "$env:LOCALAPPDATA\Android\Sdk\ndk\26.3.11579264" -ApiLevel 34
-VerifyReference compara o SHA-256 de cada novo artefato com o de bin/; apenas o uso da mesma toolchain de bin/ produzirá bytes idênticos. Trocar a versão do NDK ainda permite a execução, mas os hashes serão diferentes.
Artefatos:
| Artefato | Código-fonte de entrada |
|---|---|
exploit-android-perf | src/exploit-android-perf.c |
exploit-android-perf-chain | src/exploit-android-perf-chain.c |
exploit-android-key-ptr | src/exploit-android-key-ptr.c + src/pc98260_rootd.c |
pc98260-su | src/pc98260_su.c |
A compilação não se conecta ao telefone nem grava no dispositivo.
Conecte um dispositivo com depuração USB ativada e autorizada e adicione o platform-tools ao PATH:
.\开始98260临时ROOT.bat
Ou especifique o dispositivo explicitamente:
powershell -NoProfile -ExecutionPolicy Bypass -File .\run_98260.ps1 -Serial <ADB序列号> -Reboot
O script do host verifica o modelo do dispositivo, a versão incremental do sistema, a string completa do kernel, o boot ID e os hashes dos quatro binários; ele também define /sys/kernel/tracing/tracing_on como 0 antes de iniciar cada estágio (em algumas builds do HyperOS, o miuibpf o mantém em 1, e a cadeia de exploração se recusa a executar por isso). Quando aparece [PARKED], o script para e solicita uma reinicialização.
Após o sucesso, o root pode ser usado assim:
adb shell -t /data/local/tmp/pc98260-su
adb shell /data/local/tmp/pc98260-su -c "id"
A cadeia de exploração exige recuperar com precisão "a página onde está o timer alvo". Se a mesma página alvo não for observada, ou se a verificação após a escrita do ponteiro for inconsistente, o programa preserva o zombie/mapeamento relevante e para, evitando recuperar às cegas enquanto o nó pendente ainda é referenciado pelo kernel. Nesse caso, deve-se usar uma nova inicialização do telefone como limite para a próxima tentativa.
Este repositório não contém: backup do dispositivo, imagens boot/init_boot, imagens de partição, payload.bin, kernel/ELF extraídos do firmware, logs de execução brutos, números de série ADB ou boot ID. logs/ e build/ estão no Git ignore. Em bin/ há apenas os quatro binários temporários da cadeia de escalonamento de privilégios.
/data/local/tmp/pc98260-root.sock com capabilities completas; o dispositivo inteiro fica totalmente exposto durante esta inicialização.