
Analisi tecnica dettagliata e implementazione dell'exploit per CVE-2015-0057, una vulnerabilità use-after-free in win32k.sys, che copre i sistemi Windows a 32 e 64 bit da XP a 8.1.
Autore: Aaron Adams
Traduzione: 55-AA
Nota del traduttore: alcune parti sono state tradotte liberamente; per eventuali dubbi si faccia riferimento all'originale.
Terminologia:
All'inizio di quest'anno, mi sono imbattuto in una vulnerabilità interessante in win32k.sys (CVE-2015-0057) e sono riuscito a realizzare uno sfruttamento stabile su sistemi a 32 e 64 bit, con copertura da XP a Windows 8.1 (con alcune eccezioni). Questo articolo descrive in dettaglio come ho realizzato lo sfruttamento su entrambe le piattaforme, includendo alla fine alcune considerazioni aggiuntive. Viene anche descritto come realizzare lo sfruttamento con privilegi di integrità bassi su Windows 8.1 con SMEP abilitato.
L'articolo è lungo; ho cercato di fornire quanti più dettagli possibile per mostrare la complessità dello sfruttamento di questa vulnerabilità, senza nasconderli, anche se ho omesso alcuni particolari. Spero che questi dettagli siano utili a tutti.
Il 10 febbraio 2015, Microsoft ha pubblicato i dettagli di MS15-010. Questo bug è stato scoperto per primo da Udi Yavo di enSilo. Udi ha fornito un'ottima analisi sul blog breaking malware: "one bit rule-bypassing windows 10 protections using single bit". Raccomando una lettura attenta di quell'articolo per comprendere a fondo il bug, anche se in questo articolo fornirò quanti più dettagli possibile, riguardanti gli ostacoli che devono essere superati quando si attiva la vulnerabilità. Lo sfruttamento di questa vulnerabilità è molto interessante; molti dettagli provengono dal blog di Udi, e di seguito la sua dichiarazione:
Divulgazione ragionevole: sebbene questo blog sia tecnico, non riveleremo alcun codice o dettaglio completo, per impedire a qualsiasi esperto tecnico di riprodurre lo sfruttamento della vulnerabilità.
Come ricompensa aggiuntiva per lo sfruttamento di questa vulnerabilità, abbiamo ottenuto un'evoluzione Pokémon: il Pokémon Tecnico. Penso di dover dare a Udi qualche riconoscimento per aver scoperto il bug e per aver fornito nel blog la situazione correlata e i dettagli per sfruttarlo; queste informazioni sono state davvero utili.
In precedenza, non avevo mai sfruttato vulnerabilità di win32k.sys e non conoscevo le callback in modalità utente e molte API correlate, quindi ringrazio anche alcuni rinomati ricercatori di sicurezza per le risorse innovative pubblicate online, come Skywing, Tarjei Mandt, Alex Ionescu e j00ru. Queste persone hanno reso pubbliche così tante informazioni tecniche che meritano tutte lodi. Ho fatto ampio riferimento all'articolo di Tarjei Mandt Win32k.sys exploitation paper.
Mentre scrivevo lo sfruttamento di questa vulnerabilità, un eccellente reverse engineer ha realizzato uno sfruttamento stabile di CVE-2015-1701, il cui codice di esempio sulle callback in modalità utente è stato molto utile; ringrazio l'autore.
È importante notare che la mia analisi seguente è stata condotta su Windows 7, perché sembra essere l'unica versione in cui tutte le strutture in win32k.sys hanno simboli corrispondenti. La maggior parte di questi simboli è utilizzabile per le strutture di altre versioni di win32k.sys. Per qualche motivo sconosciuto, Microsoft ha rimosso questi simboli a partire da Windows 8.
Infine, voglio dire che il mio metodo di sfruttamento è piuttosto complesso. È del tutto possibile che esista un metodo più semplice che non ho scoperto. Sarei molto interessato a sentire se qualcuno ha utilizzato un approccio diverso. In ogni caso, spero che tutto ciò sia utile per lo studio delle vulnerabilità di win32k.sys.
Di seguito vediamo il bug nel disassemblato di win32k!xxxEnableWndSBArrows, un bug piuttosto sottile:
Caso senza patch:
.text:FFFFF97FFF1B157D mov r8d, r13d
.text:FFFFF97FFF1B1580 mov rdx, r14
.text:FFFFF97FFF1B1583 call xxxDrawScrollBar ; attiva callback in usermode
.text:FFFFF97FFF1B1588 jmp short loc_FFFFF97FFF1B1519
[...]
.text:FFFFF97FFF1B1519 mov eax, [rbx] ; riferimento a puntatore tagSBINFO senza controllo
.text:FFFFF97FFF1B151B mov ebp, 0FFFFFFFBh
.text:FFFFF97FFF1B1520 xor eax, esi
Nel codice sopra, Win32K!xxxDrawScrollBar può, in determinate condizioni, effettuare una callback nello spazio utente; nel codice utente, il puntatore a tagSBINFO potrebbe essere rilasciato dall'attaccante. Quando si ritorna al codice sopra, l'istruzione all'indirizzo 0xFFFFF97FFF1B1519 farà riferimento a un puntatore non valido.
Caso con patch:
.text:FFFFF97FFF1D69C3 xor r8d, r8d
.text:FFFFF97FFF1D69C6 mov rdx, rbp
.text:FFFFF97FFF1D69C9 call xxxDrawScrollBar ; attiva callback in usermode
.text:FFFFF97FFF1D69CE cmp rbx, [rdi+0B0h] ; verifica che il puntatore tagSBINFO sia corretto
---.text:FFFFF97FFF1D69D5 jz short loc_FFFFF97FFF1D69E4; se corretto, prosegue con il flusso originale
| .text:FFFFF97FFF1D69D7 mov rcx, rbp
| .text:FFFFF97FFF1D69DA call _ReleaseDC
| .text:FFFFF97FFF1D69DF jmp loc_FFFFF97FFF1D6958 ; salta all'uscita della funzione
|->.text:FFFFF97FFF1D69E4 mov eax, [rbx] ; usa il puntatore tagSBINFO corretto in sicurezza
.text:FFFFF97FFF1D69E6 xor eax, r14d
Nella versione con patch, vediamo che viene effettuato un controllo di nullità sul puntatore tagSBINFO prima di usarlo. Le informazioni sulla struttura correlata verranno fornite in seguito.
Per realizzare lo sfruttamento, abbiamo eseguito più corruzioni. In una di esse abbiamo attivato la vulnerabilità.
La radice tecnica di questo bug è un use-after-free (UAF) nell'heap del desktop. All'inizio questo mi ha confuso, poiché non conoscevo il meccanismo delle callback in modalità utente di win32k.sys e non capivo come funzionasse. Pensavo quindi che si trattasse di una race condition sui lock che portava a UAF. In realtà, i lock di quella struttura erano usati correttamente e il flusso era come previsto. In breve, la vera causa del problema è:
Tutto qui. Ignorando le callback in modalità utente, questa fase è piuttosto chiara.