Libc-Schutzmaßnahmen

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) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Durchsetzung der Chunk-Ausrichtung

Malloc reserviert Speicher in 8-Byte-(32-bit)- oder 16-Byte-(64-bit)-Gruppierungen. Das bedeutet, dass das Ende von Chunks in 32-bit-Systemen mit 0x8 und in 64-bit-Systemen mit 0x0 ausgerichtet sein sollte. Die Sicherheitsfunktion prüft, ob jeder Chunk an diesen spezifischen Stellen korrekt ausgerichtet ist, bevor ein Zeiger aus einem Bin verwendet wird.

Sicherheitsvorteile

Die Durchsetzung der Chunk-Ausrichtung in 64-bit-Systemen erhöht die Sicherheit von Malloc erheblich, indem sie die Platzierung gefälschter Chunks auf nur 1 von 16 Adressen beschränkt. Das verkompliziert Exploits, besonders in Szenarien, in denen der Angreifer nur eingeschränkte Kontrolle über Eingabewerte hat, wodurch Angriffe komplexer und schwieriger auszuführen sind.

  • Fastbin Attack on __malloc_hook

Die neuen Ausrichtungsregeln in Malloc vereiteln außerdem einen klassischen Angriff auf den __malloc_hook. Früher konnten Angreifer Chunk-Größen manipulieren, um diesen Funktionszeiger zu überschreiben und dadurch Codeausführung zu erlangen. Jetzt stellt die strikte Ausrichtungsanforderung sicher, dass solche Manipulationen nicht mehr praktikabel sind, womit ein häufiger Exploit-Weg geschlossen und die Gesamtsicherheit erhöht wird.

Hinweis: Seit glibc 2.34 sind die legacy hooks (__malloc_hook, __free_hook, etc.) aus dem exportierten ABI entfernt. Moderne Exploits zielen nun auf andere beschreibbare Funktionszeiger (z. B. tcache per-thread struct, vtable-style callbacks) oder verlassen sich auf setcontext, _IO_list_all primitives, etc.

Pointer Mangling on fastbins and tcache

Pointer Mangling ist eine Sicherheitsverbesserung zum Schutz der fastbin und tcache Fd pointers bei Speicherverwaltungsoperationen. Diese Technik hilft, bestimmte Arten von Speicher-Exploits zu verhindern, insbesondere solche, die keine geleakten Speicherinformationen benötigen oder Speicherstellen direkt relativ zu bekannten Positionen manipulieren (relative overwrites).

Der Kern dieser Technik ist eine Verschleierungsformel:

New_Ptr = (L >> 12) XOR P

  • L ist die Storage Location des Zeigers.
  • P ist der tatsächliche fastbin/tcache Fd Pointer.

Der Grund für die bitweise Verschiebung der Storage Location (L) um 12 Bits nach rechts vor der XOR-Operation ist entscheidend. Diese Manipulation adressiert eine Verwundbarkeit, die in der deterministischen Natur der niedrigsten 12 Bits von Speicheradressen liegt, die aufgrund von Architektur-Einschränkungen typischerweise vorhersehbar sind. Durch das Verschieben der Bits wird der vorhersehbare Anteil aus der Gleichung entfernt, wodurch die Zufälligkeit des neuen, gemangelten Zeigers erhöht und damit Exploits, die sich auf die Vorhersagbarkeit dieser Bits stützen, abgesichert werden.

Dieser gemanglete Zeiger nutzt die bereits vorhandene Zufälligkeit durch Address Space Layout Randomization (ASLR), die die von Programmen verwendeten Adressen randomisiert, um es Angreifern schwerer zu machen, das Speicherlayout eines Prozesses vorherzusagen.

Demangling des Zeigers, um die ursprüngliche Adresse wiederherzustellen, erfolgt mittels derselben XOR-Operation. Dabei wird der gemanglete Zeiger als P in der Formel behandelt und beim XOR mit der unveränderten Storage Location (L) ergibt sich der ursprüngliche Zeiger. Diese Symmetrie beim Mangling und Demangling stellt sicher, dass das System Zeiger effizient kodieren und dekodieren kann, ohne signifikanten Overhead, während die Sicherheit gegen Pointer-Manipulationen im Heap stark erhöht wird.

