
CVE-2017-8570 Exp e analisi del campione di exploit
Causa: aprendo un documento Office, FLTLDR.EXE viene utilizzato per rendere un file EPS incorporato che contiene la vulnerabilità. Il file è scritto in linguaggio PostScript e può essere sfruttato da un aggressore tramite l'operazione "save-restore"; si tratta essenzialmente di una vulnerabilità UAF. La vulnerabilità può essere sfruttata quando un utente apre un file contenente un'immagine grafica malformata o quando inserisce un'immagine grafica malformata in un file Office.
Versioni interessate: Microsoft Office 2010 Service Pack 2, Microsoft Office 2013 Service Pack 1, Microsoft Office 2016
POC: kcufId's Github
L'autore ha cercato a lungo in rete senza trovare un pacchetto Office contenente EPSIMP32.FLT. Fortunatamente il collega kcufId ha fornito un LoadEps.exe per caricare file EPS; grazie kcufId.
LoadEps.exe prima carica EPSIMP32.FLT:

Poi chiama ImportGr per iniziare il caricamento del file EPS:

A questo punto premere F7 per seguire, e si può interrompere con successo sul punto di interruzione impostato all'interno di EPSIMP32.FLT.
Prima di entrare nel vivo, illustriamo la struttura dell'oggetto PostScript.
// PostScript Object
struct PostScript object
{
dword type;
dword attr;
dword value1;
dword value2; // if array, point to userdict where store the array object
}ps_obj;
I valori corrispondenti ai diversi type sono:
0x0 nulltype
0x3 integertype
0x5 realtype
0x8 booleantype
0x10 operatortype
0x20 marktype
0x40 savetype
0x300 nametype
0x500 stringtype
0x900 filetype
0x30000 arraytype
0x0B0000 packedarraytype
0x70000 packedarraytype
0x110000 dicttype
0x210000 gstatetype
Prendiamo le stringhe come esempio per illustrare la struttura di archiviazione. Impostando un punto di interruzione sulla funzione forall, è possibile visualizzare ulteriormente come viene gestita una stringa (per sapere come individuare la funzione forall, consultare https://paper.seebug.org/368/).

L'immagine 1 corrisponde a ps_obj, il cui campo value2 punta all'elemento corrispondente nell'elenco degli indici (immagine 2); l'elemento dell'indice punta a una struttura di dimensione 0x30, la cui posizione 0x24 contiene un puntatore a un puntatore a una struttura di dimensione 0x28 (immagine 5), e la posizione 0x2C contiene la dimensione della stringa (immagine 3); nella struttura dell'immagine 5, la posizione 0x4 memorizza l'indirizzo dell'elemento corrispondente nell'elenco degli indici (cioè 0x01DB5E94 dell'immagine 4), la posizione 0x20 punta alla posizione finale di archiviazione della stringa (immagine 6), e la posizione 0x24 è la dimensione effettiva della memoria occupata: dimensione della stringa + 1.
Struttura di dimensione 0x30:
+0x0 dword
+0x4 dword
+0x8 dword
+0xc dword
+0x10 dword
+0x14 dword
+0x18 dword
+0x1c dword
+0x20 dword
+0x24 dword pp_struct // puntatore a puntatore a struttura di dimensione 0x28
+0x28 dword
+0x2c dword size // dimensione effettiva della stringa
Struttura di dimensione 0x28 (per gli array, la struttura ha dimensione 0x2C e la posizione 0x28 punta agli elementi dell'array, ciascun elemento è un ps_obj):
+0x0 dword
+0x4 dword // indirizzo dell'elemento corrispondente nell'elenco degli indici
+0x8 dword
+0xc dword
+0x10 dword
+0x14 dword
+0x18 dword
+0x1c dword
+0x20 dword ptr_object // punta alla posizione finale di archiviazione della stringa
+0x24 dword size // dimensione effettiva della memoria occupata, dimensione effettiva della stringa + 1
Primo trigger della vulnerabilità:

Innanzitutto, lo stato della VM viene salvato nella variabile l62, quindi per ogni carattere della variabile l63 viene chiamato il processo l61 –>> l59 –>> l56; l62 restore ripristina lo stato precedente, in modo che lo spazio di memoria allocato per l63 dopo l'istruzione /l62 save def venga liberato, diventando un puntatore penzolante.

Le variabili l95-l99 determinano il flusso successivo e i loro valori sono tutti 0 (cioè 32 bit):

Secondo trigger della vulnerabilità: prima viene allocato spazio di memoria di dimensione 0x27 (che in realtà occuperà 0x28) per memorizzare l63:

Poi l62 restore ripristina lo stato precedente, causando la liberazione dello spazio di memoria allocato per l63, che diventa un puntatore penzolante; successivamente viene eseguito l100, e lo spazio di memoria precedentemente occupato da l63 viene utilizzato per memorizzare la struttura 0x28 della stringa l102 (cioè l136) (questo spiega perché l63 richiedeva uno spazio di memoria di dimensione 0x27):

Vengono ottenuti rispettivamente i valori nelle posizioni 0x4, 0x20 e 0x24 di questa struttura:

Infine viene modificato il contenuto della stringa l136 (l'immagine mostra solo una parte delle modifiche):

Queste modifiche sono costruite con cura e verranno utilizzate al terzo trigger della vulnerabilità.
Terzo trigger della vulnerabilità: viene allocato un array contenente 0x37 elementi, quindi durante l'iterazione al 0x34° elemento viene eseguito l62 restore:

Dopo l'esecuzione di restore, la struttura 0x30 dell'array viene sovrascritta dal contenuto della stringa l193:

In questo modo, l'oggetto eseguito nell'ultimo processo forall (0x36) diventa la struttura 0x30 dell'immagine sopra, e ottenere il suo 0x36° elemento porta alla stringa accuratamente costruita durante il secondo trigger della vulnerabilità:

L'elemento dell'array ottenuto è un array di dimensione 4, il cui primo elemento è una stringa con indirizzo iniziale 0 e dimensione 0x7FFFFFFF:

Questo array viene memorizzato nella variabile l159, e il suo primo elemento (la stringa con indirizzo iniziale 0 e dimensione 0x7FFFFFFF) viene memorizzato nella variabile l201, dopodiché è possibile ottenere il valore di qualsiasi indirizzo tramite la variabile l201.
Ottenimento della base di kernel32.dll:


In questo modo, la variabile l314 memorizza la base di EPSIMP32.FLT.

Nota: la sintassi del comando search è la seguente:

Ricerca di un gadget specifico:


Costruzione di una struttura di tipo file:
l199 l201 get_dword
/l487 exch def
l487 l201 get_dword
/l488 exch def
l488 36 my_add l201 get_dword
/l489 exch def
l489 l201 get_dword
/l490 exch def
l490 32 my_add l201 get_dword
/l491 exch def
l199 l491 l201 put_data_to_array
l199 12 my_sub 2304 l201 put_data_to_array

Scrittura dei dati costruiti all'indirizzo l492 (l491+0x32):
l492 0 l201 put_data_to_array %% 0x00 0
l492 4 my_add l375 l201 put_data_to_array %% 0x04 Indirizzo di <5E C3>
l492 8 my_add l373 l201 put_data_to_array %% 0x08 Indirizzo di <94 00 00 00 00 5E C3>
l492 12 my_add l377 l201 put_data_to_array %% 0x0C Indirizzo di <C2 0C 00>
l492 16 my_add l370 l201 put_data_to_array %% 0x10 Indirizzo di VirtualProtect()
l492 20 my_add 0 l201 put_data_to_array %% 0x14 0
l492 24 my_add 0 l201 put_data_to_array %% 0x18 0
l492 28 my_add 0 l201 put_data_to_array %% 0x1C 0
l492 32 my_add l368 l201 put_data_to_array %% 0x20 Indirizzo dello Shellcode
l492 36 my_add l368 l201 put_data_to_array %% 0x24 Indirizzo dello Shellcode——lpAddress
l492 40 my_add l349 l201 put_data_to_array %% 0x28 Dimensione dello Shellcode——dwSize
l492 44 my_add 64 l201 put_data_to_array %% 0x2C PAGE_EXECUTE_READWRITE——flNewProtect
l492 48 my_add l493 l201 put_data_to_array %% 0x30 lpflOldProtect
Infine, all'esecuzione dell'istruzione closefile, si salta allo Shellcode:

Lo script exploit EPS si trova nella directory \word\media; una volta estratto, è possibile vederlo. I campioni di sfruttamento di questa vulnerabilità sono sostanzialmente identici tranne che per la parte dello Shellcode, quindi analizziamo un campione di un'organizzazione Patchword come esempio.
Nome file: Cyber_Secure_Pakistan.docx
MD5: DD89BBB916A2C909630EC78CBB0E13E5
Salto allo Shellcode, ripristino dello stack:

Allocazione di memoria:

Ottenimento dell'indirizzo della chiamata di funzione:

Durante il debug, probabilmente a causa di problemi ambientali, l'indirizzo della chiamata di funzione CreateToolhelp32Snapshot non è stato ottenuto con successo:

Inserire manualmente l'indirizzo e aprire Word per continuare l'analisi. Enumerazione dei processi, ricerca di WINWORD.exe:

Creazione di un programma chiamato MSBuild.exe nella directory C:\ProgramData\Microsoft\DeviceSync:

Scrittura del contenuto del file, il cui contenuto è memorizzato nella variabile payload_32 dello script EPS:


Creazione del file vmtools.dll:

Scrittura del contenuto del file, il cui contenuto è memorizzato nella variabile payload_32_f2 dello script EPS:


Creazione del file VMwareCplLauncher.exe:

Il suo contenuto è memorizzato nella variabile payload_32_f1 dello script EPS:

Questo file è un file bianco con firma Vmware:

Iniezione del seguente contenuto in explorer.exe:

La sua funzione è quella di creare un processo VMwareCplLauncher.exe:

Il flusso successivo è menzionato in questo rapporto di 360; questo articolo non ne tratterà l'analisi:

I lettori interessati possono consultare ulteriormente il rapporto.
Nota: i campioni di sfruttamento di questa vulnerabilità sono sostanzialmente simili; la differenza sta nel payload finale di MSBuild.exe, memorizzato nella variabile payload_32 dello script EPS. Può essere dumpato direttamente e, dopo aver riempito l'intestazione del file DOS, può essere trascinato in IDA per l'analisi.