Statische Code-Analyse gegen Insider-Angriffe Time Bombs, CHROOT und verdächtige Prozesse aufspüren

Autor / Redakteur: Mark Hermeling * / Stephan Augsten

Nicht selten kommt es in der Software-Entwicklung zu Insider-Angriffen, indem Schadcode während der Entwicklung in die Anwendung eingebaut wird. Dadurch entstehen Hintertüren, die Angriffe auf das Unternehmen oder auf dessen Kunden ermöglichen. Mit statischer Analyse lassen sich solche Angriffe erkennen, bevor die Software beim Kunden im eigenen Netzwerk in Betrieb geht.

Anbieter zum Thema

Tools zur statischen Analyse sind in der Lage, absichtlich in Software eingebaute Sicherheitslücken aufzuspüren.
Tools zur statischen Analyse sind in der Lage, absichtlich in Software eingebaute Sicherheitslücken aufzuspüren.
(Bild gemeinfrei: typographyimages - Pixabay.com)

„Vom Menschen droht dem Menschen täglich Gefahr.“ Sicher hatte der römische Philosoph und Stoiker Lucius Annaeus Seneca bei seinem Ausspruch nicht die IT im Sinn. Dennoch gilt der Satz uneingeschränkt in der IT-Sicherheit: Viele Sicherheitsvorfälle werden nicht von Hackern verursacht, sondern von Insidern. In der IT-Sicherheit spricht man immer dann von Insider, wenn sich der Angreifer innerhalb des Perimeters befindet. Das können Mitarbeiter der verschiedenen Abteilungen sein, Entwickler oder auch externe Dienstleister.

Im Gegensatz zu den klassischen Cyber-Attacken hat der Angreifer in diesem Fall ganz offizielle Zugriffsrechte zu bestimmten Geräten oder Systemen. Und damit natürlich auch viel mehr Möglichkeiten als ein Außenstehender. Welchen Anteil Insider an den Cyber-Attacken haben, hängt laut IBM X-Force Threat Intelligence Index 2017 von der jeweiligen Branche ab. Im Gesundheitswesen geht jeder vierte Angriff auf das Konto eines böswilligen Insiders, in der fertigenden Industrie sind externe Angreifer mit 96 Prozent die klare Mehrheit. Auch die Zahl der Angriffe, die versehentlich durch die eigenen Mitarbeiter ausgelöst werden, variieren.

Über die Hälfte aller Sicherheitsvorfälle in der Finanzbranche etwa sind laut der IBM-Studie darauf zurückzuführen, während die Mitarbeiter im ITK-Bereich nur bei drei Prozent der Vorfälle unbeabsichtigt einen Anteil hatten. Die Gründe für kriminelles Verhalten sind vielfältig. Geldgier oder Rache am Arbeitgeber, etwa nach einer Kündigung, sind wohl die prominentesten Vertreter in dieser Kategorie. In der Software-Entwicklung bietet es sich für diese Menschen an, die Produkte des Unternehmens mit geplanten Sicherheitslücken zu versehen, die später ausgenutzt werden können - ein besonderer Fall eines Zero-Day-Exploits.

Versteckten Schadcode finden

Tools zur statischen Analyse sind in der Lage, die meisten absichtlich eingebauten Sicherheitslücken aufzuspüren. Die Tools können zudem den Datenstrom von externen Quellen zum verwundbaren Code nachvollziehen (Tainted-Data-Analyse) und damit einen Angriffsvektor verifizieren. Derartige Sicherheitslücken können mit Vorsatz programmiert und so versteckt werden, dass sie innerhalb des weiteren Entwicklungsprozesses unentdeckt bleiben.

Der Angreifer nutzt sie dann zu einem späteren Zeitpunkt für seine kriminellen Zwecke aus. Es ist deswegen unverzichtbar, derartige Schwachstellen mit geeigneten Maßnahmen innerhalb des Software Development Lifecycles aufzuspüren und zu beseitigen. Die Analyse von Binärcode kann im Wesentlichen dieselben Fehler finden wie die Source-Code-Analyse. CodeSonar von GrammaTech ist zudem in der Lage, Source- und Binärcode simultan zu überprüfen. Das ist insbesondere dann wichtig, wenn innerhalb eines Projekts nur vereinzelt binäre Komponenten wie etwa Bibliotheken genutzt werden.

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 <stdlib.h>
#include <stdio.h>
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 Time Bombs

Ein weiteres typisches Muster ist der Versuch, CHROOT ohne CHDIR auszuführen. Die Linux/Unix-Funktion chroot() (Change Process Root Directory) ist potenziell 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 <unistd.h>
#include <stdio.h>
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;
}

Sogenannte Time Bombs sind bei Insider-Angriffen ebenfalls 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 hart gecodeten 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. */
}

Insider-Angriffe sind weder besonders kompliziert noch besonders selten. Dennoch werden sie bei der manuellen Code-Prüfung oder auch beim Testing oft übersehen. Moderne Tools zur statischen Analyse können versteckten Schadcode automatisiert aufdecken. Dabei werden unterschiedliche Arten von Sicherheitslücken sowie verdächtige Datenströme und verschiedene bösartige Codetypen erkannt, bevor die Software zum Kunden geht.

* Mark Hermeling ist Senior Director Product Marketing bei GrammaTech, Inc.

(ID:44934460)