Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-43499-pmg110-root — Эксплойт Android LPE для CVE-2026-43499, нацеленный на OPPO PMG110 (ядро 6.6). Использует futex PI UAF для получения root-прав и установки su-демона через LD_PRELOAD. | Kitploit
Инструменты/GitHubGitHub/soralis0912/cve-2026-43499-pmg110-root
Безопасность AndroidПовышение привилегийАнализ уязвимостейЭксплуатацияПост-эксплуатацияТестирование на ПроникновениеМобильная безопасностьRed TeamingРазработка Полезной Нагрузки

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Эксплуатация Бинарных Файлов
GitHubsoralis0912/cve-2026-43499-pmg110-root

CVE-2026-43499-pmg110-root

Эксплойт Android LPE для CVE-2026-43499, нацеленный на OPPO PMG110 (ядро 6.6). Использует futex PI UAF для получения root-прав и установки su-демона через LD_PRELOAD.

Репозиторий
124 дней назадЕщё не проверено

pmg110-root

Локальное повышение привилегий через CVE-2026-43499 (use-after-free в futex PI rt_mutex_waiter), портированное на OPPO PMG110 / K15 Pro+ — MediaTek MT6991, ColorOS 16.

Загружается один файл, запуск через LD_PRELOAD:

root@kitploit:~
adb push out/preload-pmg110-16.0.9.400.so /data/local/tmp/preload.so
adb shell chmod 644 /data/local/tmp/preload.so
adb shell LD_PRELOAD=/data/local/tmp/preload.so /system/bin/true

В случае успеха на устройстве остаётся постоянный su:

root@kitploit:~
adb shell /data/local/tmp/su -c id      # uid=0(root)

Проверено на устройстве (2026-07-27): uid=0 примерно за 35 секунд при «чистом» запуске без переопределений окружения, и su затем отвечает из обычного непривилегированного adb shell:

root@kitploit:~
$ adb shell "/data/local/tmp/su -c 'echo 0 > /proc/sys/kernel/kptr_restrict'"
$ adb shell "/data/local/tmp/su -c 'grep -w init_task /proc/kallsyms'"
ffffffe89033e780 D init_task

Эксплойт и установка su проверены на этом устройстве. То, что затем считала рутированная оболочка, также подтверждает P0_KERNEL_PHYS_LOAD, смещения символов и KS_MTE_TAGGED=0 независимо от эксплойта — см. targets/pmg110-16.0.9.400/NOTES.md.

Что делает и чего не делает

Он выполняет Write 1 (SELinux permissive) и Write 2 (cred → init_cred), переводит дочерний процесс в uid=0 и оттуда устанавливает встроенный демон su.

  • по-прежнему загружается один файл. su — не второй артефакт: su_daemon.c собирается как отдельный aarch64 PIE и через .incbin встраивается в .rodata библиотеки, поэтому он находится внутри preload.so и записывается обратно во время выполнения. Путь warhol-root, без изменений.
  • нет root-скрипта, нет ksud, нет KernelSU
  • вызывающий процесс остаётся непривилегированным — он получает root, обращаясь к демону, и то же самое вы будете делать из оболочки потом
  • SELinux остаётся в режиме permissive, как это делает warhol-root: демон должен обслуживать непривилегированных клиентов через свой сокет. Перезагрузка вернёт enforcing.

su устанавливается в трёх местах, потому что одно из них — то, до которого вы действительно доберётесь:

Демон слушает /data/local/tmp/temp_su.sock и пишет лог в /data/local/tmp/su_daemon.log. Root не сохраняется после перезагрузки — повторно запускайте команду с LD_PRELOAD после каждой загрузки.

Для установки KernelSU используйте вместо этого маршрут /data/local/tmp/a/e в ghostlock-oneplus.

Связь с warhol-root

Всё, кроме ядра эксплойта, принадлежит warhol-root — взято, а не изобретено заново:

  • структура — заголовки для каждого устройства в targets/<device>/, размещаемые в source/src/ во время сборки, так что переключение DEVICE никогда не оставит позади заголовки предыдущего устройства
  • сборка — выбор тулчейна в source/Makefile (NDK, если он есть, иначе хост-clang против sysroot NDK) и двухэтапное правило встраивания, которое создаёт build/embed/su_daemon_aarch64_pie перед линковкой .so
  • путь su — su_daemon.c и su_blob.S побайтно идентичны warhol-root, а su_install.c — это его установщик из preload.c

