Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-98937 — PoC verificato e analisi per un bypass del controllo dei permessi in perf/core di Linux che espone gli indirizzi della callchain del kernel a task Android non privilegiati, consentendo la derivazione dello slide KASLR. | Kitploit
Strumenti/GitHubGitHub/woshigenm/cve-2026-98937
Sicurezza AndroidEscalation di PrivilegiAnalisi delle VulnerabilitàExploitRaccolta InformazioniPaper e Ricerca
GitHubwoshigenm/cve-2026-98937

CVE-2026-98937

PoC verificato e analisi per un bypass del controllo dei permessi in perf/core di Linux che espone gli indirizzi della callchain del kernel a task Android non privilegiati, consentendo la derivazione dello slide KASLR.

Vedi Repository
424 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2026-98937 — bypass dei permessi per le callchain del kernel perf

English | 简体中文

Bypass del controllo dei permessi in perf/core di Linux: un task non privilegiato può richiedere le callchain del kernel impostando exclude_kernel=1, aggirando il gate perf_allow_kernel() e divulgando i frame dello stack del kernel tramite il ring buffer di perf. Questo repository contiene l'analisi e un PoC verificato; il bug consente una fuga di informazioni, non una primitiva diretta di escalation dei privilegi.

Stato

VoceValore
CVECVE-2026-98937
ClasseBypass dei permessi / divulgazione di informazioni (CWE-284/CWE-269)
TargetAndroid arm64 (verificato su HONOR YLP-W00 e Redmi K70)
KernelYLP-W00: 6.12.38-android16-5-gfde7767f6ef6-abogki481467632-4k; K70: 5.15.178-android13-8-00021-g6f2f96be86b9-ab13729987
SELinuxEnforcing (u:r:shell:s0)
CorrettoNo; corretto upstream in 6.12.113 / 6.18.56 / 7.2.10 / 7.3+
StatoPoC verificato; oracolo per lo slide KASLR convalidato su 6.12.38 e 5.15.178
Pre-checksrc/vuln_precheck.h

Versioni interessate

I kernel precedenti alla correzione seguente sono interessati. Corretto da a4b016d0a29038a5b7c96bf62c054bf7832451d9 ("perf/core: Check kernel access when kernel callchains are requested", Dapeng Mi, unito il 2026-06-30) e dai corrispondenti backport stabili.

Causa principale

perf_event_open() controllava il profiling del kernel solo in base a !attr.exclude_kernel:

if (!attr.exclude_kernel) {
        err = perf_allow_kernel(&attr);
        if (err)
                return err;
}

perf_allow_kernel() contiene sia il controllo perf_event_paranoid > 1 sia l'hook SELinux perf_event { kernel }. Un task può impostare exclude_kernel=1 pur richiedendo comunque le callchain del kernel (PERF_SAMPLE_CALLCHAIN con exclude_callchain_kernel=0); perf_callchain() raccoglie quindi la parte del kernel indipendentemente dal filtro di campionamento. Gli eventi PMU hardware che contano solo la modalità utente possono ricevere il proprio interrupt di overflow in contesto kernel (skid), quindi perf_callchain_kernel() esegue l'unwinding dello stack del kernel e scrive gli indirizzi del testo del kernel nel ring buffer.

La correzione chiama perf_allow_kernel() quando viene richiesto il campionamento del kernel o le callchain del kernel:

if (!attr.exclude_kernel ||
    ((attr.sample_type & PERF_SAMPLE_CALLCHAIN) &&
     !attr.exclude_callchain_kernel)) {
        err = perf_allow_kernel();
        if (err)
                return err;
}

Lo snippet sopra è la forma del ramo stabile 6.12.113, in cui perf_allow_kernel() non accetta più un puntatore ad attributo; il commit upstream usa la stessa condizione con perf_allow_kernel(&attr).

Vedi docs/analysis.md per il percorso di chiamata completo, la meccanica dello skid, le evidenze di audit SELinux e le misurazioni sul dispositivo.

Progettazione della verifica

Il PoC esegue tre casi come processo shell non privilegiato:

Casoattributi perf_eventAtteso su un kernel vulnerabile
Aexclude_kernel=0EACCES (gate kernel-perf attivo)
Bexclude_kernel=1, exclude_callchain_kernel=1evento consentito, nessun frame di callchain del kernel
Cexclude_kernel=1, exclude_callchain_kernel=0evento consentito, frame di callchain del kernel divulgati

Sul dispositivo verificato YLP-W00 (kernel 6.12.38, SELinux Enforcing):

  • Caso A: EACCES, con avc: denied { kernel } ... tclass=perf_event nel log di audit.
  • Caso B: evento aperto, 0 voci di callchain del kernel.
  • Caso C: evento aperto, ~179k campioni con contesto kernel e ~537k indirizzi di callchain del kernel (3 frame per campione), tutti nell'intervallo kernel 0xffffffde....

Sul dispositivo verificato Redmi K70 (kernel 5.15.178, ROM Android 17 di terze parti, SELinux Enforcing), è stato osservato lo stesso schema:

  • Caso A: EACCES, stessa riga di audit SELinux { kernel }.
  • Caso B: evento aperto, 0 voci di callchain del kernel.
  • Caso C: evento aperto; 14.090 indirizzi di callchain del kernel in 2.432 campioni a periodo 1000, e 5.049 in 876 campioni a periodo 5000, nell'intervallo kernel 0xffffffdd....

Sui dispositivi verificati, un kernel corretto rifiuterebbe il caso C a perf_event_open() con EACCES poiché la richiesta di callchain del kernel ora raggiunge perf_allow_kernel().

Derivazione dello slide KASLR

Con un vmlinux corrispondente, i frame di callchain divulgati diventano un oracolo dello slide KASLR per ogni avvio. Lo slide virtuale arm64 è allineato a 2 MiB, e ogni indirizzo di testo divulgato deve soddisfare _stext <= addr - slide < _etext; intersecando tali intervalli normalmente rimane esattamente uno slide.

make slide \
  SLIDE_VMLINUX=/path/to/vmlinux-6.12.38.elf \
  SLIDE_LINK_BASE=0xffffffc080000000 \
  SLIDE_LOG=logs/poc-ylp-w00-20261027-020133-period1000.log

Sul boot YLP-W00 6.12.38 verificato, tre frame forniscono lo slide=0x1DCFC00000 univoco (runtime _text=0xffffffde4fc00000):

Indirizzo divulgatoIndirizzo link-timeSimbolo
0xffffffde50748c780xffffffc080b48c78local_daif_restore+0x4 (msr DAIF, x0; ret)
0xffffffde50d406e00xffffffc0811406e0el0t_64_sync_handler+0x70 (dopo bl el0_svc)
0xffffffde4fc115880xffffffc080011588el0t_64_sync+0x1a8 (dopo bl el0t_64_sync_handler)

Questi sono frame di testo del kernel core, non moduli: l'interrupt PMU in sospeso viene consegnato esattamente al ret dopo msr DAIF, x0 nel percorso di ingresso della syscall. Gli indirizzi grezzi non possono essere simbolizzati direttamente sotto KASLR; sottrarre prima lo slide. Se un frame è un indirizzo di modulo, nessuno slide colloca tutti gli indirizzi in [_stext, _etext) e lo script lo segnala invece di tirare a indovinare. Lo slide cambia a ogni avvio e non deve essere memorizzato tra riavvii.

Anche il Redmi K70 (5.15.178) è stato validato. La sua immagine corrispondente è stata estratta da /sdcard/boot.img (boot v4; la stringa di versione incorporata corrisponde al kernel in esecuzione) e vmlinux-to-elf ha recuperato 158.668 simboli. Sette frame univoci da una singola esecuzione con periodo 1000 forniscono slide=0x1D93800000 (runtime _text=0xffffffdd9b800000), mappando su syscall_trace_enter, el0_svc_common, do_el0_svc, el0_svc, el0t_64_sync_handler, el0t_64_sync e syscall_trace_exit.

La base link-time è specifica del branch — non riutilizzare il valore 6.12 su 5.15:

Branch del kernelKIMAGE_VADDR
Android 13-5.15 (K70)0xffffffc008000000
Android 16-6.12 (YLP-W00)0xffffffc080000000
upstream v5.15 (layout diverso)0xffffffc010000000

vmlinux-to-elf ha rilevato automaticamente 0xffffffc008000000 per l'immagine del K70, corrispondente ad AOSP android13-5.15. Se la base ELF rilevata automaticamente differisce dal KIMAGE_VADDR del branch, passare --link-base (o SLIDE_LINK_BASE=): la simbolizzazione resta nello spazio ELF, lo slide riportato viene reso relativo alla base reale, e il runtime _text è invariante rispetto a uno spostamento costante della base. Fornire il leak del K70 all'immagine 6.12.38 resta un test negativo deliberato e non produce alcun candidato.

Build

Requisiti:

  • Android NDK r29 in /opt/android-ndk-r29 (sovrascrivere con NDK=)
  • GNU make
  • adb
make                 # PoC, arm64, API 24
make ARCH=arm API=29 # other ABI / API level
make host            # static build for qemu-aarch64
make emu             # build and run the static PoC locally
make help

Gli artefatti vengono scritti in build/ e sono ignorati da git.

Utilizzo

Scarica lo strumento