
Исследовательский порт Android CVE-2026-98260 для конкретной цели — Xiaomi 17 (pudding)
Цепочка эксплойта для Android AArch64, нацеленная на конкретную сборку ядра Xiaomi 17 (кодовое имя
pudding): начиная с обычной оболочки ADB, последовательно переводит SELinux в режим Permissive, обнуляет UID/GID текущего процесса, добавляет полный набор Linux capabilities и предоставляет root-сервис в рамках текущего цикла загрузки.
Этот проект основан на материале CVE-2026-98260-popsicle-android (Xiaomi 17 Pro Max / popsicle) и портирован из него; это не независимое исследование, реализованное с нуля.
Вызов 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 |
| Система | Xiaomi HyperOS 4 OS4.0.5.0.XPCCNXM, Android 17 |
| Ядро | 6.12.69-android16-6-g43b5ab7e247d-abogki561813157-4k |
| Размер страницы | 4 KiB |
| Начальная точка | Авторизованная обычная оболочка ADB, UID 2000, SELinux Enforcing, загрузчик заблокирован |
| Успешный результат | UID/GID 0, SELinux Permissive, CapPrm/CapEff/CapBnd=000001ffffffffff |
| Время жизни | root-сервис доступен для новых оболочек ADB в рамках текущей загрузки; после перезагрузки требуется повторный запуск |
Независимая проверка после успеха (в новой оболочке ADB):
uid=0(root) gid=0(root)
CapInh: 000001ffffffffff
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
getenforce: Permissive
Это не постоянный root. Ничего не записывается в boot/init_boot или любой другой раздел, загрузчик остаётся заблокированным; после перезагрузки SELinux возвращается в режим Enforcing, а root-сервис исчезает.
Вероятность успеха не гарантируется. На практике потребовалось 9 запусков, чтобы один раз полностью пройти A→B→C. Условия прохождения трёх этапов независимы друг от друга:
| Этап | Программа на устройстве | Условие прохождения |
|---|---|---|
| 1. SELinux | exploit-android-perf | getenforce возвращает Permissive, остальные поля словаря состояния остаются ожидаемыми |
| 2. Идентичность | exploit-android-perf-chain | UID/GID того же процесса становятся равны 0, затем выполняется exec fullcap |
| 3. Полные права | exploit-android-key-ptr + pc98260_rootd.c | Полные capabilities, root-сервис доступен из новой оболочки |
Если какой-либо шаг не сработал, выводится [PARKED] и сохраняется опасное состояние, необходима перезагрузка; повторные попытки в рамках текущей загрузки недопустимы.
--aio 16384 — это настроечное значение для данного устройства (в успешном запуске попадание произошло на 3903-й странице метаданных perf).
| Место | popsicle | pudding |
|---|---|---|
LINK_SELINUX_STATE | 0xffffffc08289aba0 | 0xffffffc0827f9ba0 |
LINK_GETPID | 0xffffffc080074eac | 0xffffffc080102e10 |
| Утечка адреса timer | зонд, возвращаемый alloc_posix_timer | этот символ встроен (inlined), вместо него используется точка входа posix_cpu_timer_create $arg1 |
PERF_MAX | 8192 | 16384 (повышает шанс попадания в страницу) |
Обоснование и доказательства см. в docs/ADAPTATION.md.
Требуется Android NDK. Каталог bin/ в репозитории собран с помощью 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 поочерёдно сравнивает SHA-256 новых артефактов с bin/; побайтовое совпадение возможно только при использовании того же инструментария, что и для bin/. При смене версии NDK всё будет работать, но хеши будут отличаться.
Артефакты:
| Артефакт | Исходный код |
|---|---|
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 |
Сборка не подключается к телефону и не записывает данные на устройство.
Подключите устройство с включённой отладкой по USB и выданным разрешением, добавьте platform-tools в PATH:
.\开始98260临时ROOT.bat
Или явно указать устройство:
powershell -NoProfile -ExecutionPolicy Bypass -File .\run_98260.ps1 -Serial <ADB序列号> -Reboot
Скрипт на хосте проверяет модель устройства, инкрементальную версию системы, полную строку ядра, boot ID и хеши четырёх бинарников; кроме того, перед запуском каждого этапа он устанавливает /sys/kernel/tracing/tracing_on в 0 (в некоторых сборках HyperOS miuibpf оставляет его в 1, из-за чего цепочка эксплуатации отказывается запускаться). При появлении [PARKED] скрипт останавливается и предлагает перезагрузиться.
После успешного выполнения root можно использовать так:
adb shell -t /data/local/tmp/pc98260-su
adb shell /data/local/tmp/pc98260-su -c "id"
Цепочка эксплуатации требует точного освобождения «той самой страницы, где находится целевой таймер». Если не удаётся наблюдать ту же целевую страницу или проверка после записи указателя оказывается несогласованной, программа сохраняет соответствующие zombie/отображения и останавливается, чтобы избежать слепого освобождения, пока ядро всё ещё ссылается на висячий узел. В этом случае границей следующей попытки следует считать новую загрузку телефона.
Данный репозиторий не содержит: резервные копии устройства, образы boot/init_boot, образы разделов, payload.bin, извлечённые из прошивки ядра/ELF, исходные журналы выполнения, серийные номера ADB или boot ID. logs/ и build/ игнорируются Git. В bin/ находятся только четыре бинарника временной цепочки повышения привилегий.
/data/local/tmp/pc98260-root.sock с полными capabilities; в течение текущей загрузки всё устройство полностью открыто.