Bei den Vorträgen von Ilja hab ich regelmäßig das Problem, dass ich höchstens die Hälfte davon verstehe. Das geht immer so weit in C- und Kernel-Interna, das brauche ich normalerweise nicht und ich programmiere auch nicht besonders gern. Diesmal habe ich zwar ganz gut verstanden, worum es ging aber die potentiellen Lücken zu einem Exploit zu entwickeln ist nochmal ein eigener Schritt.
Der erste Teil beschäftigte sich mit /dev/kmem und möglichen Race Conditions beim Auslesen des Kernel-Speichers. Die Lücken sind auf NetBSD bezogen, können aber ähnlich in allen anderen Systemen auftreten, die noch /dev/kmem verwenden (neuere Systeme greifen auf sysctl bzw. /proc zu und benötigen /dev/kmem nicht mehr).
Das Auslesen der Prozesstabelle via /dev/kmem funktioniert im Detail wie folgt:
- Finde die Prozesstabelle im Kernel-Speicher
- Finde die passende Prozessstruktur in der Prozesstabelle
- Finde den Zeiger in der Prozessstruktur, der z.B. auf den Prozessnamen zeigt
- Lese die Informationen auf die der Zeiger der Prozessstruktur zeigt
- Gib die Daten aus
Zwischen den Schritten zwei und drei kann eine interessante Race Condition auftreten. Das kommt vor, wenn während dieses Ablaufs der Prozess beendet wird und aus der Prozesstabelle verschwindet. Der Angriff sieht dann wie folgt aus:
- die Prozessstruktur wird wieder freigegeben
- der Speicher kann reallokiert werden
- wenn der Angreifer die Kontrolle über diesen Speicherbereich bekommt, kann er dort beliebigen Inhalt hineinschreiben
- der Inhalt sollte aussehen wie eine Prozessstruktur
- die Stelle an die der Pointer zeigt kann ausgelesen werden
Ein wunderbarer Data Leak direkt aus dem Kernel mit allen damit verbundenen Sicherheitsimplikationen. Noch schöner ist es, dass zwei SGID-kmem NetBSD-Programme (trsp/trpt) ihre Privilegien beim Starten nicht verwerfen und sogar core-Files einlesen (womit sie anfällig für manipulierte core-Files werden). Damit dürfte unter geeigneten Umständen eine Rechteeskalation zur Gruppe kmem und damit der komplett lesende Zugriff auf /dev/kmem möglich sein.
Eine zweite Fehlerklasse verursacht der Systemaufruf snprintf() in C, der zwei Eigenschaften hat. Zum einen ist der Rückgabewert der Funktion beim Schreiben in einen Puffer nicht die Zahl der tatsächlich geschriebenen Zeichen sondern die Zahl der geschriebenen Zeichen wenn alles in den Puffer gepasst hätte. Zum zweiten gibt snprintf() bei einem Fehler -1 als Rückgabewert zurück. Einige Funktionen prüfen jedoch den Rückgabewert nicht sondern verwenden ihn direkt zur Zeigermanipulation. Bei geeigneten mehrfachen Aufrufen mit Fehler (-1) kann dieser Zeiger dann auf eine beliebige Adresse gesetzt werden.
Der letzte Teil des Vortrags beschäftigt sich mit Out of Band Daten bei TCP. Dafür wird das Urgent-Flag und der Urgent-Pointer im TCP-Header genutzt. Allerdings gibt es kaum noch Anwendungen die Out of Band Daten nutzen.
Das Senden von OOB-Daten ist recht einfach: send(fd, data, len, MSG_OOB);
Das Lesen ist etwas kniffliger, da beim Empfänger Out of Band Daten normalerweise einfach ignoriert werden. Mittels der Funktion: fcntl(fd, F_SETOWN, getpid()); kann der Filehandle so gesetzt werden, dass OOB-Daten empfangen werden. Der Aufruf recv(fd, buf, len, MSG_OOB); kann dann zum Lesen genutzt werden. (Alternative Unix-Versionen haben andere Konstantennamen, MSG_OOB ist dann entsprechend anzupassen).
Eine Alternative ist OOB_INLINE, mit der Daten beim Empfänger auch in den normalen Empfangsdatenstrom eingebunden werden können. Und hier bekommen spätestens Intrusion Detection Systeme Probleme denn wie soll das IDS erkennen, dass die Daten zwar OOB gesendet aber Inline empfangen werden. Und pauschal Inline-Empfang anzunehmen ist auch nicht möglich eben weil das Standardverhalten des Empfängers einfach das Ignorieren der Daten ist.
Ich sag ja … ist immer krasses Zeug mit dem sich Ilja da beschäftigt.
Kommentare gesperrt wegen Spam
Comment by Christian — 15. März 2009 @ 19:58