Sicherheitsvorteile

Pointer Mangling zielt darauf ab, teilweise und vollständige Zeigerüberschreibungen im Heap zu verhindern — eine bedeutende Sicherheitsverbesserung. Diese Funktion beeinflusst Exploit-Techniken auf mehrere Arten:

  1. Verhinderung von Byte-weisen relativen Overwrites: Früher konnten Angreifer Teile eines Zeigers ändern, um Heap-Chunks ohne genaue Adressen umzuleiten — eine Technik, die im leakless House of Roman Exploit zu sehen ist. Mit Pointer Mangling erfordern solche relativen Overwrites ohne heap leak jetzt Brute-Forcing, was ihre Erfolgsaussichten drastisch reduziert.
  2. Erhöhte Schwierigkeit bei Tcache Bin/Fastbin-Angriffen: Gängige Angriffe, die Funktionszeiger (wie __malloc_hook) durch Manipulation von fastbin- oder tcache-Einträgen überschreiben, werden erschwert. Beispielsweise würde ein Angriff typischerweise eine LibC-Adresse leaken, einen Chunk in die tcache bin free’en und dann den Fd-Pointer so überschreiben, dass er auf __malloc_hook zeigt, um arbitrary code execution zu erreichen. Mit Pointer Mangling müssen diese Pointer korrekt gemangelt sein, wodurch ein heap leak für eine präzise Manipulation erforderlich wird und die Exploit-Hürde steigt.
  3. Heap-Leaks werden für Nicht-Heap-Regionen erforderlich: Das Erstellen eines gefälschten Chunks in Nicht-Heap-Bereichen (wie Stack, .bss oder PLT/GOT) erfordert jetzt ebenfalls einen heap leak, da Pointer Mangling berücksichtigt werden muss. Das erhöht die Komplexität beim Ausnutzen dieser Bereiche ähnlich wie bei der Manipulation von LibC-Adressen.
  4. Leaken von Heap-Adressen wird schwieriger: Pointer Mangling schränkt die Nützlichkeit von Fd-Pointern in fastbin- und tcache-Bins als Quellen für Heap-Adress-Leaks ein. Allerdings bleiben Pointer in unsorted, small und large bins ungemangelt und damit weiterhin für Leaks nutzbar. Diese Verschiebung treibt Angreifer dazu, diese Bins nach verwertbaren Informationen zu durchsuchen, wobei einige Techniken eventuell erlauben, Pointer vor einem Leak zu demangeln — jedoch mit Einschränkungen.

Safe-Linking Bypass (seitenbündiges leak-Szenario)

Selbst mit aktiviertem safe-linking (glibc ≥ 2.32) kann, wenn du den gemanglten Zeiger leaken kannst und sowohl der korrumpierte Chunk als auch der Opfer-Chunk dieselbe 4KB-Seite teilen, der ursprüngliche Zeiger nur mit dem Page-Offset wiederhergestellt werden:

// leaked_fd is the mangled Fd read from the chunk on the same page
uintptr_t l = (uintptr_t)&chunk->fd;           // storage location
uintptr_t original = (leaked_fd ^ (l >> 12));  // demangle

Dies stellt den Fd wieder her und erlaubt klassisches tcache/fastbin poisoning. Wenn die chunks auf unterschiedlichen Seiten liegen, ist das brute-forcing des 12-Bit-Page-Offsets (0x1000 Möglichkeiten) oft praktikabel, wenn Allokationsmuster deterministisch sind oder Abstürze akzeptabel sind (z. B. CTF-style exploits).

Demangling von Pointern mit einem Heap Leak

Caution

Für eine bessere Erklärung des Prozesses siehe den Original-Post hier.

Algorithmus-Übersicht

Die für das Mangling und Demangling von Pointern verwendete Formel ist:

New_Ptr = (L >> 12) XOR P

Wobei L der Speicherort ist und P der Fd-Pointer. Wenn L um 12 Bits nach rechts geschoben wird, werden die höchstwertigen Bits von P offengelegt, aufgrund der Natur von XOR, das 0 ausgibt, wenn Bits mit sich selbst XORed werden.

