hacktricks/reversing-and-exploiting/linux-exploiting-basic-esp/common-binary-protections-and-bypasses/stack-canaries
2024-07-18 22:12:19 +00:00
..
bf-forked-stack-canaries.md Translated ['binary-exploitation/basic-stack-binary-exploitation-methodo 2024-07-18 22:12:19 +00:00
print-stack-canary.md Translated ['binary-exploitation/basic-stack-binary-exploitation-methodo 2024-07-18 22:12:19 +00:00
README.md Translated ['binary-exploitation/basic-stack-binary-exploitation-methodo 2024-07-18 22:12:19 +00:00

Stack Canaries

{% hint style="success" %} Impara e pratica Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Supporta HackTricks
{% endhint %}

StackGuard e StackShield

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.

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 anche 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 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 uno alla volta. 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.

Lunghezze

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.

{% hint style="danger" %} 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. {% endhint %}

Bypass

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:

{% content-ref url="bf-forked-stack-canaries.md" %} bf-forked-stack-canaries.md {% endcontent-ref %}

  • Se c'è qualche interessante fuga o vulnerabilità di lettura arbitraria nel binario potrebbe essere possibile fugare:

{% content-ref url="print-stack-canary.md" %} print-stack-canary.md {% endcontent-ref %}

  • 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:

{% content-ref url="../../stack-overflow/pointer-redirecting.md" %} pointer-redirecting.md {% endcontent-ref %}

  • Modificare sia il canary master che quello 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).

  • 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.

Riferimenti

{% hint style="success" %} Impara e pratica Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Supporta HackTricks
{% endhint %}