Hacking Akademie

Quellcode-Analyse – Schwachstellen im Source Code identifizieren

Quellcode-Analyse

Schwachstellen im Source Code identifizieren

Es existieren verschiedene Methoden, um den Code einer Anwendung einem Sicherheitstest zu unterziehen. Eine dieser Methoden ist die Quellcode-Analyse, auch als Static Application Security Testing (SAST) bezeichnet. Dieser Beitrag zeigt die Vorgehensweise von SAST im Überblick und benennt Vor- und Nachteile gegenüber anderen Testing-Verfahren. Die Arbeit eines Ethical Hackers und Penetration Testers ist vielfältig. Neben den klassischen Penetration Tests, bei denen der Pentester die Perspektive des Black Hat Hackers, also eines echten Angreifers einnimmt, gibt es auch andere Formen der Security-Analyse. Hierzu zählt auch das automatisierte Application Security Testing mittels entsprechender Tools. Wir unterscheiden hier verschiedene Varianten, u.a.:

  • Static Application Security Testing (SAST): Hierbei wird der Quellcode “offline” analysiert, also ohne dass die Anwendung läuft.
  • Dynamic Application Security Testing (DAST): In dieser Variante wird die Anwendung ausgeführt und durch gezielte Eingaben geprüft, ob sich das Programm so verhält wie erwartet oder evtl. unerwartet reagiert, ggf. sogar abstürzt.
  • Feedback-based Application Security Testing (FAST): Hierbei handelt es sich um eine Weiterentwicklung des DAST-Ansatzes, bei dem die Eingaben mittels Fuzzing systematisch weiterentwickelt werden. Die Eingabe wird demnach entsprechend des Feedbacks der Anwendung über eine Mutation Engine angepasst, um in jeder folgenden Runde gezieltere Eingaben vorzunehmen, die Fehler in der Anwendung provozieren sollen.

Nachfolgend betrachten wir SAST und stellen Stärken und Schwächen dieser Methode heraus.

Grundlagen der automatisierten Quellcode-Analyse

Quellcode-Analysen sind nicht selten Bestandteil einer Security-Analyse im Rahmen eines Penetration Tests. Dabei wird dem Pentester der Code zur Prüfung im Rahmen eines White-Box-Tests vertraulich zugänglich gemacht. Auch Code, der entweder bewusst oder auch unerwünschter Weise veröffentlicht wurde (hier sprechen wir von “geleaktem” Code), wird in der Regel von verschiedenen Seiten analysiert und überprüft. Die SAST-Methode ist schon lange Zeit gängige Praxis und hat den Vorteil, dass sie bereits frühzeitig in der Entwicklung einer Anwendung zum Einsatz kommen kann. Der zu überprüfende Quellcode muss zum Zeitpunkt der Analyse noch nicht vollständig lauffähig und funktionsfähig sein, da das Programm nicht ausgeführt wird. Stattdessen wird der Quellcode (gängiger Weise auch als Source Code bezeichnet) offline analysiert und auf Schwachstellen geprüft. Heutige Anwendungen umfassen oft viele tausend Zeilen Code und können nicht mehr vollständig manuell geprüft werden. Daher kommen in der Regel entsprechende Tools zum Einsatz, die eine automatisierte Analyse des Codes vornehmen und ihn auf mögliche Schwachstellen untersuchen. Es gibt diverse Open-Source- sowie kommerzielle Tools für alle denkbaren Programmiersprachen. Eine Übersicht bietet die OWASP-Projektseite unter https://owasp.org/www-community/Source_Code_Analysis_Tools. Hier finden sich auch Auswahlkriterien für ein geeignetes Tool.

Vor- und Nachteile der automatisierten Analyse

Die automatisierte Analyse mittels Source Code Analysis Tools hat mehrere Vorteile. Sie skaliert sehr gut und kann jederzeit erneut durchgeführt werden, z.B. wenn täglich neue Versionen der Software während der Entwicklungsphase geprüft werden sollen. Zudem finden derartige Tools bestimmte Fehler mit hoher Zuverlässigkeit. Hierzu gehören Buffer Overflows, SQL-Injection-Schwachstellen und andere. Die Ausgabe der Analyse umfasst die kritischen Code-Zeilen und die genaue Stelle im Code, so dass Entwickler und Pentester das Problem schnell lokalisieren können. Auf der anderen Seite kann dieser automatisierte Ansatz bei weitem nicht alle Schwachstellen aufdecken. So sind Authentifizierungs- und Zugriffsschwachstellen auf diese Art nicht identifizierbar. Zudem hängt es auch stark vom Code und von der Programmiersprache ab, wie genau die automatisierte Analyse durchgeführt werden kann. In jedem Fall muss der Analyst auch mit eine hohen Anzahl von False Positives rechnen, also Fundstellen, die kein echtes Problem darstellen. Auch wenn die Analyse-Tools dem Pentester viel Arbeit abnehmen können, geht es nicht ohne manuelle Detailanalyse. Die offenbarten Fundstellen müssen überprüft werden, um festzustellen, ob es sich im konkreten Fall tatsächlich um eine Schwachstelle handelt, die ausgebeutet werden kann, oder der Code im Kontext ungefährlich für die Integrität der Anwendung ist. Hierzu muss der Analyst zum einen ein fundiertes Verständnis der Programmierkonzepte und der konkreten Programmiersprache mitbringen und zum anderen die Ansätze und Konzepte verstanden haben, nach denen eine manuelle Quellcode-Analyse erfolgt. Dieses Verständnis ist essenziell für eine effektive Analyse.