Wichtige Schritte im Algorithmus:

  1. Initialer Leak der höchstwertigen Bits: Durch das XORen des verschobenen L mit P erhält man effektiv die oberen 12 Bits von P, weil der verschobene Teil von L null ist und die entsprechenden Bits von P unverändert bleiben.
  2. Wiederherstellung der Pointer-Bits: Da XOR umkehrbar ist, erlaubt das Kennen des Ergebnisses und eines der Operanden, den anderen Operanden zu berechnen. Diese Eigenschaft wird genutzt, um die vollständige Bitfolge von P herzuleiten, indem sukzessive bekannte Bitmengen mit Teilen des mangled pointer XORed werden.
  3. Iteratives Demangling: 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 mangled pointer zu dekodieren, bis alle Bits wiederhergestellt sind.
  4. Umgang mit deterministischen Bits: Die letzten 12 Bits von L gehen durch den Shift verloren, sind aber deterministisch und können nachträglich rekonstruiert werden.

Eine Implementierung dieses Algorithmus finden Sie hier: https://github.com/mdulin2/mangle

Pointer Guard

Pointer Guard ist eine Exploit-Mitigationsmaßnahme in glibc, die gespeicherte function pointers schützt, insbesondere solche, die durch Bibliotheksaufrufe wie atexit() registriert werden. Diese Schutzmaßnahme verschleiert die Pointer, indem sie sie mit einem im Thread-Data (fs:0x30) gespeicherten Secret XORed und eine bitweise Rotation anwendet. Dieser Mechanismus soll verhindern, dass Angreifer durch Überschreiben von function pointers den Kontrollfluss kapern.

Umgehung von Pointer Guard mit einem Leak

  1. Verstehen der Pointer Guard-Operationen: Das Mangling der Pointer erfolgt über das PTR_MANGLE-Macro, das den Pointer mit einem 64-Bit-Secret XORed und dann eine Rotation um 0x11 Bits nach links ausführt. Die Gegenoperation zur Wiederherstellung des ursprünglichen Pointers wird von PTR_DEMANGLE übernommen.
  2. Angriffsstrategie: Der Angriff basiert auf einem known-plaintext-Ansatz, bei dem der Angreifer sowohl die ursprüngliche als auch die gemanglete Version eines Pointers kennen muss, um das zum Mangling verwendete Secret zu ermitteln.
  3. Ausnutzen bekannter Plaintexts:
  • Identifizieren fester function pointers: Durch Untersuchung des glibc-Quellcodes oder initialisierter function pointer-Tabellen (wie __libc_pthread_functions) kann ein Angreifer vorhersagbare function pointers finden.
  • Berechnung des Secrets: Mit einem bekannten function pointer wie __pthread_attr_destroy und seiner gemangelten Version aus der function pointer-Tabelle kann das Secret berechnet werden, indem man die gemangelte Adresse rückwärts rotiert (Rechtsrotation) und anschließend mit der Funktionsadresse XORed.
  1. Alternative Plaintexts: Der Angreifer kann auch experimentieren, Pointer mit bekannten Werten wie 0 oder -1 zu manglen, um zu sehen, ob diese in Memory-Dumps erkennbare Muster erzeugen; das Auffinden solcher Muster kann das Secret offenbaren.
  2. Praktische Anwendung: Nach Berechnung des Secrets kann ein Angreifer Pointer kontrolliert manipulieren und somit den Pointer Guard in einer multithreaded Anwendung umgehen, sofern die libc-Basisadresse bekannt ist und das Lesen beliebiger Speicherstellen möglich ist.

GLIBC Tunables & Aktuelle Loader-Bugs

Der dynamic loader parst GLIBC_TUNABLES vor dem Programmstart. Fehlparsing-Bugs hier wirken sich direkt auf libc aus, bevor die meisten Mitigationen greifen. Der 2023er “Looney Tunables”-Bug (CVE-2023-4911) ist ein Beispiel: ein überlanger GLIBC_TUNABLES-Wert überläuft interne Puffer in ld.so und ermöglicht in Kombination mit SUID-Binaries eine Privilegieneskalation auf vielen Distributionen. Die Ausnutzung erfordert nur das Anlegen der Umgebung und das wiederholte Aufrufen des Zielbinaries; pointer guard oder safe-linking verhindern das nicht, da die Korruption im Loader vor der Heap-Initialisierung stattfindet.

Quellen

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) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks