Stack Canaries

Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

StackGuard e StackShield

StackGuard inserisce un valore speciale noto come canary prima del EIP (Extended Instruction Pointer), specificamente 0x000aff0d (rappresentante null, newline, EOF, carriage return) per proteggersi dagli overflow di buffer. Tuttavia, funzioni come recv(), memcpy(), read(), e bcopy() rimangono vulnerabili, e non protegge l'EBP (Base Pointer).

StackShield adotta un approccio più sofisticato rispetto a StackGuard mantenendo uno Stack di Ritorno Globale, che memorizza tutti gli indirizzi di ritorno (EIP). Questa configurazione garantisce che eventuali overflow non causino danni, poiché consente di confrontare gli indirizzi di ritorno memorizzati con quelli effettivi per rilevare eventuali occorrenze di overflow. Inoltre, StackShield può controllare l'indirizzo di ritorno rispetto a un valore di confine per rilevare se l'EIP punta al di fuori dello spazio dati previsto. Tuttavia, questa protezione può essere aggirata attraverso tecniche come Return-to-libc, ROP (Return-Oriented Programming), o ret2ret, indicando che StackShield non protegge nemmeno le variabili locali.

Stack Smash Protector (ProPolice) -fstack-protector:

Questo meccanismo posiziona un canary prima dell'EBP, e riorganizza le variabili locali per posizionare i buffer a indirizzi di memoria più alti, impedendo loro di sovrascrivere altre variabili. Copia in modo sicuro gli argomenti passati nello stack sopra le variabili locali e utilizza queste copie come argomenti. Tuttavia, non protegge gli array con meno di 8 elementi o i buffer all'interno di una struttura dell'utente.

Il canary è un numero casuale derivato da /dev/urandom o un valore predefinito di 0xff0a0000. È memorizzato in TLS (Thread Local Storage), consentendo a spazi di memoria condivisi tra thread di avere variabili globali o statiche specifiche del thread. Queste variabili vengono inizialmente copiate dal processo genitore, e i processi figlio possono modificare i loro dati senza influenzare il genitore o i fratelli. Tuttavia, se viene utilizzato un fork() senza creare un nuovo canary, tutti i processi (genitore e figli) condividono lo stesso canary, rendendolo vulnerabile. Sull'architettura i386, il canary è memorizzato a gs:0x14, e su x86_64, a fs:0x28.

Questa protezione locale identifica le funzioni con buffer vulnerabili agli attacchi e inietta codice all'inizio di queste funzioni per posizionare il canary, e alla fine per verificare la sua integrità.

Quando un server web utilizza fork(), consente un attacco di forza bruta per indovinare il byte del canary uno alla volta. Tuttavia, utilizzando execve() dopo fork() sovrascrive lo spazio di memoria, annullando l'attacco. vfork() consente al processo figlio di eseguire senza duplicazione fino a quando tenta di scrivere, momento in cui viene creata una duplicazione, offrendo un approccio diverso alla creazione di processi e alla gestione della memoria.

Lunghezze

Nei binari x64, il cookie del canary è un qword di 0x8 byte. I primi sette byte sono casuali e l'ultimo byte è un byte nullo.

Nei binari x86, il cookie del canary è un dword di 0x4 byte. I primi tre byte sono casuali e l'ultimo byte è un byte nullo.

Il byte meno significativo di entrambi i canary è un byte nullo perché sarà il primo nello stack proveniente da indirizzi inferiori e quindi le funzioni che leggono stringhe si fermeranno prima di leggerlo.

Bypass

Leak del canary e quindi sovrascriverlo (ad es. overflow del buffer) con il proprio valore.

  • Se il canary è forked nei processi figlio potrebbe essere possibile forzarlo un byte alla volta:

pageBF Forked & Threaded Stack Canaries
  • Se c'è qualche leak interessante o vulnerabilità di lettura arbitraria nel binario potrebbe essere possibile effettuare un leak:

pagePrint Stack Canary
  • Sovrascrivere i puntatori memorizzati nello stack

Lo stack vulnerabile a un overflow dello stack potrebbe contenere indirizzi a stringhe o funzioni che possono essere sovrascritti per sfruttare la vulnerabilità senza dover raggiungere il canary dello stack. Controlla:

pagePointer Redirecting
  • Modificare sia il canary master che il canary del thread

Un buffer overflow in una funzione thread-safe protetta con canary può essere utilizzato per modificare il canary master del thread. Di conseguenza, la mitigazione è inutile perché il controllo viene effettuato con due canary che sono gli stessi (anche se modificati).

Inoltre, un buffer overflow in una funzione thread-safe protetta con canary potrebbe essere utilizzato per modificare il canary master memorizzato nel TLS. Questo perché potrebbe essere possibile raggiungere la posizione di memoria in cui è memorizzato il TLS (e quindi il canary) tramite un bof nello stack di un thread. Di conseguenza, la mitigazione è inutile perché il controllo viene effettuato con due canary che sono gli stessi (anche se modificati). Questo attacco è eseguito nella spiegazione: http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads

Controlla anche la presentazione di https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015 che menziona che di solito il TLS è memorizzato da mmap e quando viene creato uno stack di thread viene generato anche da mmap secondo questo, che potrebbe consentire l'overflow come mostrato nella spiegazione precedente.

  • Modificare l'entry GOT di __stack_chk_fail

Se il binario ha Partial RELRO, allora è possibile utilizzare una scrittura arbitraria per modificare l'entry GOT di __stack_chk_fail in una funzione fittizia che non blocca il programma se il canary viene modificato.

Questo attacco è eseguito nella spiegazione: https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/

Riferimenti

Impara l'hacking su AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated