it-swarm.dev

Stack Overflows: Sconfiggere Canarie, ASLR, DEP, NX

Per evitare overflow del buffer, sono disponibili diverse protezioni come l'utilizzo di valori di Canary, ASLR, DEP, NX. Ma dove c'è una volontà, c'è un modo. Sto studiando i vari metodi che un attaccante potrebbe eventualmente aggirare questi schemi di protezione. Sembra che non ci sia un posto in cui vengono fornite informazioni chiare. Questi sono alcuni dei miei pensieri.

Canarie - Un attaccante potrebbe capire il valore canarino e usarlo nella sua iniezione di buffer per ingannare la guardia dello stack dal rilevare un exploit

DEP, NX - Se sono presenti chiamate a VirtualAlloc(), VirtualProtect(), l'attaccante potrebbe provare a reindirizzare il codice a queste funzioni e disabilitare DEP, NX sulle pagine su cui vuole iniettare codice arbitrario.

[~ # ~] aslr [~ # ~] - Nessun indizio. Come funzionano ASLR e DEP?

86
sudhacker

Canary
I canarini dello stack funzionano modificando le regioni del prologo e dell'epilogo di ogni funzione per posizionare e controllare rispettivamente un valore nello stack. Di conseguenza, se un buffer di stack viene sovrascritto durante un'operazione di copia in memoria, l'errore viene notato prima l'esecuzione ritorna dalla funzione di copia. Quando ciò accade, viene sollevata un'eccezione, che viene ripristinata nella gerarchia del gestore delle eccezioni fino a quando non raggiunge il gestore delle eccezioni predefinito del sistema operativo. Se è possibile sovrascrivere una struttura di gestore di eccezioni esistente nello stack, è possibile farla puntare al proprio codice. Questo è un exploit per la gestione delle eccezioni strutturate (SEH) e ti consente di saltare completamente il controllo canarino.

DEP/NX
DEP e NX contrassegnano essenzialmente le strutture importanti della memoria come non eseguibili e forza eccezioni a livello hardware se si tenta di eseguire quelle aree di memoria. Ciò rende normali i buffer overflow dello stack in cui si imposta eip su esp+offset ed esegui immediatamente il tuo shellcode impossibile, perché lo stack non è eseguibile. Bypassare DEP e NX richiede un bel trucco chiamato Return-Oriented Programming .

Il POR comporta essenzialmente la ricerca di frammenti di codice esistenti dal programma (chiamati gadget) e il passaggio a essi, in modo da produrre il risultato desiderato. Poiché il codice fa parte della memoria eseguibile legittima, DEP e NX non contano. Questi gadget sono concatenati insieme tramite lo stack, che contiene il payload dell'exploit. Ogni voce nello stack corrisponde all'indirizzo del prossimo gadget ROP. Ogni gadget ha la forma di instr1; instr2; instr3; ... instrN; ret, in modo che ret salti all'indirizzo successivo nello stack dopo aver eseguito le istruzioni, concatenando così i gadget. Spesso, per completare correttamente una catena, devono essere inseriti valori aggiuntivi nello stack, a causa di istruzioni che altrimenti si frappongono.

Il trucco è mettere insieme questi ROP per chiamare una funzione di protezione della memoria come VirtualProtect, che viene quindi utilizzata per rendere eseguibile lo stack, in modo che il tuo shellcode possa essere eseguito, tramite un jmp esp o gadget equivalente. Strumenti come mona.py può essere utilizzato per generare queste catene di gadget ROP o per trovare gadget ROP in generale.

[~ ~ #] ASLR [~ ~ #]
Esistono alcuni modi per aggirare ASLR:

  • Sovrascrittura diretta RET: spesso i processi con ASLR caricheranno comunque moduli non ASLR, consentendoti di eseguire il tuo codice shell tramite un jmp esp.
  • Sovrascrivi EIP parziale: sovrascrivi solo una parte di EIP o utilizza una divulgazione di informazioni affidabili nello stack per trovare quale dovrebbe essere il vero EIP, quindi utilizzalo per calcolare il tuo obiettivo. Abbiamo comunque bisogno di un modulo non ASLR per questo.
  • Spray NOP: crea un grande blocco di NOP per aumentare le possibilità di saltare in atterraggio sulla memoria legittima. Difficile, ma possibile anche quando tutti i moduli sono abilitati per ASLR. Tuttavia, non funzionerà se DEP è attivato.
  • Bruteforce: se riesci a provare un exploit con una vulnerabilità che non causa l'arresto anomalo del programma, puoi bruteforce con 256 indirizzi target diversi fino a quando non funziona.

Lettura consigliata:

96
Polynomial

Canarie e altri volatili non impedire l'overflow; cercano solo di far fronte alle conseguenze di un trabocco che è accaduto . Il canarino tenta di rilevare il caso di un overflow che ha sovrascritto l'indirizzo di ritorno in un frame dello stack. DEP è un ulteriore passo avanti, presuppone che l'indirizzo di ritorno sia stato sovrascritto e seguito e limita le aree in cui l'esecuzione potrebbe saltare. ASLR è ancora un passo avanti: "mescola" le aree in cui è consentita l'esecuzione .

Storicamente, i buffer overflow venivano sfruttati per sovrascrivere l'indirizzo di ritorno nello stack, in modo da far saltare l'esecuzione ai dati che sono stati usati per overflow del buffer. Il canarino tenta di rilevarlo prima di saltare e DEP viene utilizzato per rendere lo spazio dello stack non eseguibile. DEP funziona anche quando overflow dei buffer nell'heap (il canarino è di alcuna utilità solo per gli overflow del buffer dello stack, ma l'heap può contenere anche buffer e anche dati sensibili da sovrascrivere, come i puntatori alle funzioni, specialmente nel contesto di = OOP linguaggi come C++). Per aggirare DEP e il canarino, gli aggressori hanno iniziato a cercare overflow che consentano di sovrascrivere i puntatori affinché funzionino, in modo da far saltare l'esecuzione codice libreria standard che è necessariamente "lì" e anche necessariamente eseguibile. Ecco perché è stato inventato ASLR: per rendere più difficili tali giochi. ASLR può ancora essere sconfitto essendo fortunato: poiché ASLR deve mantenere l'allineamento della pagina (4 kB su x86), all'interno di uno spazio di indirizzi non troppo grande (in genere meno di 2 GB su x86 a 32 bit), non ci sono così tanti posti in cui potrebbe trovarsi il codice di destinazione (al massimo mezzo milioni) A seconda del contesto di attacco e della frequenza con cui la sceneggiatura dell'attaccante può provare, questo può essere troppo basso per il massimo comfort.

Il tema importante qui è che canarini, DEP e ASLR non sconfiggono gli overflow stessi, ma prendono di mira i metodi di exploit di overflow generico che sono stati tradizionalmente impiegati. In qualsiasi applicazione, un overflow che sovrascrive i dati senza puntatore può essere letale come un exploit Shell remoto (ad esempio, immaginare un overflow che modifica un campo stringa chiamato "authenticated_user_name "). La corsa alle armi tra attaccanti e difensori sta diventando troppo specializzata e, a mio avviso, manca sempre di più il punto. Su base generale, è molto meglio non consentire mai lo straripamento, ovvero bloccare/uccidere processo/thread offensivo prima che scriva byte al di fuori del buffer di destinazione. Questo è ciò che accade con quasi tutti i linguaggi di programmazione decenti (Java, C #, VB.NET, Python , Ruby, Node.js, OCaml, PHP ... la scelta è ampia).

28
Thomas Pornin

Il livello base di protezione è ASLR + DEP.

Se non li usi entrambi, ci sono molte potenti tecniche per sfruttare un sovraccarico del buffer (ad es. Elaborazione orientata al ritorno, spruzzatura di heap, ipotesi ripetute). Ad esempio, il solo DEP può essere sconfitto usando il calcolo orientato al ritorno; e ASLR da solo può essere sconfitto usando l'heap spray e ripetuti tentativi.

Tuttavia, se il target utilizza sia ASLR + DEP, lo sfruttamento diventa significativamente più difficile. Le tecniche sopra menzionate non sono sufficienti per sconfiggere ASLR + DEP. ASLR + DEP sono come un pugno di uno o due che rendono la vita dell'attaccante molto più dura. Sconfiggere la combinazione di ASLR + DEP non è impossibile, ma richiede molta più intelligenza.

Il mio esempio preferito di metodi per sconfiggere ASLR + DEP è spiegato nel mazzo slide, Interpreter Exploitation: Pointer Inference and JIT Spraying . Lì, l'autore descrive come ha sfruttato un errore di sicurezza della memoria in Flash. Ha sfruttato le proprietà di Flash JIT per disporre la memoria in un modo che gli consente di montare un attacco di iniezione di codice, nonostante la presenza di ASLR + DEP. Ricordiamo che un JIT è un compilatore just-in-time; compila i bytecode Flash in codice nativo. Il codice nativo verrà archiviato da qualche parte nella memoria e Flash JIT lo contrassegna come eseguibile (nonostante DEP). L'autore ha trovato un modo per generare bytecode Flash che, una volta compilato, generava una sequenza di byte che incorporava il suo codice shell dannoso (compensato da un byte). Ha quindi usato tecniche di spruzzatura dell'heap per assicurarsi che ce ne fossero molte copie in memoria. Infine, ha sfruttato il bug di sicurezza della memoria per far passare il programma a un altro indirizzo; a causa di ASLR, era come saltare a un indirizzo casuale, ma le molte copie assicurarono che con grande probabilità questo sarebbe saltato nel suo shellcode. In questo modo, ha bypassato sia l'ASLR che il DEP, un'impresa elegante.

Un'ultima nota: vale la pena ricordare che ASLR è molto più efficace sulle architetture a 64 bit. Sulle architetture a 32 bit, l'ASLR può spesso essere sconfitta semplicemente facendo più tentativi. Semplicemente non ci sono abbastanza gradi di libertà su piattaforme a 32 bit per introdurre abbastanza casualità, quindi le possibilità dell'attaccante di riuscire con stupida fortuna rimangono troppo alte, su piattaforme a 32 bit. Per la difesa più efficace, utilizzare una piattaforma a 64 bit.

13
D.W.