
Exploit proof-of-concept LPE per Android Binder UAF che sfrutta iovec spraying e addr_limit overwrite per ottenere lettura/scrittura arbitraria del kernel.
Un exploit Proof-of-Concept / Escalation locale dei privilegi (LPE) riscritto che ha come bersaglio CVE-2019-2215, una vulnerabilità Use-After-Free nel driver Binder di Android.
Ho fornito la build del kernel vulnerabile nella cartella vulnerable_kernel_builds. Crea un emulatore AOSP di Android 10 ed esegui il kernel con esso
emulator -show-kernel -no-window -no-snapshot -wipe-data -avd research -kernel bzImage
Per i dettagli tecnici del bug puoi consultare questo fantastico blog https://projectzero.google/2019/11/bad-binder-android-in-wild-exploit.html
La struttura task_struct ha un membro importante, addr_limit, di tipo mm_segment_t. addr_limit memorizza l'indirizzo di spazio utente valido più alto. addr_limit fa parte di struct thread_info o struct thread_struct a seconda dell'architettura di destinazione. Dato che ora abbiamo a che fare con un sistema x86_64 a 64 bit, addr_limit è definito in struct thread_struct.

Se riusciamo a sovrascrivere questo addr_limit con 0xFFFFFFFFFFFFFFFF, saremo in grado di leggere e scrivere in qualsiasi parte della memoria dello spazio kernel. Per una migliore compatibilità dell'exploit su x86_64 e arm64, è meglio impostare addr_limit a 0xFFFFFFFFFFFFFFFE
struct iovec è usata per Vectored I/O, nota anche come Scatter/Gather I/O. Uno dei problemi principali di struct iovec è la loro breve durata. Le system call le allocano quando lavorano con i buffer e le liberano immediatamente quando ritornano alla modalità utente.
Vogliamo che la struttura iovec rimanga nel kernel quando inneschiamo l'operazione di unlink e sovrascriviamo il puntatore iov_base con l'indirizzo di binder_thread->wait.head per ottenere una lettura e scrittura con scope limitato. Un modo è usare system call come readv, writev su un file descriptor di tipo pipe, perché può bloccarsi se la pipe è piena o vuota. Una pipe è un canale di dati unidirezionale che può essere usato per la comunicazione tra processi. La caratteristica di blocco della pipe ci offre una finestra temporale significativa per corrompere la struttura iovec nello spazio kernel.
Allo stesso modo possiamo usare la system call recvmsg per bloccarla passando MSG_WAITALL come parametro flag.
Poiché la dimensione della struttura binder_thread è di 408 byte, finirà nella cache kmalloc-512.

dovremo impilare 25 strutture iovec per riallocare il chunk pendente. 408 / 16 = 25.5

Come possiamo vedere dall'immagine sopra, iovecStack[10].iov_len e iovecStack[11].iov_base verranno sovrascritti.

Quindi, vorremmo elaborare iovecStack[10], bloccare la system call writev e poi innescare l'operazione di unlink. In questo modo garantiamo che, quando iovecStack[11].iov_base viene sovrascritto, riprenderemo la system call writev. Infine, facciamo leak del contenuto del chunk binder_thread riportandolo nello spazio utente e da esso leggiamo il puntatore a task_struct.

Per ottenere una write con scope limitato, useremo la system call recvmsg per bloccarla passando MSG_WAITALL come parametro flag. La system call recvmsg può bloccarsi proprio come la system call writev.

Poiché la dimensione di mm_segment_t è di 0x8 byte, vorremmo sovrascriverlo con 0xFFFFFFFFFFFFFFFE, poiché è l'indirizzo valido più alto dello spazio kernel e non farà crashare il processo se si verifica un page fault su un sistema arm64.

