Stack Canaries
Last updated
Last updated
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
StackGuard inserisce un valore speciale noto come canary prima dell'EIP (Extended Instruction Pointer), specificamente 0x000aff0d
(che rappresenta null, newline, EOF, carriage return) per proteggere contro i buffer overflow. 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 Global Return Stack, che memorizza tutti gli indirizzi di ritorno (EIPs). Questa configurazione garantisce che qualsiasi overflow non causi danni, poiché consente un confronto tra gli indirizzi di ritorno memorizzati e quelli effettivi per rilevare le 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 elusa attraverso tecniche come Return-to-libc, ROP (Return-Oriented Programming), o ret2ret, indicando che StackShield non protegge nemmeno le variabili locali.
-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 anche in modo sicuro gli argomenti passati sullo 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 utente.
Il canary è un numero casuale derivato da /dev/urandom
o un valore predefinito di 0xff0a0000
. È memorizzato in TLS (Thread Local Storage), consentendo spazi di memoria condivisi tra i thread di avere variabili globali o statiche specifiche per il thread. Queste variabili vengono inizialmente copiate dal processo padre, e i processi figli possono alterare i loro dati senza influenzare il padre o i fratelli. Tuttavia, se un fork()
viene utilizzato senza creare un nuovo canary, tutti i processi (padre e figli) condividono lo stesso canary, rendendolo vulnerabile. Sull'architettura i386, il canary è memorizzato in gs:0x14
, e su x86_64, in fs:0x28
.
Questa protezione locale identifica le funzioni con buffer vulnerabili ad attacchi e inietta codice all'inizio di queste funzioni per posizionare il canary, e alla fine per verificarne l'integrità.
Quando un server web utilizza fork()
, abilita un attacco di forza bruta per indovinare il byte del canary byte per byte. Tuttavia, utilizzare execve()
dopo fork()
sovrascrive lo spazio di memoria, annullando l'attacco. vfork()
consente al processo figlio di eseguire senza duplicazione fino a quando non tenta di scrivere, momento in cui viene creata una duplicazione, offrendo un approccio diverso alla creazione di processi e alla gestione della memoria.
Nei binari x64
, il cookie del canary è un 0x8
byte qword. I primi sette byte sono casuali e l'ultimo byte è un byte nullo.
Nei binari x86
, il cookie del canary è un 0x4
byte dword. 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 più bassi e quindi le funzioni che leggono stringhe si fermeranno prima di leggerlo.
Fuggire il canary e poi sovrascriverlo (ad es. buffer overflow) con il proprio valore.
Se il canary è forkato nei processi figli potrebbe essere possibile brute-forzarlo un byte alla volta:
Se c'è qualche interessante leak o vulnerabilità di lettura arbitraria nel binario potrebbe essere possibile fugare:
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:
Pointer RedirectingModificare sia il canary master che il canary del thread
Un buffer overflow in una funzione thread protetta con canary può essere utilizzato per modificare il canary master del thread. Di conseguenza, la mitigazione è inutile perché il controllo viene utilizzato con due canary che sono gli stessi (anche se modificati).
Inoltre, un buffer overflow in una funzione thread 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 utilizzato con due canary che sono gli stessi (anche se modificati). Questo attacco è eseguito nella scrittura: 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 uno stack di thread viene creato è anche generato da mmap
secondo questo, il che potrebbe consentire l'overflow come mostrato nella scrittura precedente.
Modificare l'entry GOT di __stack_chk_fail
Se il binario ha Partial RELRO, allora puoi utilizzare una scrittura arbitraria per modificare l'entry GOT di __stack_chk_fail
per essere una funzione fittizia che non blocca il programma se il canary viene modificato.
Questo attacco è eseguito nella scrittura: https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)