Von Sources und Sinks

Wirklich elementar ist es zu verstehen, dass jeglicher Input durch die Benutzer der Software pozenziell gefährlich sein kann. Das bedeutet für die Quellcode Analyse, dass alle Punkte, in denen Input verarbeitet wird, identifiziert werden müssen. Dieser Input wird auch “Sources” (zu Deutsch: Quellen) genannt. In vielen Programmiersprachen gibt es zudem eine Reihe potenziell gefährlicher Funktionen. Das können zum Beispiel Funktionen sein, die Befehle auf Systemebene ausführen, oder Funktionen die anderen Quellcode laden und ausführen. Auch zu beachten sind Dateioperationen, also Funktionen, die etwas in eine Datei schreiben oder diese in anderer Art manipulieren, z.B. löschen, ändern, etc. Diese Funktionen werden “Sinks” genannt. Um die “Sinks” (zu Deutsch: Senken) zu finden, kann einfach der komplette Quellcode automatisiert nach den entsprechenden Funktionsnamen durchsucht werden. Da der Analyst sich bei der Analyse von Quellcode auf die potenziell unsicheren Teile konzentrieren muss, kann er nun gezielt nach den Sources und den Sinks suchen. Sind die entsprechenden Teile des Quellcode identifiziert, kann er systematisch nachvollziehen, ob User-Input aus einer der Sources eine der Sinks erreicht. Wenn ja, muss er untersuchen, unter welchen Bedingungen das passiert, denn nicht immer muss sofort eine Schwachstelle vorhanden sein. Wurde der Input auf seinem Weg zur Sink ausreichend geprüft, modifiziert und abgesichert, gibt es grundsätzlich kein Problem.

Vorwärts oder rückwärts?

Oft kommt es dennoch vor, dass Code mit der Zeit auch für die Entwickler sehr komplex und unübersichtlich wird. Je mehr Features und Funktionen eingebaut werden, desto wahrscheinlicher wird es, dass der User-Input an Stellen verarbeitet wird, wo die Entwickler ihn nicht erwarten. Bei der Analyse von Sourcecode kann der Analyst aus unterschiedlichen Richtungen vorgehen. Gibt es zum Beispiel viele Sinks und wenige Sources, ist es sinnvoller, vorwärts durch den Code zu gehen und alle möglichen Wege der Sources zu prüfen. Gibt es hingehen wenige Sinks, so kann er rückwärts durch den Code gehen und prüfen, ob er möglicherweise eine der Sources zurückverfolgen kann.

Den Überblick behalten

Mit diesem Ansatz können viele kritische Probleme entdeckt werden, aber die Konzentration auf den User-Input und die potenziell gefährlichen Funktionen reicht leider nicht. Der Analyst kann jetzt vielleicht ausschließen, dass ein Nutzer Code ausführen, oder etwas Schadhaftes einschleusen kann, aber er weiß dadurch noch nicht sehr viel über den logischen Aufbau und die Funktionalität des Programms. Daher lohnt es sich, nach einem groben Gesamtüberblick den Code in einzelne Funktionsteile zu zerlegen. Welcher Teil des Codes ist verantwortlich für die Authentifizierung der Nutzer? Gibt es eine ‘Passwort-Zurücksetzten’ Funktion? Wo genau kommuniziert der Code mit der Datenbank? Diese und andere Fragen müssen geklärt werden und sind nur ein paar Beispiele dafür, wie Teile der Anwendung über die Sicherheit entscheiden können. Hier sollte vor allem auch darauf geachtet werden, wie der Code logisch aufgebaut ist, welche Prüfungen es gibt, welche Funktionen zur Überprüfung verwendet werden und wie komplex und unübersichtlich der Code wirklich ist.

Vergleich mit anderen Analyseverfahren

Es wird deutlich, dass SAST ein wichtiges Mittel zur Security-Analyse von Anwendungen ist, jedoch nicht das Allheilmittel darstellt. Durch die zahlreichen Falschmeldungen eines SAST-Tools besteht die Gefahr, dass bei der Analyse wichtige Fehler übersehen werden. Eine derartige Analyse ist trotz Automatisierung häufig aufwändig, wenn alle Meldungen auf ihre Relevanz geprüft werden müssen. Zudem tun sich SAST-Tools schwer mit heutigen, immer komplexeren Frameworks, da viele Funktionen aus externen Quellen eingebunden werden und daher in einigen Fällen nicht immer der gesamte Quellcode zur Verfügung steht. Eine statische Analyse des Source Codes sollte daher durch weitere Techniken ergänzt werden. In jedem Fall bietet sich das Dynamic Application Security Testing (DAST) mit seinen Varianten an. Bei diesem Ansatz wird zur Laufzeit mit dem Programm interagiert, um dessen Feedback und Reaktion zu testen. Dies bietet den Vorteil, dass nur sehr wenige False Positives erzeugt werden, hat aber andersherum das Problem, dass auch bei sorgfältiger Auswahl der Eingangswerte nicht der gesamte Code getestet werden kann. Jede Analyseform hat ihre Vor- und Nachteile. Daher sollte sich ein Analyst klar darüber sein, welche Aussagekraft die jeweils eingesetzte Variante hat und wo ihre Grenzen liegen.