daily.out

2010-08-01

Ausführbarkeit des Heap

In "The Mac Hacker's Handbook" von Charlie Miller und Dino Dai Zovi ist mir ein grundlegender Fehler im Kapitel "Executable Heap" (Seite 24 und folgende) aufgefallen: Sie schreiben, Leopard würde das Nicht-Ausführbarkeits-Bit nur für den Stack setzen, nicht aber für den Heap. Was mich noch mehr wundert, ist ihre Anmerkung dazu in dem diesbezüglichen Kapitel, daß sie nicht wissen, ob das Absicht, ein Versehen oder ein Bug ist.

Ein Blick in die Dokumentation zu Leopard bringt Klarheit: "Features – System security: … No-execute heap for 64-bit applications".

Wenn sie ihr Beispielprogramm in 64 Bit übersetzt hätten, dann wäre ihnen der Irrtum auch aufgefallen:

macmarks-imac:bin macmark$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.5
BuildVersion: 9A581
macmarks-imac:bin macmark$ cat heap_executable.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char shellcode[]= "\xeb\xfe";

int main(int argc, char *argv[]) {
void (*f) ();
char *x = malloc(2);
memcpy(x, shellcode, sizeof(shellcode));
f = (void (*) () ) x;
f();
}
macmarks-imac:bin macmark$ gcc -Wall -arch x86_64 heap_executable.c -o heap_executable_64
heap_executable.c: In function 'main':
heap_executable.c:13: warning: control reaches end of non-void function
macmarks-imac:bin macmark$ gcc -Wall -arch i386 heap_executable.c -o heap_executable_32
heap_executable.c: In function 'main':
heap_executable.c:13: warning: control reaches end of non-void function
macmarks-imac:bin macmark$ ./heap_executable_64
Bus error
macmarks-imac:bin macmark$ ./heap_executable_32

Dieser C-Code ist wie die meisten Hackereien jenseits dessen, was einem normalen Programmierer einfallen würde: Es wird ein Zeiger auf eine Funktion deklariert, was nicht alle Tage genutzt wird. Dieser Funktions-Zeiger, wird später auf eine Stelle gesetzt (mittels passendem Casting), die eine Zeichenkette, enthält. Dann wird diese "Funktion" ausgeführt, wobei die Zeichenkette ausgeführt wird. Die Zeichenkette wird also als Funktion interpretiert. Im realen Fall würde die Zeichenkette anderen Angriffs-Code als hier enthalten.

Mit malloc wird dabei dafür gesorgt, daß die Zeichenkette im Heap liegt. Wenn man eine Zeichenkette vom Stack ausführen wollte, dann würde die Zeile char *x = malloc(2); durch char x[4]; ersetzt, da lokale Variablen auf dem Stack angelegt werden, dynamisch reservierter Speicher jedoch auf dem Heap. Da die als Funktion ausgeführte Zeichenkette im Heap liegt, kommt es zu einem Fehler, wenn der Heap als nicht ausführbar markiert ist. Kommt kein Fehler, dann ist der Heap ausführbar.

Beim Ausführen der 64-Bit-Version bekommt man einen Fehler, beim Ausführen der 32-Bit-Version jedoch keinen und das Programm läuft weiter und verbraucht viel Rechenleistung. Der Code wurde jeweils auf einem frisch installierten Leopard 10.5.0 ausgeführt.

Ich hatte dann Charlie und Dino per Twitter auf den Fehler angesprochen. Charlie antwortete, daß er das nicht glaubt und daß Schnee Leopard dies macht, aber Leopard nicht. Dino antwortete danach, daß er sich sicher ist, daß 10.5 einen nicht-ausführbaren Heap für 64-Bit hat. Ich wies auch nochmal daraufhin, daß mit der 64-Bit-Compiler-Option der Heap nicht ausführbar ist im Gegensatz zur 32-Bit-Einstellung. Dann stimmte Charlie zu. So können Hacker sich irren.

Valid XHTML 1.0!

Besucherzähler


Latest Update: 11. September 2015 at 19:49h (german time)
Link: macmark.de/blog/osx_blog_2010-08.php