Ядро эксплойта — не warhol-root. warhol-root — это popsicle, привязанный к GKI 6.12 / android16, и его generate_target.py отвергает любой другой баннер. У PMG110 — 6.6 / android15, поэтому ядро здесь — это дерево ghostlock 6.6, само являющееся потомком того же кода (kernelsnitch/utils.h и timeutils.h побайтно идентичны между двумя репозиториями) и получившее дальнейшее развитие.

Каждая строка собственно эксплойта — Write 1, Write 2, KernelSnitch, маршрут pselect — это один и тот же код в обоих деревьях.

Откуда вызывается установка su

Это единственное структурное различие, и оно обусловлено тем, что два дерева получают root по-разному.

warhol-root рутит сам процесс эксплойта и потому вызывает install_embedded_su() напрямую из run_direct_root(). Здесь Write 2 подменяет указатель cred у форкнутого дочернего процесса, а родитель остаётся непривилегированным вызывающим, поэтому дочерний процесс в child_main() — единственный контекст, который может выполнить установку, — именно там он и запускается.

Оба дерева несут одну и ту же слабую заглушку install_embedded_su() в util.c, возвращающую ENOSYS; именно сильное определение включает этот маршрут. Это стоит знать, потому что сборка, в которой по какой-то причине теряется su_install.c, по-прежнему линкуется и запускается — просто сообщает su=0/38 и ничего не устанавливает.

Сборка

root@kitploit:~
make                      # = make preload -> out/preload-<DEVICE>.so
make DEVICE=<name>        # use targets/<name>/
make devices              # list available DEVICE values
make info                 # show the selected target and the resolved toolchain

Тулчейн находится автоматически: сначала ANDROID_NDK_HOME / ANDROID_NDK_ROOT, затем обычные места установки NDK для Linux и macOS, а если ничего из этого не нашлось — хост-clang, нацеленный на sysroot NDK. Устанавливайте ANDROID_NDK_HOME только для переопределения поиска. make info выводит, что было выбрано.

Сборка двухэтапная — вот что стоит знать:

  1. su_daemon.c → build/embed/su_daemon_aarch64_pie — отдельный aarch64 PIE
  2. su_blob.S через .incbin встраивает этот бинарник в .rodata, и всё это линкуется в единый preload.so

Поэтому make clean и пересборка — единственный способ изменить встроенный su: достаточно отредактировать один su_daemon.c, зависимость объявлена, но блоб — артефакт сборки и не отслеживается.

targets/<device>/{target.h,device_offsets.h} заново размещаются в source/src/ при каждой сборке, так что устаревший заголовок от другого устройства не может быть молча подхвачен.

