Una tipica strategia per sconfiggere ASLR consiste nel trovare sia un bug di overflow del buffer che un bug di divulgazione delle informazioni. Ma quando si attaccano server che vengono riavviati automaticamente ogni volta che si arrestano / muoiono, è sufficiente un bug di overflow del buffer? Possiamo usare quel bug di overflow del buffer per darci anche la capacità di divulgazione delle informazioni?
Permettimi di arricchire lo scenario. Supponiamo che abbia un programma server che elabora una richiesta dalla rete e che verrà automaticamente riavviato in caso di arresto anomalo e supponiamo di aver trovato una vulnerabilità di sovraccarico del buffer (di un buffer allocata nell'heap B
) nel server che posso sfruttare in modo affidabile inviando una richiesta appropriatamente predisposta al server. Supponiamo anche di poter rilevare quando il server si arresta in modo anomalo (ad esempio, potrebbe bloccarsi perché gli ho inviato una richiesta che ha danneggiato la memoria e causato la segfault; in ogni caso, suppongo di poter inviare una richiesta di mia scelta e determinare se si è bloccato o meno durante il tentativo di gestire tale richiesta). Il server sta usando ASLR e voglio derandomizzare ASLR in modo da poter montare un attacco per l'iniezione di codice, ma non conosco un bug di divulgazione delle informazioni separato - la vulnerabilità di sovraccarico del buffer è tutto ciò con cui devo lavorare.
Posso utilizzare questa vulnerabilità di sovraccarico del buffer per la divulgazione di informazioni, per apprendere il contenuto della memoria dopo B
?
Ecco un esempio del tipo di attacco che sto immaginando:
Suppose that the overflowable buffer
B
is 512 bytes long, and suppose there is a secret 8-byte pointerP
stored immediately afterB
. Suppose field F of the request is copied byte-for-byte overB
without any length check.If I send a request with a 513-byte value for F, that'll be copied over
B
. If the 513th byte of my value differs from the first byte ofP
, then the value ofP
will be corrupted, and (assuming the program later dereferencesP
) then program will probably crash during processing of this request. On the other hand, if the 513 byte of my value matches the first byte ofP
, thenP
will remain unchanged, and the program will probably not crash.So, I can imagine sending 256 requests, each with a different value for the 513th byte of field F; if 255 of them cause the server to crash and one does not, then I immediately know the value of the first byte of
P
. Now I can continue until I learn each of the bytes ofP
. This might be useful if the program is using ASLR: by learning the value of the pointerP
, I can derandomize part of memory.
Questo è solo un semplice esempio. In pratica, immagino che ci possa essere spazio inutilizzato dopo la fine di B
e prima del prossimo oggetto archiviato nell'heap, ma puoi immaginare modi per adattare queste tecniche per gestire anche quella situazione (ad esempio, se il byte dopo che B
non è stato utilizzato, puoi sovrascriverlo con qualsiasi cosa e il server non si arresta in modo anomalo, quindi è facile rilevare posizioni non utilizzate e continuare l'attacco fino a trovare l'oggetto successivo dopo B
).
Questo attacco funziona in pratica? Fornisce un modo efficace per sconfiggere ASLR, quando si verifica un overflow dell'heap in un server che viene riavviato automaticamente e quando si ha un modo per rilevare gli arresti anomali?
Ci sono degli ostacoli che ho trascurato che impediscono il corretto funzionamento? Per esempio, posso immaginare che se l'allocazione di memoria per gli oggetti nell'heap fosse non deterministica e casuale, l'attacco fallirebbe; ma le piattaforme lo fanno? Gli offset relativi tra gli oggetti nell'heap deterministico in pratica, se si esegue lo stesso programma due volte sugli stessi ingressi?
Suppongo che l'overflow del buffer consenta di sovrascrivere B
con dati binari arbitrari totalmente sotto il controllo dell'attaccante. (L'attacco non funzionerà con un strcpy()
o un overflow legato alla stringa, dal momento che i dati sono forzati ad essere nul-terminati.) Inoltre, supponiamo che il server sia riavviato usando fork (), o per qualche altra ragione, parte del layout della memoria è la stessa ogni volta che il server viene riavviato. (Ad esempio, questo si mantiene automaticamente su Windows e Mac, dal momento che le librerie si trovano allo stesso indirizzo di base ogni volta che si riavvia il server, e mantiene i processi non PIE su Linux.)
Credito: mi ispiro a un metodo di cui ho letto di recente per sfruttare un bug di overflow del buffer di un buffer allocato allo stack ai fini della divulgazione di informazioni. Questo è stato descritto nel documento Blind ROP pubblicato di recente su IEEE Security & Privacy 2014. Mostrano come farlo quando il buffer B
è allocato nello stack. In questa domanda, sto chiedendo se la loro tecnica può essere generalizzata al caso in cui il buffer B
è nell'heap.