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

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

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

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

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

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/zzzxxxxxxxxxx/ghostlock-got-w29
Повышение привилегийАнализ уязвимостейЭксплуатацияОбратная инженерияМобильная безопасностьЭксплуатация Бинарных Файлов
GitHubzzzxxxxxxxxxx/ghostlock-got-w29

GhostLock-GOT-W29

Исследование CVE-2026-43499 (GhostLock) на HUAWEI MatePad Pro 11 GOT-W29

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

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться

CVE-2026-43499 (GhostLock) — HUAWEI MatePad Pro 11 GOT-W29

Исследование повышения привилегий для CVE-2026-43499 (rtmutex/futex-PI UAF, «GhostLock») на GOT-W29 (HarmonyOS 4.0, ядро 4.19.157-perf+).

Основные выводы:

  • Примитив записи уязвимости успешно проверен на реальном устройстве (с помощью KPM перезаписано ядро sysctl_bootid, выведен KASLR slide).
  • Но реальное повышение привилегий (shell без KPM и без RT) невозможно: путь возврата pselect в ядре 4.19 детерминированно перезаписывает слово lock в overlay, и альтернативного носителя нет. Это тупик, определяемый геометрией стека ядра, а не дефект реализации (для сравнения, устройства smt878u/popsicle можно полностью повысить привилегии, так как геометрия стека у них иная).

Устройство

ПараметрЗначение
МодельHUAWEI MatePad Pro 11 GOT-W29
SoCQualcomm kona (SM8250, Snapdragon 870)
СистемаHarmonyOS 4.0 (104.0.0.136)
Ядро4.19.157-perf+
VA39-бит, страницы 4K, KASLR включён

Уязвимость

remove_waiter() в kernel/locking/rtmutex.c в пути отката rt_mutex_start_proxy_lock() использует current вместо waiter->task для очистки, что приводит к висячему pi_blocked_on (UAF в стеке). Затрагивает 2.6.39 ~ 7.1 (данное ядро входит в диапазон). Исправление в апстриме — commit 3bfdc63936dd.

На данном устройстве подтверждено: исходный код rtmutex.c:1110-1112, декомпиляция boot.elf, срабатывание на реальном устройстве — всё проверено.

Срабатывание

Механизм срабатывания уязвимости

Создание PI-цикла, чтобы FUTEX_CMP_REQUEUE_PI вернул -EDEADLK; откат запускает баг remove_waiter, оставляя висячий pi_blocked_on (указывающий на rt_waiter в стеке ядра потока-waiter).

Почему старый триггер не работал

Старый триггер заставлял waiter самому удерживать целевой futex для requeue (self-own), что как раз попадало в раннюю проверку owner==task в task_blocks_on_rt_mutex данного ядра (boot.elf 0x3808-0x3868), возвращаясь до записи pi_blocked_on → висячий указатель никогда не создавался → размещение overlay было ошибочным диагнозом (без краха + boot_id не менялся).

Правильный триггер (PI-цикл, реализован)

PI-цикл: owner FUTEX_LOCK_PI(target) удерживает цель requeue; waiter удерживает chain futex; owner затем блокируется на chain (цикл: waiter→target→owner→chain→waiter). При requeue обход цепочки обнаруживает rt_mutex_owner(chain)==top_task → -EDEADLK → откат очищает pi_blocked_on не того потока → pi_blocked_on у waiter становится висячим. Owner должен понизить приоритет (nice=10), чтобы после boost его prio отличался от prio у owner_waiter->prio, иначе rt_mutex_waiter_equal выйдет раньше времени.

Результаты

Утечка KASLR (perf_event_open)

В shell (uid 2000) perf_event_paranoid=-1, perf_event_open(PERF_SAMPLE_IP, exclude_user=1) сэмплирует кластеры адресов текста ядра, выравнивая по известным смещениям символов для получения slide.

root@kitploit:~
samples=27651 kernel_ips=1685 lo=0xffffff948728176c hi=0xffffff9488ebfc7c
KASLR slide=0x147f200000    (40/40 IP отображены в область текста ядра, проверено)
runtime _stext=0xffffff9487280800

Инструмент: tools/perf_kaslr.c. Предусловие запуска: shell (Shizuku rish), без перехвата seccomp.

Срабатывание EDEADLK

root@kitploit:~
[M] CMP_REQUEUE_PI ret=-1 errno=35 (EDEADLK!)
[W] WAIT_REQUEUE_PI ret=-1 errno=110 (ETIMEDOUT)  ← waiter вернулся
[M] waiter_returned=1                              ← остался висячий pi_blocked_on

