23.17 Kernel-Erweiterungen und gcc-propolice
Im Folgenden sollen einige interessante Erweiterungen für Linux- und BSD-Kernel besprochen werden.
Sie werden zudem sehen, dass wir dieses Thema nur sehr grundlegend behandeln können.
23.17.1 gcc propolice
Bevor wir allerdings zu den eigentlichen Kernel-Patches kommen, soll an dieser Stelle noch der sogenannte »propolice«-Patch für den GNU C Compiler (gcc) besprochen werden. Dieses Feature ist auch als »GCC Stack Smashing Protection« bekannt, und es kommt von IBM.
Die ProPolice Extension baut verschiedene Schutzmechanismen für den Stack ein, um Angriffe wie Buffer-Overflows zu erschweren.
Zu diesen Features gehört der Schutz der Pointer innerhalb einer Stackframe. Zudem werden lokale Funktionsvariablen (bei einer IA32-Architektur) vor den Buffern platziert. Überschreibt ein Angreifer also einen Buffer, so überschreibt er nicht die Variablen. Die gesicherte Rücksprungadresse und der Extendend Instruction Pointer (EIP) werden ebenfalls vor den Buffern platziert und können somit nicht mehr überschrieben werden. Um einen überschriebenen Buffer zu detektieren, wird hinter den Buffern zudem noch ein Canary-Wert eingefügt (der durch /dev/random mit Zufallswerten arbeitet): Wird dieser Canary-Wert verändert, dann wird ein Buffer überschrieben, und es steht fest, dass der Stack beschädigt wurde.
In neueren Versionen des Compilers ist der ProPolice-Patch bereits enthalten. Im Folgenden sei allerdings kurz die Vorgehensweise zur Erstellung des gcc-3.x mit dem Patch gezeigt.
Die Installation erfolgt von Hand, wenn Sie nicht gerade eine Distribution benutzen, die bereits den modifizierten gcc verwendet, etwa Hardened Linux (oder OpenBSD). Die dazu benötigten Patches finden Sie unter www.trl.ibm.com/projects/security/ssp/.
Im Folgenden wird auf fast die gleiche Weise wie früher bei Hardened Linux der gcc modifiziert. Verwendet wird dabei derzeit die Version 3.4.4.
$ tar -xf gcc-3.4.4.tar.gz $ cd gcc-3.4.4 $ patch -p0 < ../gcc_3_4_4.dif $ tar -xzvf ../protector-3.4.4-1.tar.gz $ mkdir obj && cd obj $ ../configure --prefix=/usr $ make bootstrap $ make install
Anwendungen mit SSP kompilieren
Um ein Programm nun so zu kompilieren, dass es durch die SSP geschützt wird, übergibt man beim Kompilieren den Parameter -fstack-protector.
Achtung: Im Normalfall werden nur Buffer ab einer Größe von 8 Bytes durch den Patch geschützt. Modifiziert man allerdings den Patch bzw. den Quellcode des gcc, so lässt sich diese Grenze anpassen.
Das folgende Programm soll nun einmal mit und einmal ohne SSP übersetzt werden. Dabei werden, wenn mehr Byte übergeben werden, als in dem Buffer »buf« gespeichert werden können, u. U. andere Werte auf dem Stack überschrieben. <Es muss nicht unbedingt eine andere Variable überschrieben werden, da der gcc manchmal mehr Speicher als nötig reserviert.> Wir werden uns den Unterschied einmal ansehen.
#include <string.h> int main(int argc, char *argv[]) { char buf[10]; if (argc > 1) strcpy(buf, argv[1]); return 0; }
Listing 23.28 test.c
hikoki:/tmp/ssp> gcc -o test test.c hikoki:/tmp/ssp> ./test abcdefffffffffffffffffffffffff Segmentation fault hikoki:/tmp/ssp> gcc -o test -fstack-protector test.c hikoki:/tmp/ssp> ./test abcdefffffffffffffffffffffffff *** stack smashing detected ***: ./test terminated Abort hikoki:/tmp/ssp>
Listing 23.29 SSP-Test
23.17.2 SeLinux und SeBSD
Beim SeLinux-Projekt handelt es sich um eine Erweiterung des Linux-Kernels um sogenannte Mandatory Access Control Policies. Hierbei handelt es sich um die Möglichkeit, die Rechte einzelner Prozesse stark einzugrenzen.
23.17.3 OpenWall (OWL)
Das OpenWall-Projekt ist Bestandteil vieler gehärteter Linux-Distributionen. Die Funktionalitäten von OpenWall werden teilweise auch von anderen Kernel-Patches unterstützt (besonders von grsecurity/PaX).
Zu den Features gehört eine Stack-Härtung: Der Stack eines Programms kann oft durch Buffer-Overflow-Exploits angegriffen werden, wozu der Stack ausführbar sein muss. OpenWall unterbindet diese Möglichkeit.
Die Links und FIFOs im Verzeichnis /tmp und der Zugriff auf /proc werden ebenfalls durch OWL gehärtet.
Weitere Features sind die RLIMIT_NPROC-Überprüfung für den Syscall execve() und das Löschen von nicht verwendeten Shared Memory Pages im Speicher. <RLIMIT_NPROC gibt die Anzahl der Prozesse an, die ein Benutzer maximal gleichzeitig laufen lassen kann. Shared Memory ist eine Art der Interprozesskommunikation (IPC).>
23.17.4 grsecurity
Bei grsecurity handelt es sich um einen sehr umfangreichen Kernel-Patch plus Administrationstools.
Wir können an dieser Stelle nicht auf die Feinheiten von grsecurity eingehen und werden nur die wichtigsten erwähnen.
grsecurity implementiert diverse Features, die auch OWL kennt (FIFO-Restrictions etc.), Role-Based Access Control (RSBAC), zufällige Prozess-IDs, chdir()-Hardening, Unterstützung für zufällige TCP-Quellports, Logging von Signalen, Zugriffsbeschränkungen auf /dev/kmem und /dev/mem sowie das komplette PaX-Projekt, das wir gleich besprechen werden.
Eine ausführliche Auflistung der aktuellen Features erhalten Sie auf der Seite http://www.grsecurity.net/features.php.
23.17.5 PaX
PaX (Page exec) ist ein Kernel-Patch, der das Ziel hat, Speicherseiten abzusichern. Das Primärziel ist die Verhinderung von erfolgreichen Stack-Smashing-Angriffen (die sogenannte Stack-Smashing-Protection), die nicht mit dem ProPolice-Patch des gcc zu verwechseln ist. Zu diesem Zweck wurde eine »executable space protection« implementiert, die – vereinfacht gesagt – verhindern soll, dass es zur Ausführung von Shell-Code und zu erfolgreichen Return-to-Libc-Angriffen kommt. <Dieses Thema ist sehr umfassend, und es wird leider wesentlich mehr Security- und Kernel-Know-how zum Verständnis von PaX benötigt, als wir es Ihnen hier bieten können.>
PaX erreicht das Ziel durch zwei Techniken:
1. | Nicht-ausführbare Speicherseiten Eingeschleuster Code, der zur Ausführung gebracht werden soll, muss sich innerhalb von Speicherseiten (pages) befinden, denen das Ausführen von Programmcode erlaubt ist. Sind diese Seiten nicht ausführbar, so wird auch der Code nicht ausgeführt. |
2. | Zufällige Speicheradressen Wenn ein Angreifer versucht, eine bestimmte Funktion im Speicher aufzurufen, obwohl dies nicht geplant ist, so wird dazu die Speicheradresse dieser Funktion benötigt. Durch die sogenannte »Address Space Layout Randomzation« wählt PaX diese Adressen bei jedem Programmstart neu, und ein Erraten der Adresse einer Funktion wird somit sehr erschwert. |