out/*.so не отслеживается (та же договорённость, что и в warhol-root) — клонируйте и запускайте make.

.so собирается с флагом -fvisibility=hidden и экспортирует ноль символов. Библиотека LD_PRELOAD выигрывает поиск символов для всего процесса, поэтому всё, что она экспортирует, может затенять одноимённый символ в хост-бинарнике или в libc. Этот флаг управляет только генерацией кода C, поэтому su_blob.S помечает свои два символа .hidden вручную — без этих строк границы блоба были бы единственным, что библиотека по-прежнему экспортировала.

Переменные окружения

При проверенном запуске не понадобилась ни одна из них.

Чтение лога

root@kitploit:~
[*] futex_hashsize 2048 (8 possible CPUs)
[*] ks collisions=3/3 baseline=8 threshold=10x (80) accepted=[1244..1597] slowest_rejected=N
[+] child uid = 0
[+] embedded su wrote 15304 bytes to /apex/com.android.virt/bin/su
[+] embedded su daemon ready pid=NNNN socket=/data/local/tmp/temp_su.sock daemon=/apex/com.android.virt/bin/su
[+] embedded su install ok=1 errno=0 daemon=NNNN
[+] su ready: /data/local/tmp/su and /apex/com.android.virt/bin/su
[+] ghostlock preload verdict: EXPLOIT OK

child uid = 0 — это успех эксплойта; всё, что после него, — установка. Эти два события намеренно сообщаются раздельно, как и вердикт:

Средний вариант — то различие, которое стоит иметь в виду: он говорит, что смещения в target.h верны для этой сборки, а проблема где-то в установке, а это совершенно другая вещь для отладки. su=0/38 (ENOSYS) внутри него конкретно означает, что слинковалась именно слабая заглушка.

mm_struct leak failed с последующим prepare_kernel_page retry N/24 — не сбой. Это прогресс цикла, и успешный запуск тоже показывает его. Ничего не является сбоем, пока не исчерпаны 24 попытки и не появится prepare_kernel_page timeout. Аналогично, probing cfi ... expected=9 с child uid = 2000 — это один недобранный раунд из десяти.

Не судите о запуске по усечённому логу — эта ошибка стоила здесь целого раунда неверной диагностики.

Полностью неудачный запуск — тоже норма. Гонка pselect не срабатывает в 100 % случаев: запуск может проиграть её пять раз подряд и закончиться Write 1 failed, а следующий запуск выигрывает её с первой попытки с ret=9. Наблюдалось на этом устройстве. ret=4 expected=9 — так выглядит проигрыш гонки, а не неправильный target.h — один сбой не повод заново выводить смещения. Перезапустите.

Файлы

Лицензия

Только для авторизованных исследований в области безопасности и образовательных целей.

Скачать инструмент
УстройствоOPPO PMG110 / K15 Pro+ / OP61E5L1
SoCMediaTek MT6991 (Dimensity 9500s)
Ядро6.6.118-android15-8-g93e223c276e7-abogki500782043-4k (GKI, страницы 4K)
ПрошивкаColorOS 16 / PMG110_16.0.9.400(CN01) — те же байты ядра, что и в 16.0.8.300
ОшибкаCVE-2026-43499, не исправлена в этом образе (показано дизассемблированием, а не версией)
ПутьЗачем
/apex/com.android.virt/bin/suна tmpfs, смонтированной поверх этого каталога; в PATH для root-оболочки
/data/local/tmp/suдоступен из обычного adb shell без игр с PATH
/apex/com.android.virt/bin/su в mount namespace adbdустанавливается через setns, поэтому новый adb shell его видит
ФайлПроисхождение
util.c slide.c fops.c pipe.c root.c miniadb.c common.h offset.h kernelsnitch/*ghostlock, побайтно идентично
su_daemon.c su_blob.Swarhol-root, побайтно идентично (su_blob.S добавляет две строки .hidden — см. «Сборка»)
su_install.cустановщик warhol-root из preload.c, вынесен в отдельный файл, потому что preload.c в этом дереве уже выполняет другую работу
main.cghostlock, плюс вызов su в рутированном дочернем процессе и отчёт о результате
preload.cтолько здесь — конструктор и лог с двумя приёмниками
offsets.hтолько определение структуры; запись размещается из targets/<device>/device_offsets.h
ПеременнаяДействие
GHOSTLOCK_LOGместо назначения лога (по умолчанию /data/local/tmp/.ghostlock.log); вывод идёт в stdout и в файл
GHOSTLOCK_KS_VERBOSE=1выводить адреса коллизий KernelSnitch и диапазоны прохода
GHOSTLOCK_KS_THRESHOLD=<n>переопределить множитель порога коллизий
GHOSTLOCK_MTE=1также проходить и теги указателей ядра (в 15 раз медленнее)
GHOSTLOCK_PHYS_LOAD=0x...переопределить физический адрес загрузки ядра
PSELECT_SHIFT=<n>переопределить сдвиг стекового оверлея (заменяет, а не добавляет)
ВердиктЗначение
EXPLOIT OKroot получен, su отвечает
EXPLOIT OK, SU INSTALL FAILEDWrite 1 и Write 2 сработали; сломалась только установка
EXPLOIT FAILEDзаписи не сработали
ABORTEDзапуск завершился, не успев сообщить результат, — читайте последнюю строку [!]
ПутьСодержимое
source/src/preload.cконструктор: запускает эксплойт, сообщает результат, останавливается
source/src/main.cсам эксплойт (Write 1 / Write 2)
source/src/su_daemon.cбинарник su — собирается отдельно как aarch64 PIE, не линкуется в .so
source/src/su_blob.Sчерез .incbin встраивает этот PIE в .rodata файла .so
source/src/su_install.cзаписывает блоб обратно, запускает демон, проверяет его
source/src/target.hместо размещения (игнорируется git)
targets/<device>/target.hраскладка на этапе компиляции: смещения структур, константы physmap, формы slab и futex
targets/<device>/device_offsets.hсмещения глобальных символов из kallsyms
tools/extract_device.pyboot.img → смещения, поля структур BTF, результат pselect-оверлея
tools/preloader_memlayout.pyMediaTek preloader → P0_KERNEL_PHYS_LOAD
tools/qemu_verify.pyзагружает ядро под QEMU: измеряет стековый оверлей, проверяет стабильность линейного отображения
tools/device_probe.shпредварительная проверка из непривилегированного adb shell