Инструмент: tools/edeadlk_probe.c (вариант 8+2+1 = 11 или 27).

Механизм примитива записи

rt_mutex_adjust_prio_chain step[7] выполняет rb_erase для fake waiter (путь с одним левым потомком): *(tree_left) = tree_pc + инкрементальная запись __rb_change_child. Все смещения в target.h получены дизассемблированием boot.elf.

Полные смещения

См. exploit/ghostlock-source/src/target.h. Ключевые моменты:

  • task_struct: cred=0x988, prio=0x184, pi_blocked_on=0xa90, usage=0x68, mm=0x728
  • rt_mutex_waiter (HW_FUTEX_PI): tree@0x0, pi_tree@0x18, task@0x30, lock@0x38, major@0x40, prio@0x48, deadline@0x50
  • PAGE_OFFSET=0xffffffc000000000, PHYS_OFFSET=0x80000000 (kona), KIMAGE_TEXT_BASE=0xffffff8008080000

Проверка примитива записи на реальном устройстве

Самописный KPM (tools/kpm-debug/rtmutex-dbg.c, KernelPatch 0.13.5 inline-hook) при fake walk пересоздаёт overlay (tree/task/lock) и переписывает параметр next_lock на empty_zero_page (KernelPatch _transit8 вызывает исходную функцию с изменёнными fargs), чтобы rt_mutex_adjust_prio_chain [3] next_lock==waiter->lock прошёл, [5] trylock нулевой блокировки успешен, [6] ownerless, [7] rt_mutex_dequeue (rb_erase с одним левым потомком) выполнился — sysctl_bootid перезаписан на &loggers[0][1], slide-kaslr-ok.

root@kitploit:~
REPAIR3 waiter=0xffffff801ecdbc00 lock=0xffffffa7c4950000
slide boot_id_leaked_nfulnl_logger value=ffffffa7c4612320
slide-kaslr-ok base=ffffffa7c1280000 slide=00000027b9200000

Дизайн Overlay

Геометрия стека подтверждена размерами фреймов boot.elf: в __arm64_sys_futex(0x70) + do_futex(0x60+0x1a0) rt_waiter находится на sp+0xc0 → глубина 0x1b0; в пути pselect stack_fds[0] на глубине 0x210, разница 0x60 = 12 слов. Таким образом, word_i попадает в stack_fds[12+i]: words 0-2 находятся в области ввода ex[2..4] (напрямую управляемы), words 6-7 (task/lock) — в res_in[3..4] (кодируются через in[3..4] + готовый POLLIN fd), words 3-5/8-10 остаются 0. pselect немедленно возвращается из-за готового fd → waiter в пользовательском режиме занят ожиданием (сигналы запрещены, ноль syscall), пока consumer не завершит работу.

Почему реальное повышение привилегий невозможно

1. Слово lock носителя pselect перезаписывается путём возврата

Слова task/lock overlay попадают в res_in[3]/[4] (кодируются готовностью fd). По факту res_in[4] (lock) детерминированно перезаписывается на пути возврата pselect (остатки фрейма rt_sigreturn) и никогда не равен fake_lock из payload; res_in[3] (task) иногда остаётся целым. Обход в пользовательском режиме (FP-операции + sched_yield) может лишь снизить частоту срабатывания do_notify_resume до ~21%, но перезапись lock почти неизбежна.

Ещё два связанных факта:

  • Путь ownerless заблокирован в 4.19: rt_mutex_adjust_pi() содержит if (!owner) return 0;, поэтому при отсутствии owner у fake_lock adjust_prio_chain не вызывается. В popsicle (6.12) этой проверки нет. Payload с owner перенесён (fake_lock owner=fake_task|1), но из-за неизбежной перезаписи слова lock его нельзя надёжно сработать.
  • empty_zero_page нельзя использовать как цель принудительной записи: запись в неё разрушит общую для всей системы нулевую страницу → после теста шквал oops.

2. Альтернативный носитель (ppoll) не подходит на уровне кодирования

После дизассемблирования boot.elf __arm64_sys_ppoll / do_sys_poll подтверждено: pollfd — 16-байтная структура (fd 4B + events 4B + revents 4B + pad 4B), которая не может вместить 64-битные слова task/lock fake waiter — значение fd ограничено (должен быть реальный fd), events занимает всего 4 байта и не непрерывен, revents записывается ядром (неуправляем).

3. Отличия от других устройств

smt878u / popsicle можно полностью повысить привилегии: их геометрия стека позволяет словам попадать в управляемые пользователем in/out/ex (3 fd_set pselect). У GOT-W29 позиция waiter (bits+0x60 → task/lock в res_in[3]/[4]) не имеет такого окна. Это различие в геометрии стека ядра, а не дефект реализации.

