= Sichere Software-Entwicklung im systemnahen Bereich
:author: Jan Klemkow, Benjamin Franzke
:lang: de

== Kurzfassung

Dieses Dokument beschreibt Sicherheitsrisiken von Systemprogrammen mit dem Fokus
auf UNIX-Systeme.
Systemnahe meinst in diesem Dokument alle Programme welche direkt auf die
Systemschnittstellen (System-Calls) zugreifen.

== Einleitung

Sicherheit fuer die Software-Entwicklung im systemnahen Bereich spielt eine
wesentliche Rolle.
Da es hier oft nicht nur um die Anwendung selbst sonder auch um die Sicherheit
des Gesamtsystems geht.
Systemdienste werden in vielen Faellen mit hoeheren Rechten ausgefuehrt.
Gelingt es einem Angreifer einen solchen Dienst zu uebernehmen, erlangt er
selbst hoehere Rechte auf dem Zielsystem.
Bei Endanwendungen ist dieses in der Regel nicht der Fall, sodass der Angreifer
bei einem erfolgreichen nur Teile des Zielsystems unter seine Kontrolle bringen
kann.

Historisch betrachtet hat sich die Lage in diesem Bereich in den vergangenen
zehn Jahren verbessert.
Die grossen Angriffe, welche sich zu Beginn der 2000er Jahre noch auf
Systemdienste richteten, sind heute eher selten geworden.
Momentan stehen die Endanwendungen wie Browser oder Dokumentenbetrachter im
Fokus der Angriffe.

//

//Im systemnahen Bereich gibt es viele Programme welche fuer die Sicherheit des
//Gesamtsystems eine enorme Rolle spielt.

// Angefangen beim Kernel des Betriebssystems 

== Angriffsvektoren

In diesem Kapitel werden verschiedene Angrifftvektoren und Schwachstellen von
Systemprogrammen erlaeutert.
Zudem werden werden verschiedene Verteidigungsmassnahmen erlaeutert, welche
das Risiko der Angriffsmoeglichkeiten senken.

=== Standard-C-Bibliothek

Viele Systemprogramme sind in der Programmiersprache C geschrieben.
Deren Standardbiblothek unterlag im laufe der Zeit einer ganzen Reihe von
Veraenderungen, welche unteranderem die Sicherheit von Programmen erhoehten.

Eines der groessten Probleme in C-Programmen stellen die Zeichekettenfunktionen
da.
Da diese seit langer Zeit immer wieder fuer Sicherheitsprobleme sorgen.
Bei dieses Funktionen ist Problem, dass diese die Laengen von Speicherbereichen
nicht beachten.
Dadurch kommt es schnell zu Pufferueberlaeufen und Zugriffen auf nicht
allokierte Speicherbereiche.
Dadurch koennen Angreiffer eigenen Programmcode einschleusen und ausfuehlen
lassen, sowie Programme zum Absturz bringen.

Als Fallbeispiel wird die Funktion strcpy erklaert.
Diese Funktion wird dafuer benutzt um eine Zeichenkette von einem Speicherplatz
zu einem anderen zu kopieren.
Als Parameter bekommt die Funktion die Startadresse der Quelle und die
Startadresse des Ziels im Speicher.
Der Funtkion ist dabei die Groesse der jeweiligen Speicherplaetze nicht bekannt.
Es wird nun eine Speicherzelle nach der Anderen kopiert, solange bis in der
Quelle ein NUL-Byte auftaucht.
Dabei kann die Funtkion weder sicherstellen, dass sie nicht ueber den
Quellpuffer hinaus Bytes kopiert, sowie dass sie nicht ueber die genzen des
Zielpuffers hinaus schreibt.

Durch dieses Verhalten, kommt es immer wieder zu Pufferueberlaeufen, welche
zu unvorhersagbaren Folgen fuer den weiteren Programmablauf fuehren.

Um dieses Problem zu loesen wurden neue Zeichenkettenfuntkionen in die
Standard-C-Bibliothek auf genommen, welche als Argument maximal Laengen
uebergeben bekommen.

[source,c]
-------------------
strcpy(char *dst, const char *src);
strncpy(char *dst, const char *src, size_t len);
strlcpy(char *dst, const char *src, size_t dstsize);
-------------------

Hierbei gibt es zwei Ansaetze mit Laengen umzugehen.
TODO: strncpy() strlcpy()

 * gets()
 * strlen()
 * strcpy()
 * str..()

=== Netzwerk-Programmierung

Ein grosser Angriffsvektor auf Computersysteme sind die Laufenden Dienste,
welche ueber Netzwerk und Internet erreichbar sind.
Ein Fehler in ihrer Programmierung koennte von ausserhalb ausgenutzt werden,
da Internetdiensten eine staendige weltweite Erreichbarkeit haben.
Somit kann ein Internetdienst potentiell zur jeder Zeit von jedem Ort aus
angegriffen werden.

Zum Schutz solcher Dienste gibt es verschiedene Mechanismen, welche im Folgenden
erlaeutert werden.

 * privilege separation
 * chroot/jail
 * Zugangsbeschraenkung (Firewall Layer 3/4)
 * Applikation Level Gateway (doppelte parsen von protokollen)

==== Privilege Separation

Bei der Privilege-Seperation wird ein Programm in verschiedene Prozesse mit
unterschiedlichen Berechtigungena auf geteilt.
Ziel ist es, so wenig Programmcode wie moeglich mit root-Rechten laufen zu
lassen.

Als Beispiel soll der Window-Compositer Wayland genannt...
TODO: wayland privilege separater erklaeren

Im einfachsten Fall startet ein Deamon mit Root rechten und holt sich alle
Resourcen, wie etwas sockets mit Well-Known-Ports oder eine Filedescriptor auf
eine Datei, gibt dann die rechte ab und laeuft im user-mode weiter.

==== Service-Seperation

Da auf einem Computer zumeist mehr als nur ein Dienst laeuft, welcher mit einem
Netzwerk oder dem Internet verbunden ist, ist auch die Angriffsmoeglichkeit auf
dieses System sehr hoch.

Vor Allem beim Servern, welche viele Dienste wie HTTP, FTP, SMTP, POP3 und
viele mehr anbieten ist die Gefahr einer Sicherheitsluecke sehr hoch.
Sollte einer dieser Dienste ueber eine Sicherheitsluecke von einem Angreifer
uebernommen werden, so koennte diese ebenfalls die anderen Dienste und deren
Daten uebernehmen.

Um dieses zu vermeiden, werden diese Dienste in kuenstlichen Umgebungen
getrennt von einander getrennt.

Eine Variante ist dafuer der System-Call +chroot(2)+.
Dieser System-Call wechselt fuer einen Prozess und dessen Kind-Prozesse das
Root-Verzeichnis.
Somit kann ein Prozess auf Dateien ausserhalb des neuen
Root-Verzeichnisses mehr zugreifen.
Bereits geoeffnete Dateien koennen aber weiterhin verwendet werden,
auch wenn diese Ausserhalb des neuen Root-Verzeichnisses liegen.

Ein Beispiel fuer die Anwendung dieser Technik ist der Apache-Http-Server,
welcher meist in das Verzeichnis +/var/www+ als Root-Verzeichnis wechselt.

==== Zugangsbeschraenkung

Sollte ein Dienst nur fuer 

=== Kernel

Beim erstellen einer sicherheitskritischen Anwendung ist nicht nur die
Architektur und Programmierung der Anwendung selbst wichtig.
Die Umgebung in der die Anwendung laeuft ist ebenfalls ein wichtiger Faktor,
fuer dich Sicherheit eines Systems.
So kann die Wahl eines anderen Betriebssystems schon dafuer ausschlaggebend
dafuer sein, ob eine Programmierfehler zu einem Sicherheitsrisiko wird oder
nicht.

Im Folgenden werden einige Aspekte des Kernel-Designs auf ihre Sicherheit fuer
das Gesamtsystem betrachtet.

 * interrupt blockierung
 * Treiber Userland(minix) / OpenSource (nvidia)

=== Microkernel

Die meisten Betriebssysteme verwenden ein monolitisches Kernel-Design.
In diesem werden viele Aufgaben des Betriebssystems im Kernel erledigt.
Das bedeutet, dass der Programmcode mit sehr hohen Berechtigungen
ausgefuehrt wird.

Ein Grossteil dieser Aufgaben koennen auch von User-Prozessen uebernommen
werden.
Dieses hat den Vorteil, dass Schutzfunktionen des Prozessors genutzt werden
koennen.

Bei Betriebssystemen mit einem Mikro-Kernel-Design ist dieses anders.
Dort werden viele Aufgaben an User-Prozesse ausgelagert, z. B. die
Geraetetreiber.

==== NVIDIA Treiber Problem

Im +CVE-2012-0946+ wird eine Sicherheitsluecke im NVIDIA Graphikkarten-Treiber
fuer Linux, Solaris und FreeBSD beschrieben, welcher das erlangen von hoeheren
Rechten ermoeglicht.
Das ausnutzen dieses Programmierfehlers ist nur moeglich, weil der Treiber
im Kernel-Mode ausgefuehrt wird.

//Bei dem Betriebssystem Minix etwa, werden Geraetetreiber als User-Prozess
//gestartet.
//Dadruch unterliegen sie den gleichen Sicherheitsvorkehrungen wie alle anderen
//Programme.
//So werden z. B. Speicherschutzverletzungen vom Prozessor erkannt.
//Ein Fehlerhaft programmierter Treiber kann so nicht mehr das gesammte System
//gefaehrden.

// vim: set syntax=asciidoc spell spelllang=de,en:
