Stack Canaries
Reading time: 6 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
StackGuard und StackShield
StackGuard fügt einen speziellen Wert, bekannt als canary, vor dem EIP (Extended Instruction Pointer) ein, speziell 0x000aff0d
(repräsentiert null, newline, EOF, carriage return), um gegen Bufferüberläufe zu schützen. Funktionen wie recv()
, memcpy()
, read()
und bcopy()
bleiben jedoch anfällig, und es schützt nicht den EBP (Base Pointer).
StackShield verfolgt einen ausgefeilteren Ansatz als StackGuard, indem es einen Global Return Stack beibehält, der alle Rücksprungadressen (EIPs) speichert. Diese Einrichtung stellt sicher, dass ein Überlauf keinen Schaden anrichtet, da sie einen Vergleich zwischen gespeicherten und tatsächlichen Rücksprungadressen ermöglicht, um Überlaufereignisse zu erkennen. Darüber hinaus kann StackShield die Rücksprungadresse mit einem Grenzwert vergleichen, um zu erkennen, ob der EIP außerhalb des erwarteten Datenraums zeigt. Diese Schutzmaßnahme kann jedoch durch Techniken wie Return-to-libc, ROP (Return-Oriented Programming) oder ret2ret umgangen werden, was darauf hinweist, dass StackShield auch keine lokalen Variablen schützt.
Stack Smash Protector (ProPolice) -fstack-protector
:
Dieser Mechanismus platziert einen canary vor dem EBP und reorganisiert lokale Variablen, um Puffer an höheren Speicheradressen zu positionieren, sodass sie andere Variablen nicht überschreiben. Er kopiert auch sicher die Argumente, die auf dem Stack über lokalen Variablen übergeben werden, und verwendet diese Kopien als Argumente. Allerdings schützt er keine Arrays mit weniger als 8 Elementen oder Puffer innerhalb einer Benutzerstruktur.
Der canary ist eine Zufallszahl, die aus /dev/urandom
oder einem Standardwert von 0xff0a0000
abgeleitet wird. Er wird in TLS (Thread Local Storage) gespeichert, sodass gemeinsame Speicherbereiche über Threads hinweg thread-spezifische globale oder statische Variablen haben. Diese Variablen werden zunächst vom übergeordneten Prozess kopiert, und untergeordnete Prozesse können ihre Daten ändern, ohne den übergeordneten oder Geschwisterprozesse zu beeinflussen. Wenn jedoch ein fork()
ohne Erstellung eines neuen canary verwendet wird, teilen sich alle Prozesse (Eltern und Kinder) denselben canary, was ihn anfällig macht. Auf der i386-Architektur wird der canary bei gs:0x14
gespeichert, und auf x86_64 bei fs:0x28
.
Dieser lokale Schutz identifiziert Funktionen mit Puffern, die anfällig für Angriffe sind, und injiziert Code am Anfang dieser Funktionen, um den canary zu platzieren, und am Ende, um seine Integrität zu überprüfen.
Wenn ein Webserver fork()
verwendet, ermöglicht dies einen Brute-Force-Angriff, um den canary Byte für Byte zu erraten. Die Verwendung von execve()
nach fork()
überschreibt jedoch den Speicherbereich und macht den Angriff zunichte. vfork()
ermöglicht es dem untergeordneten Prozess, ohne Duplikation auszuführen, bis er versucht zu schreiben, an welchem Punkt ein Duplikat erstellt wird, was einen anderen Ansatz zur Prozessgenerierung und Speicherverwaltung bietet.
Längen
In x64
-Binaries ist das canary-Cookie ein 0x8
Byte qword. Die ersten sieben Bytes sind zufällig und das letzte Byte ist ein null Byte.
In x86
-Binaries ist das canary-Cookie ein 0x4
Byte dword. Die ersten drei Bytes sind zufällig und das letzte Byte ist ein null Byte.
caution
Das am wenigsten signifikante Byte beider canaries ist ein null Byte, da es das erste im Stack ist, das von niedrigeren Adressen kommt, und daher werden Funktionen, die Strings lesen, stoppen, bevor sie es lesen.
Umgehungen
Den canary auslesen und dann mit seinem eigenen Wert überschreiben (z.B. Bufferüberlauf).
- Wenn der canary in untergeordneten Prozessen geforkt wird, könnte es möglich sein, ihn byteweise zu brute-forcen:
BF Forked & Threaded Stack Canaries
- Wenn es eine interessante Leck- oder willkürliche Leseanfälligkeit im Binary gibt, könnte es möglich sein, ihn auszulesen:
- Überschreiben von im Stack gespeicherten Zeigern
Der Stack, der anfällig für einen Stacküberlauf ist, könnte Adressen zu Strings oder Funktionen enthalten, die überschrieben werden können, um die Anfälligkeit auszunutzen, ohne den Stack-Canary erreichen zu müssen. Überprüfen Sie:
- Ändern sowohl des Master- als auch des Thread-Canary
Ein Buffer Überlauf in einer threaded Funktion, die mit einem Canary geschützt ist, kann verwendet werden, um den Master-Canary des Threads zu ändern. Infolgedessen ist die Minderung nutzlos, da die Überprüfung mit zwei Canaries verwendet wird, die gleich sind (obwohl modifiziert).
Darüber hinaus könnte ein Buffer Überlauf in einer threaded Funktion, die mit einem Canary geschützt ist, verwendet werden, um den Master-Canary, der im TLS gespeichert ist, zu ändern. Dies liegt daran, dass es möglich sein könnte, die Speicherposition zu erreichen, an der das TLS gespeichert ist (und daher der canary) über einen bof im Stack eines Threads.
Infolgedessen ist die Minderung nutzlos, da die Überprüfung mit zwei Canaries verwendet wird, die gleich sind (obwohl modifiziert).
Dieser Angriff wird in dem Writeup durchgeführt: http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
Überprüfen Sie auch die Präsentation von https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015, die erwähnt, dass normalerweise das TLS durch mmap
gespeichert wird und wenn ein Stack eines Threads erstellt wird, es auch durch mmap
generiert wird, was den Überlauf ermöglichen könnte, wie im vorherigen Writeup gezeigt.
- Ändern des GOT-Eintrags von
__stack_chk_fail
Wenn das Binary Partial RELRO hat, können Sie einen willkürlichen Schreibvorgang verwenden, um den GOT-Eintrag von __stack_chk_fail
in eine Dummy-Funktion zu ändern, die das Programm nicht blockiert, wenn der canary geändert wird.
Dieser Angriff wird in dem Writeup durchgeführt: https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
Referenzen
- https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html
- http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
- https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.