4. Ограничения обычного домена приложений

В домене приложений (untrusted_app) нет готового канала KASLR (perf/kallsyms/pagemap/dmesg — всё отклонено); CMP_REQUEUE_PI возвращает 1 (requeue успешен) и не идёт по пути отката EDEADLK; major_only в cpuset без root жёстко закорачивает step[6] обхода цепочки. Единственная точка входа для изменения QOS — /dev/iaware_qos_ctrl — заблокирована SELinux. Поэтому обычные права приложения не позволяют сработать этой CVE.

Цепочка инструментов отладки

Самописный модуль KernelPatch (rtmutex-dbg) для наблюдения на реальном устройстве за fake waiter и примитивом записи, собран на основе заголовков LyraVoid/KernelPatch 0.13.5 (того же исходника, что FolkPatch).

Набор хуков

Сборка

root@kitploit:~
cd <KernelPatch>/kpms/rtmutex-dbg
make TARGET_COMPILE=aarch64-linux-android- \
  CC=$PREFIX/bin/aarch64-linux-android-clang \
  LD=$PREFIX/bin/aarch64-linux-android-ld

Результат — rtmutex_dbg.kpm. Флаги компиляции должны включать -fno-pic -fno-pie -fno-asynchronous-unwind-tables -fno-unwind-tables (уже встроены в Makefile): clang по умолчанию использует PIC, что даёт релокации GOT, и по умолчанию генерирует .eh_frame (R_AARCH64_PREL32), а загрузчик KPM этого не поддерживает → ошибка загрузки -1.

Загрузка

Superkey у FolkPatch — su (не KernelPatch по умолчанию, как в APatch). Используйте инструмент sc_kpm_load (исходник sc_kpm_load.c):

root@kitploit:~
adb shell /data/local/tmp/sc_kpm_load su /sdcard/Download/rtmutex_dbg.kpm  # загрузка
adb shell /data/local/tmp/sc_kpm_load unload rtmutex-dbg su               # выгрузка
adb shell /data/local/tmp/sc_kpm_load ctl rtmutex-dbg counts su           # счётчики

Одношаговый тест

run_rtmdbg_test.sh (на устройстве /data/local/tmp/ghostlock-test/): запуск GhostLock от имени shell (реальный путь GOT_SLIDE_NO_RT=1), цикл синхронизации 0.5s для предотвращения потери логов, dmesg -w в файл, автоматическое завершение через 90s (SIGSTOP для предотвращения перезагрузки из-за soft-lock). Перед тестом:

root@kitploit:~
adb shell 'su -c "sh /sdcard/ghostlock-test/set_debug_no_reboot.sh"'  # предотвращение перезагрузки

Точки наблюдения (dmesg [RTMDBG])

  • REPAIR3: при проверке примитива записи пересоздание overlay и перезапись параметра next_lock
  • FAKEWALK skip: перекрытый fake walk пропущен (без записи и без краха)
  • prio_chain[N] / prio_chain_ret: вызовы обхода и возвращаемые значения (0=пройден полностью; 4294967261=-EDEADLK)
  • do_select n=320: res_in[3]/[4] на стороне ядра
  • futex op=13/14: CMP_REQUEUE_PI / WAIT_REQUEUE_PI

Полные стеки oops/panic Huawei записываются в /data/log/bbox/history.log.

Структура каталога

root@kitploit:~
tools/      инструменты проверки (perf KASLR, EDEADLK-зонд, цепочка KPM)
target/     все проверенные смещения
exploit/    перенесённый slide.c (с изменениями для срабатывания EDEADLK)

Благодарности

  • PoC в апстриме: x-spy/CVE-2026-43499-popsicle, soralis0912/CVE-2026-43499-aristotle, JoinChang/ghostlock-oneplus, Wtrwx/smt878u-ionstack-poc (GPL-3.0)
  • CVE: NVD, Red Hat RHSB-2026-010
Скачать инструмент
hookназначение
rt_mutex_adjust_piзапись корректировок PI; при перекрытии overlay — skip (очистка pi_blocked_on)
rt_mutex_adjust_prio_chainбезусловный skip при fake walk; полный дамп waiter
__arm64_sys_pselect6 / __arm64_sys_ppollочистка _TIF_WORK_MASK на пути возврата; наблюдение fd_set
do_selectчтение res_in[3]/[4] на стороне ядра
__arm64_sys_futexтрассировка WAIT_REQUEUE_PI / CMP_REQUEUE_PI
rt_mutex_dequeueподтверждение выполнения примитива записи step[7] и формы дерева