Wenn Ihr Stack und Ihr Heap nicht ausführbar sind, wie kann Ihr Code dann ausgeführt werden?

Lesezeit: 4 Minuten

Benutzer-Avatar
Adam Sch

Ich habe ein Buch über Pufferüberlauf gelesen, und es schlägt das nächste vor, mit dem man sich befassen sollte:

Den Stack (und Heap) nicht ausführbar zu machen, bietet ein hohes Maß an Schutz gegen viele Arten von Pufferüberlaufangriffen für bestehende Programme.

Aber ich verstehe nicht, wie wir das machen sollen – wo würde die Ausführung stattfinden, wenn nicht auf dem Heap oder auf dem Stack?

Benutzer-Avatar
Jim Balter

Wenn ich Ihre Frage richtig verstehe, spricht keine der anderen Antworten sie an. Die Antwort ist, dass die Ausführung im Codeabschnitt erfolgt, der weder Stack noch Heap ist. In einem typischen ausgelagerten Speichersystem wird der Code aus einer Programmdatei (z. B. einer .exe-Datei in Windows) in ausführbare, aber schreibgeschützte Seiten geladen. Dem Prozess werden für Stack und Heap zusätzliche beschreibbare (und ausführbare) Seiten zugeordnet. Der Vorschlag hier ist, dass das Betriebssystem und die Hardware zusammenarbeiten sollten, um diese Seiten als beschreibbar, aber nicht ausführbar zu markieren (die Antwort von rgngl erklärt, wie das in Windows geht).

Selbst mit nicht ausführbarem Heap und Stack sind Exploits immer noch möglich, die die in Alexey Frunzes Antwort erwähnte return-orientierte Programmierung verwenden, aber es gibt Schutztechniken, die sogar diese verhindern, wie z http://en.wikipedia.org/wiki/Return-to-libc_attack#Protection_from_return-to-libc_attacks

  • Gute Antwort. Ein kleiner Kommentar jedoch – (Blind) ROP besiegt tatsächlich ASLR ieeexplore.ieee.org/xpl/…

    – Hack-R

    15. März 2015 um 20:23 Uhr

Es gibt sogenannte „return-orientierte Programming“ (AKA ROP) Art von Exploits.

Der Angreifer findet heraus, wie er aus verschiedenen Teilen des Programms, das ausgenutzt wird, seinen bösartigen Code macht.

Er findet brauchbare Bytesequenzen (Anweisungen) vor den Byte(n) der Rückgabeanweisung, die nützliche Operationen an Registern oder im Speicher ausführen können, wie z. B. einen Wert an eine Stelle verschieben, Werte hinzufügen, Werte vergleichen usw gebaut aus.

Dann zwingt der Angreifer durch Ausnutzen eines Codefehlers das Programm, mit der Ausführung der Kette dieser Mikrosubroutinen zu beginnen, die all die böse Arbeit erledigen.

Also, jetzt wird aus gutem Code böser Code. Nichts wird auf dem Stack oder im Heap ausgeführt.

Bemerkenswert ist auch, dass bei CPUs, bei denen Befehle mehrere Bytes umfassen und variable Länge haben, sogar die unmittelbaren Befehlsoperanden (IOW, numerische Konstanten), die Teil von Befehlen sind, zu Code werden können, sodass die Chancen, brauchbare Bytesequenzen zu finden, dort höher sind als auf “einfacheren” CPUs.

Es ist auch oft möglich, bösartigen Code zu konstruieren, der den Speicherschutz ändert, und der Exploit wird nicht mehr durch den Code der vorhandenen Anwendung eingeschränkt.

Ganz konkretes Beispiel: Richten Sie die Absenderadresse ein, auf die verwiesen werden soll system und der nächste Schlitz auf dem Stapel (oder das erste Argumentregister auf Pass-by-Register-Bögen), um ein Zeiger auf die Zeichenfolge zu sein "/bin/sh".

  • Aber müssen Sie in diesem Fall nicht auch Zugriff auf die Konsole haben?

    – Alexey Frunze

    14. Juli 2012 um 8:03 Uhr

  • Nein. Ich bin davon ausgegangen, dass die Standardeinstellung des Prozesses ein Socket oder Terminal ist, mit dem Sie verbunden sind, aber wenn nicht, ändern Sie es einfach "/bin/sh" zu "/bin/sh 0<&n" wo n ist die Dateideskriptornummer des Server-Sockets für Ihre Verbindung.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    14. Juli 2012 um 8:16 Uhr

  • Oder Sie können es natürlich so ändern, dass es ohne interaktive Shell tut, was Sie wollen, z "echo 'toor::0:0::/:/bin/sh' >> /etc/passwd"

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    14. Juli 2012 um 8:37 Uhr

Diese Art von Schutz wird vom Betriebssystem bereitgestellt und kann nicht in der Anwendungsschicht erfolgen.

Siehe den Wikipedia-Artikel, der auch erklärt, wie man es unter Windows aktiviert: http://en.wikipedia.org/wiki/Data_Execution_Prevention

Ihr Code wird im Textsegment ausgeführt, nicht im Stack oder Heap (beide dienen der Datenspeicherung). Die Organisation ist also:

<highest addresses>
stack
...
heap
data section (initialized data & bss - uninitialized data) 
code section (text)
<lowest addresses> 

Der Codeabschnitt ist ausführbar, aber unveränderlich. Dieser Wikipedia-Artikel enthält weitere Details: https://en.wikipedia.org/wiki/Datensegment

Benutzer-Avatar
0x90

Sie können zu jeder anderen Stelle springen, die ein ausführbares Segment ist, und Ihren bösen Code ausführen …

Schließlich sind alle Daten auf jedem Speicher Bits und Bits können Anweisungen an die CPU sein, die ausgeführt werden sollen.

Benutzer-Avatar
argentage

Sie können Ihren Überlauf verwenden, um die Rückkehradresse einer Funktion zu überschreiben, die mit Ihrem Code zu einer bekannten Adresse springen kann. Aber dann reagierten die Betriebssystemschreiber, indem sie den Adresscode randomisierten, der ausgeführt wird auf …

  • Wie laden Sie zunächst Ihren Code in ausführbare Speicherorte, wenn sich alles außer dem Programmcode im nicht ausführbaren Speicher befindet? Die Randomisierung des Adressraums allein verhindert keine ROP-basierten Exploits. Siehe meine Antwort.

    – Alexey Frunze

    14. Juli 2012 um 7:55 Uhr

1351690cookie-checkWenn Ihr Stack und Ihr Heap nicht ausführbar sind, wie kann Ihr Code dann ausgeführt werden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy