Stack Canaries
Last updated
Last updated
Lernen Sie AWS-Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lernen Sie GCP-Hacking: HackTricks Training GCP Red Team Expert (GRTE)
StackGuard fügt einen speziellen Wert, bekannt als Canary, vor dem EIP (Extended Instruction Pointer) ein, speziell 0x000aff0d
(null, Zeilenumbruch, EOF, Wagenrücklauf), um sich vor Pufferüberläufen zu schützen. Funktionen wie recv()
, memcpy()
, read()
und bcopy()
bleiben jedoch anfällig, und es schützt nicht den EBP (Base Pointer).
StackShield geht mit einem Global Return Stack einen anspruchsvolleren Ansatz als StackGuard, der alle Rückgabeadressen (EIPs) speichert. Diese Einrichtung stellt sicher, dass ein Überlauf keinen Schaden verursacht, da ein Vergleich zwischen gespeicherten und tatsächlichen Rückgabeadressen erfolgt, um Überlaufvorkommen zu erkennen. Darüber hinaus kann StackShield die Rückgabeadresse gegen einen Grenzwert überprüfen, um festzustellen, ob der EIP außerhalb des erwarteten Datenspeichers zeigt. Diese Schutzmaßnahme kann jedoch durch Techniken wie Return-to-libc, ROP (Return-Oriented Programming) oder ret2ret umgangen werden, was darauf hindeutet, dass StackShield auch lokale Variablen nicht schützt.
-fstack-protector
:Dieser Mechanismus platziert einen Canary vor dem EBP und ordnet lokale Variablen so um, dass Puffer an höheren Speicheradressen positioniert werden, um ein Überschreiben anderer Variablen zu verhindern. Er kopiert auch sicher Argumente, die über den Stapel übergeben werden, über lokale Variablen und verwendet diese Kopien als Argumente. Es schützt jedoch keine Arrays mit weniger als 8 Elementen oder Puffer innerhalb einer Benutzerstruktur.
Der Canary ist eine Zufallszahl, abgeleitet von /dev/urandom
oder einem Standardwert von 0xff0a0000
. Er wird im TLS (Thread Local Storage) gespeichert, was gemeinsame Speicherbereiche über Threads hinweg ermöglicht, um threadspezifische globale oder statische Variablen zu haben. Diese Variablen werden ursprünglich vom Elternprozess kopiert, und Kindprozesse können ihre Daten ändern, ohne den Eltern- oder Geschwisterprozess zu beeinflussen. Wenn jedoch ein fork()
ohne Erstellung eines neuen Canary verwendet wird, teilen alle Prozesse (Eltern und Kinder) denselben Canary, was ihn anfällig macht. Auf der i386-Architektur wird der Canary bei gs:0x14
und auf x86_64 bei fs:0x28
gespeichert.
Dieser lokale Schutz identifiziert Funktionen mit anfälligen Puffern für Angriffe und fügt Code am Anfang dieser Funktionen ein, um den Canary zu platzieren, und am Ende, um seine Integrität zu überprüfen.
Wenn ein Webserver fork()
verwendet, ermöglicht es einen Brute-Force-Angriff, um das Canary-Byte für Byte zu erraten. Die Verwendung von execve()
nach fork()
überschreibt jedoch den Speicherbereich und hebt den Angriff auf. vfork()
ermöglicht es dem Kindprozess, ohne Duplikation auszuführen, bis er versucht zu schreiben, woraufhin eine Duplikation erstellt wird, was einen anderen Ansatz zur Prozesserstellung und Speicherbehandlung bietet.
In x64
-Binärdateien ist das Canary-Cookie ein 0x8
Byte Qword. Die ersten sieben Bytes sind zufällig und das letzte Byte ist ein Nullbyte.
In x86
-Binärdateien ist das Canary-Cookie ein 0x4
Byte Dword. Die ersten drei Bytes sind zufällig und das letzte Byte ist ein Nullbyte.
Das am wenigsten signifikante Byte beider Canaries ist ein Nullbyte, da es das erste im Stapel ist, das von niedrigeren Adressen kommt, und daher Funktionen, die Zeichenfolgen lesen, vor dem Lesen stoppen.
Lecken des Canaries und dann Überschreiben (z. B. Pufferüberlauf) mit seinem eigenen Wert.
Wenn der Canary in Kindprozessen geforkt wird, könnte es möglich sein, ihn Byte für Byte brute-force:
Wenn es eine interessante Leckstelle oder beliebige Leseanfälligkeit in der Binärdatei gibt, könnte es möglich sein, sie zu leaken:
Überschreiben von auf dem Stapel gespeicherten Zeigern
Der Stapel, der anfällig für einen Stapelüberlauf ist, könnte Adressen zu Zeichenfolgen oder Funktionen enthalten, die überschrieben werden können, um die Schwachstelle auszunutzen, ohne den Stapel-Canary erreichen zu müssen. Überprüfen Sie:
Pointer RedirectingÄndern des Master- und Thread-Canary
Ein Pufferüberlauf in einer threadgeschützten Funktion mit Canary kann verwendet werden, um den Master-Canary des Threads zu ändern. Dadurch ist die Schutzmaßnahme nutzlos, da die Überprüfung mit zwei identischen Canaries erfolgt (obwohl modifiziert).
Darüber hinaus könnte ein Pufferüberlauf in einer threadgeschützten Funktion verwendet werden, um den im TLS gespeicherten Master-Canary zu ändern. Dies liegt daran, dass es möglicherweise möglich ist, die Speicherposition zu erreichen, an der das TLS gespeichert ist (und daher der Canary) über einen bof im Stapel eines Threads. Als Ergebnis ist die Schutzmaßnahme nutzlos, da die Überprüfung mit zwei identischen Canaries erfolgt (obwohl modifiziert). Dieser Angriff wird im Write-up 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 Stapel eines Threads erstellt wird, wird er auch durch mmap
generiert, was möglicherweise den Überlauf ermöglicht, wie im vorherigen Write-up gezeigt.
Ändern des GOT-Eintrags von __stack_chk_fail
Wenn die Binärdatei Partial RELRO hat, können Sie einen beliebigen Schreibzugriff verwenden, um den GOT-Eintrag von __stack_chk_fail
zu ändern, damit er eine Dummy-Funktion ist, die das Programm nicht blockiert, wenn der Canary geändert wird.
Dieser Angriff wird im Write-up durchgeführt: https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
Lernen Sie & üben Sie AWS-Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lernen Sie & üben Sie GCP-Hacking: HackTricks Training GCP Red Team Expert (GRTE)