Absichtlich platzierte Schwachstellen Risiko Insider-Angriffe – Code-Manipulationen erkennen
Nicht nur versehentliche Fehler gefährden die eigene Software: Auch böswillige Angriffe durch Insider stellen ein erhebliches Risiko dar. Um absichtliche Code-Manipulationen und versteckten Schadcode zu finden, bietet sich die statische Analyse an. Eigener, aber auch Code aus fremden Händen sollte damit überprüft werden.
Anbieter zum Thema

Beim Thema Sicherheit und Schadcode denken die meisten Menschen zunächst an Hacker, die von außen Lücken in einer Software ausnutzen wollen. Dabei wird oft übersehen, dass auch von Projekt-Insidern ein beachtliches Schadenpotenzial ausgeht. Hier sollte man nicht nur die ganz normalen Fehler bedenken, die einfach passieren und kaum zu vermeiden sind. Immer wieder kommt es vor, dass Insider gezielt einem Unternehmen schaden oder die Produkte für kriminelle Aktivitäten nutzen wollen. Die Gründe dafür sind sehr vielfältig und reichen von Enttäuschung über die eigene Karriere bis zu schlicht kriminellem Verhalten. Denn klar ist: Wer einen Code gut kennt oder sogar selbst Teile davon entwickelt, kann die Systeme wesentlich effektiver angreifen als ein normaler Hacker, der auf zufällig gefundene Exploits vertrauen muss. Eine viel genutzte Bibliothek zu manipulieren ist also aus krimineller Sicht ein effektives Geschäftsmodell.
Laut dem CERT Insider Threat Center der amerikanischen Carnegie Mellow University gehen fast ein Viertel aller kriminellen Handlungen in der IT auf das Konto von Insidern, Tendenz steigend. Und ein großer Teil der betroffenen Unternehmen sieht darin ein größeres Schadenspotenzial als bei Angriffen von außen. Andere Untersuchungen kommen zu einem ähnlichen Ergebnis. So ermittelte zum Beispiel IBM bereits vor einigen Jahren eine Insider-Quote von 32 Prozent. Die Schäden, die den Unternehmen dadurch entstehen, beziffert eine Studie des Ponemon Institute vom April dieses Jahres auf durchschnittlich rund 650.000 Dollar pro Vorfall und Unternehmen – wenn kriminelle Energie im Spiel war. Versehen und Unaufmerksamkeiten kosten ein Unternehmen im Schnitt dagegen nur gut 280.000 Dollar.
Testing kann nicht alles aufdecken
Alle Untersuchungen betrachten den IT-Markt als Ganzes, für den Bereich der Software-Entwicklung und für das Embedded-Umfeld werden keine gesonderten Daten ausgewiesen. Doch gerade hier ist es sehr einfach, Schadcode einzuschleusen und damit direkte Schäden anzurichten. Oder um einen späteren Angriff vorzubereiten – das Stichwort dazu ist Zero-Day Exploit. Backdoors und Timebombs lassen sich relativ einfach im Code eines Projekts verstecken, denn sie sind kaum durch das herkömmliche Testing aufzuspüren: Code, der während des Testings nicht durchlaufen wird, erzeugt keine Fehlermeldungen. Im besten Fall wird er als Dead Code markiert.
Noch schwieriger wird der Schutz vor kriminellen oder geschäftsschädigenden Aktivitäten, wenn extern entwickelter Code zum Einsatz kommt. Und laut VDC Research stammt fast 45 Prozent der Code-Basis aktueller Embedded-Projekte von Dritten. Meist handelt es sich dabei um spezielle Komponenten wie Grafik- und Windowing-Toolkits, Kryptografie-Bibliotheken oder Datenbanken. Ein erheblicher Teil dieser Komponenten liegt binär vor, kann also nicht wie Quellcode von den Entwicklern auf verdächtige Spuren überprüft werden. Doch auch die Quellen sind manuell kaum überprüfbar. Zum einen sind Insider gut darin, bösartigen Code zu kaschieren. Zum anderen müssten bei der Überprüfung neben den Funktionen auch alle Datenströme nachvollzogen werden, um die Verarbeitung von Daten aus unsicheren Quellen – hier spricht man von Tainted Data – zu erkennen. Tools zur statischen Analyse sind in der Lage, die meisten absichtlich eingebauten Sicherheitslücken aufzuspüren. Im Gegensatz zum herkömmlichen Testing wird bei der statischen Analyse der Code nicht ausgeführt, sondern in ein Modell überführt. An diesem analysiert das Tool die Steuerungs- und Datenströme. Eines der wenigen Tools am Markt, dass auch binären Code auf diese Weise analysieren kann, ist CodeSonar von GrammaTech.
Ein typisches Muster für eine Insider-Attacke ist zum Beispiel das Erzeugen von so genannten Untrusted Processes. Das Erzeugen von Kindprozessen ist grundsätzlich nicht ohne Risiken - vor allem dann, wenn der Prozessname oder seine Parameter manipuliert werden können. Hier entsteht im schlimmsten Fall die Möglichkeit zur Command Injection. Bei Untrusted Processes kann nicht sichergestellt werden, ob sie die Sicherheitsvorgaben des jeweiligen Projekts einhalten. Sie können somit potenziellen Schadcode enthalten, um bestehende Sicherheitsmechanismen zu umgehen. Um Untrusted Processes zu erkennen, müssen im Code zunächst alle Calls gefunden werden, die Prozesse erzeugen, um dann die Prozessnamen mit einer Blacklist abzugleichen. Diese enthält als gefährlich eingestufte Befehle und Prozessnamen. Im folgenden Beispiel erfolgt in CodeSonar eine Warnung wegen des genutzten Befehls sh, aber nicht wegen des Prozesses „myprocess“:
#include
#include
void ut_proc(const char *command) {
FILE *pipe_file;
if (pipe_file = (FILE*)popen("/usr/bin/myprocess","r")){
/* Nicht in der Blacklist */
pclose(pipe_file);
}
if (pipe_file = (FILE*)popen("/usr/bin/sh","r")){
/*Erzeugt hier die Warnung 'Untrusted Process Creation' */
pclose(pipe_file);
}
}
CHROOT und Timebombs
Ein weiteres typisches Muster ist der Versuch CHROOT ohne CHDIR auszuführen. Die Linux/Unix-Funktion chroot() (Change Process Root Directory) ist potentiell gefährlich, da Schadcode darüber möglicherweise auf Dateien in anderen Systembereichen zugreifen könnte. Deswegen wird chroot() üblicherweise um ein direkt vor- oder nachgestelltes chdir() (Change Current Process Directory) ergänzt. Im folgenden Beispiel warnt das Analyse-Tool, dass chdir() nicht vor einer Funktionsrückgabe aufgerufen wurde. Eine zweite Warnung weist darauf hin, dass der chdir()-Aufruf von der Variablen fname abhängt.
#include
#include
int chroot_no_chdir(const char *fname, char *buf){
FILE *localfile;
int bytesread=0;
if (chroot("/downloaddir") == -1){
/* Warnung 'chroot without chdir' */
return 0;
}
if (fname){
if (localfile = fopen(fname, "r")){
bytesread = fread(buf, 1, sizeof(buf), localfile);
fclose(localfile);
}
if (chdir("/")==-1){
/* chdir() wird nur aufgerufen wenn fname != NULL */
return 0-bytesread;
}
}
return bytesread;
}
Auch so genannte Timebombs sind bei Insider-Angriffen häufig zu beobachten. Möglich sind die Zeitbomben immer dann, wenn ein Programm Zeitwerte der Systemuhr abruft und benutzt. Gegen sinnvolle Überprüfungen der Systemzeit ist nichts einzuwenden. Aber wenn ein Code gar keine Variable hat, die von der Systemzeit abhängt, sondern einen hartgecodeden Wert? Das könnte ein Hinweis darauf sein, dass das Programm auf ein bestimmtes Datum oder eine bestimmte Zeit wartet, um Schadcode auszuführen. Im folgenden Beispiel ist die Stelle verdächtig, in der die Zeit nicht mit dem Ergebnis des time()-Aufrufs verglichen wird:
void misc_timebomb(void){
time_t deadline = 1893456000;
time_t now = time(NULL);
if (now > time(NULL)){
/* OK: Zeitwert wird mit Zeitwert verglichen */
/* ... */
}
if (now < deadline){
/* Warnung 'Potential Timebomb' Zeitwert wird mit einer anderen Werteart verglichen */
return;
}
/* Bei einer Insider-Attacke könnte hier der Schadcode stehen, der nach Ablauf der Deadline ausgeführt würde. */
}
Binär ist manchmal einfacher
Dass diese Angriffsvektoren keine Theorie sind, hat sich zum Beispiel am freien IRC-Daemon UnrealIRCD gezeigt (CVE-2010-2075), bei dem externe Daten über eine Socket-Verbindung ungeprüft Systembefehle ausführen konnten. Im Quellcode erscheint die betreffende Stelle als ein harmloses Makro zum Debug-Login:
Hinter der Verschleierung steht ein System Call, alles weist auf eine Insider-Sache hin. Im Binärcode hingegen zeigt sich das ganze Ausmaß der Bedrohung. Denn alle Obfuscation-Anstrengungen wurden vom Compiler aufgelöst, der Call fällt sofort ins Auge:
Die Gefahren, die von Insidern ausgehen, sind nicht zu unterschätzen. Denn im Gegensatz zu externen Angreifern verfügen die Insider meist über ein profundes Wissen, das sie einsetzen können. Und gerade das Embedded-Umfeld hat viel Potenzial, zu einem Tummelplatz der Kriminellen zu werden. Denn in vielen Bereichen werden Embedded Devices immer kritischer. Nicht nur für den Unternehmenserfolg. In der Automobilbranche oder der Medizintechnik hängen letztlich Leben daran, dass die Devices wie vorgesehen funktionieren. Für Kriminelle ist diese Situation ein gefundenes Fressen. Die Entwicklungsteams werden diesen Gefahren nur begegnen können, indem sie strikte Prozesse zur Qualitätssicherung und Code-Analyse innerhalb der Software Development Lifecycles etablieren. Und je früher der Code überprüft wird, desto einfacher und günstiger ist die Beseitigung vorhandener Fehler und die Abwehr von Angriffen. Die statische Analyse kann dabei frühzeitig in der Entwicklung und weitgehend automatisiert eine wertvolle Hilfe sein. Denn Vertrauen ist gut, strikte Qualitätssicherung ist besser.
:quality(80)/images.vogel.de/vogelonline/bdb/1390900/1390949/original.jpg)
Sicherheitslücke im Linux-Tool beep als Einfallstor ins System
:quality(80)/images.vogel.de/vogelonline/bdb/1092500/1092518/original.jpg)
Multicore
Effiziente Embedded-Multicore-Programmierung
* Mark Hermeling ist Senior Director Product Marketing bei GrammaTech.
(ID:45319861)