Libc Protections
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)
Malloc alloziert Speicher in 8-Byte (32-Bit) oder 16-Byte (64-Bit) Gruppierungen. Dies bedeutet, dass das Ende von Chunks in 32-Bit-Systemen mit 0x8 und in 64-Bit-Systemen mit 0x0 ausgerichtet sein sollte. Das Sicherheitsmerkmal überprüft, ob jeder Chunk korrekt an diesen spezifischen Positionen ausgerichtet ist, bevor ein Zeiger aus einem Bin verwendet wird.
Die Durchsetzung der Chunk-Ausrichtung in 64-Bit-Systemen verbessert die Sicherheit von Malloc erheblich, indem sie die Platzierung von Fake-Chunks auf nur 1 von 16 Adressen beschränkt. Dies erschwert Exploitationsversuche erheblich, insbesondere in Szenarien, in denen der Benutzer nur begrenzte Kontrolle über Eingabewerte hat, was Angriffe komplexer und schwieriger ausführbar macht.
Fastbin-Angriff auf __malloc_hook
Die neuen Ausrichtungsregeln in Malloc vereiteln auch einen klassischen Angriff, der den __malloc_hook
betrifft. Früher konnten Angreifer Chunk-Größen manipulieren, um diesen Funktionszeiger zu überschreiben und Codeausführung zu erlangen. Die strikten Ausrichtungsanforderungen stellen nun sicher, dass solche Manipulationen nicht mehr möglich sind, was einen häufigen Ausbeutungsweg schließt und die Gesamtsicherheit verbessert.
Zeigermanipulation ist eine Sicherheitsverbesserung, die dazu dient, Fastbin- und Tcache-Fd-Zeiger bei Speicherverwaltungsvorgängen zu schützen. Diese Technik hilft, bestimmte Arten von Speicher-Exploit-Taktiken zu verhindern, insbesondere solche, die keine durchgesickerten Speicherinformationen erfordern oder die Speicherpositionen direkt relativ zu bekannten Positionen manipulieren (relative Überschreibungen).
Der Kern dieser Technik ist eine Verschleierungsformel:
Neuer_Ptr = (L >> 12) XOR P
L ist der Speicherort des Zeigers.
P ist der tatsächliche Fastbin/Tcache-Fd-Zeiger.
Der Grund für die bitweise Verschiebung des Speicherorts (L) um 12 Bits nach rechts vor der XOR-Operation ist entscheidend. Diese Manipulation behebt eine Schwachstelle, die in der deterministischen Natur der am wenigsten signifikanten 12 Bits von Speicheradressen liegt, die aufgrund von Systemarchitektur-Einschränkungen typischerweise vorhersehbar sind. Durch Verschieben der Bits wird der vorhersehbare Teil aus der Gleichung entfernt, die Zufälligkeit des neuen, verschleierten Zeigers verbessert und damit gegen Angriffe geschützt, die auf der Vorhersagbarkeit dieser Bits beruhen.
Dieser verschleierte Zeiger nutzt die bereits vorhandene Zufälligkeit von Address Space Layout Randomization (ASLR), die Adressen, die von Programmen verwendet werden, zufällig macht, um es Angreifern zu erschweren, das Speicherlayout eines Prozesses vorherzusagen.
Das Entschleiern des Zeigers, um die ursprüngliche Adresse abzurufen, beinhaltet die Verwendung derselben XOR-Operation. Hier wird der verschleierte Zeiger als P in der Formel behandelt, und wenn er mit dem unveränderten Speicherort (L) XOR-verknüpft wird, wird der ursprüngliche Zeiger offengelegt. Diese Symmetrie beim Verschleiern und Entschleiern gewährleistet, dass das System Zeiger effizient codieren und decodieren kann, ohne signifikante Overheads zu verursachen, und die Sicherheit gegen Angriffe, die Speicherzeiger manipulieren, erheblich erhöht.
Die Zeigerverschleierung zielt darauf ab, partielle und vollständige Zeigerüberschreibungen im Heap-Management zu verhindern, was eine erhebliche Sicherheitsverbesserung darstellt. Diese Funktion beeinflusst Exploit-Techniken auf verschiedene Weise:
Verhinderung von Bye-Byte-Relativen Überschreibungen: Früher konnten Angreifer einen Teil eines Zeigers ändern, um Heap-Chunks zu verschiedenen Positionen umzuleiten, ohne genaue Adressen zu kennen, eine Technik, die im leckfreien House of Roman-Exploit offensichtlich ist. Mit der Zeigerverschleierung erfordern solche relativen Überschreibungen ohne ein Heap-Leck jetzt Brute-Force, was ihre Erfolgschancen drastisch reduziert.
Erhöhte Schwierigkeit von Tcache-Bin/Fastbin-Angriffen: Häufige Angriffe, die Funktionszeiger (wie __malloc_hook
) überschreiben, indem sie Fastbin- oder Tcache-Einträge manipulieren, werden behindert. Zum Beispiel könnte ein Angriff das Offenlegen einer LibC-Adresse, das Freigeben eines Chunks in den Tcache-Bin und das Überschreiben des Fd-Zeigers beinhalten, um ihn auf __malloc_hook
umzuleiten, um beliebigen Code auszuführen. Mit der Zeigerverschleierung müssen diese Zeiger korrekt verschleiert sein, was ein Heap-Leck für eine genaue Manipulation erforderlich macht, wodurch die Ausbeutungshürde erhöht wird.
Erfordernis von Heap-Lecks an Nicht-Heap-Positionen: Das Erstellen eines Fake-Chunks in Nicht-Heap-Bereichen (wie dem Stack, dem .bss-Abschnitt oder PLT/GOT) erfordert jetzt ebenfalls ein Heap-Leck aufgrund der Notwendigkeit der Zeigerverschleierung. Dies erhöht die Komplexität bei der Ausnutzung dieser Bereiche, ähnlich der Anforderung an die Manipulation von LibC-Adressen.
Das Offenlegen von Heap-Adressen wird schwieriger: Die Zeigerverschleierung beschränkt die Nützlichkeit von Fd-Zeigern in Fastbin- und Tcache-Bins als Quellen für Heap-Adresslecks. Zeiger in unsortierten, kleinen und großen Bins bleiben jedoch unverschleiert und sind daher weiterhin für das Offenlegen von Adressen verwendbar. Diese Verschiebung zwingt Angreifer dazu, diese Bins nach ausnutzbaren Informationen zu durchsuchen, obwohl einige Techniken möglicherweise immer noch das Entschleiern von Zeigern vor einem Leck ermöglichen, wenn auch mit Einschränkungen.
Für eine bessere Erklärung des Prozesses überprüfen Sie den Originalbeitrag hier.
Die Formel für das Verschleiern und Entschleiern von Zeigern lautet:
Neuer_Ptr = (L >> 12) XOR P
Dabei ist L der Speicherort und P der Fd-Zeiger. Wenn L um 12 Bits nach rechts verschoben wird, werden die signifikantesten Bits von P freigelegt, aufgrund der Natur von XOR, die 0 ausgibt, wenn Bits mit sich selbst XOR-verknüpft werden.
Wichtige Schritte im Algorithmus:
Erstes Offenlegen der signifikantesten Bits: Durch XOR-Verknüpfung des verschobenen L mit P erhalten Sie effektiv die oberen 12 Bits von P, da der verschobene Teil von L null sein wird und die entsprechenden Bits von P unverändert bleiben.
Wiederherstellung von Zeigerbits: Da XOR umkehrbar ist, ermöglicht es, das Ergebnis und einen der Operanden zu kennen, den anderen Operanden zu berechnen. Diese Eigenschaft wird verwendet, um den gesamten Satz von Bits für P zu deduzieren, indem bekannte Bitsets sukzessive mit Teilen des verschleierten Zeigers XOR-verknüpft werden.
Iteratives Entschleiern: Der Prozess wird wiederholt, wobei jedes Mal die neu entdeckten Bits von P aus dem vorherigen Schritt verwendet werden, um das nächste Segment des verschleierten Zeigers zu decodieren, bis alle Bits wiederhergestellt sind.
Behandlung deterministischer Bits: Die letzten 12 Bits von L gehen aufgrund der Verschiebung verloren, aber sie sind deterministisch und können nach dem Prozess rekonstruiert werden.
Eine Implementierung dieses Algorithmus finden Sie hier: https://github.com/mdulin2/mangle
Pointer Guard ist eine Exploit-Minderungstechnik, die in glibc verwendet wird, um gespeicherte Funktionszeiger zu schützen, insbesondere solche, die von Bibliotheksaufrufen wie atexit()
registriert wurden. Dieser Schutz beinhaltet das Verwirren der Zeiger durch XOR-Verknüpfung mit einem im Thread-Datenbereich (fs:0x30
) gespeicherten Geheimnis und Anwendung einer bitweisen Rotation. Dieser Mechanismus zielt darauf ab, zu verhindern, dass Angreifer die Kontrollflussübernahme durch Überschreiben von Funktionszeigern durchführen.
Verständnis der Pointer Guard Operationen: Das Verwirren (Mangeln) von Zeigern wird mit dem PTR_MANGLE
-Makro durchgeführt, das den Zeiger mit einem 64-Bit-Geheimnis XOR-verknüpft und dann eine Linksrotation um 0x11 Bits durchführt. Die Umkehrung zur Wiederherstellung des Original-Zeigers wird von PTR_DEMANGLE
behandelt.
Angriffsstrategie: Der Angriff basiert auf einem Known-Plaintext-Ansatz, bei dem der Angreifer sowohl die Original- als auch die veränderten Versionen eines Zeigers kennen muss, um das für das Verwirren verwendete Geheimnis abzuleiten.
Ausnutzen bekannter Klartexte:
Identifizierung fester Funktionszeiger: Durch Untersuchung des glibc-Quellcodes oder initialisierter Funktionszeiger-Tabellen (wie __libc_pthread_functions
) kann ein Angreifer vorhersehbare Funktionszeiger finden.
Berechnung des Geheimnisses: Unter Verwendung eines bekannten Funktionszeigers wie __pthread_attr_destroy
und seiner veränderten Version aus der Funktionszeiger-Tabelle kann das Geheimnis berechnet werden, indem der veränderte Zeiger rückwärts rotiert (Rechtsrotation) und dann mit der Adresse der Funktion XOR-verknüpft wird.
Alternative Klartexte: Der Angreifer kann auch versuchen, Zeiger mit bekannten Werten wie 0 oder -1 zu verändern, um zu sehen, ob diese identifizierbare Muster im Speicher erzeugen, die möglicherweise das Geheimnis offenbaren, wenn diese Muster in Speicherauszügen gefunden werden.
Praktische Anwendung: Nach Berechnung des Geheimnisses kann ein Angreifer Zeiger auf kontrollierte Weise manipulieren und somit den Pointer Guard-Schutz in einer Mehrfadenanwendung umgehen, wenn er die Basisadresse von libc kennt und die Fähigkeit besitzt, beliebige Speicherorte zu lesen.