Exploits entmystifiziert, Teil 1 Wie ein Angreifer Schadcode ins System schleusen kann

Autor / Redakteur: Thorsten Henning* / Stephan Augsten

Der Exploit ist ein wichtiges Mittel, um in IT-Systeme vorzudringen. Unverzichtbar sind Exploits beispielsweise für Advanced Persistent Threats, kurz APTs. Doch was macht diesen Angriffsvektor aus und wie wird er genutzt? Diese Beitragsreihe soll Aufklärung leisten.

Firma zum Thema

Um unbemerkt Schadcode auf einem System auszuführen, muss ein Angreifer sich zunächst einmal Zugriff zum System verschaffen.
Um unbemerkt Schadcode auf einem System auszuführen, muss ein Angreifer sich zunächst einmal Zugriff zum System verschaffen.
(Bild: Archiv)

Exploits gibt es schon lange, doch erst seit den letzten Jahren ist der Begriff weit verbreitet und anerkannt als Hauptangriffsvektor. Um zu verstehen, wie Exploits funktionieren, bedarf es eines gewissen Grundwissens, wie Anwendungen verarbeitet und ausgeführt werden und wie dieser Prozess böswillig manipuliert werden kann.

Im ersten Teil dieser Reihe geht es um die Bausteine von Exploits, einschließlich der wichtigsten Motivationen, verschiedenen Techniken sowie der Entwicklung von Schutzmechanismen und Gegenmaßnahmen. Zudem sollen Antworten geliefert werden auf folgende Fragen:

  • Was ist der Unterschied zwischen Sicherheitslücke (Vulnerability) und Exploit?
  • Was bedeutet es, wenn ein Software-Anbieter die Sicherheitsanfälligkeit als kritisch sieht?
  • Warum können Exploits nicht von Signatur-basierten Lösungen erkannt werden?
  • Was ist der Unterschied zwischen Stack-Overflow und Use-After-Free-Vulnerabilities?
  • Was ist der Unterschied zwischen einer Speicherbeschädigung und Java-Schwachstellen?

Zunächst werfen wir einen Blick auf Speicherfehler-Exploits und ihre kritische Rolle in der Bedrohungslandschaft.

Das Problem des Remote-Angreifers

Attacken können aus vielen Gründen erfolgen, aber was auch immer die Motivation ist: Um seine Mission zu erfüllen, muss ein Angreifer Code auf einem infizierten Computer ausführen. Dieser Code könnte zur heimlichen Datenexfiltration, zum Löschen von Festplatten oder zum Sabotieren eines SCADA-Systems dienen. Um ausgeführt zu werden, muss der Code aber erst das Ziel des Angriffs erreichen.

Das offensichtliche Problem besteht darin, dass unter normalen Umständen der Angreifer keinen Zugriff auf seine Zielmaschine hat. Exploits stellen eine Lösung für das Problem des Fernangreifers dar. Der Exploit gibt dem Angreifer Benutzerrechte auf dem übernommenen Computer. Der Exploit ist somit das Mittel, mit dem der Angreifer in einem infizierten Computer Fuß fasst.

Um das zu erreichen, zielen Angreifer auf die Anwendungen, mit denen Benutzer normalerweise mit externen Inhalten interagieren. Die am häufigsten verwendeten Anwendungen sind Browser, Leser, Spiele und Microsoft-Office-Dokumente. Angreifer versuchen, ihren Code in einer Datei einzubetten, die die Anwendung, auf die sie abzielen, öffnen wird. Erst danach kommen die Hauptkomponenten eines Angriffs zum Einsatz: Backdoor, C2C-Kommunikation, Key-Logger etc., die heruntergeladen und ausgeführt werden.

Exploit-Bausteine – Schwachstellen und Shellcode

Anwendungen akzeptieren Eingaben und verarbeiten diese. Theoretisch könnte diese Eingabe entweder ordnungsgemäß sein und ausgeführt werden oder fehlerhaft sein und abgelehnt werden. In der Praxis gibt es jedoch auch noch eine dritte Möglichkeit, bei der die Datei tatsächlich manipuliert ist, aber von der Anwendung akzeptiert wird. Die Anwendung startet mit dem Ausführen der Datei, aber irgendwo entlang der Strecke wird die Ausführung vom vorgezeichneten Weg abweichen und bringt die Anwendung zum Absturz.

Um zu verstehen, warum dies passiert, gilt es einen Blick darauf zu werfen, was passiert, wenn ein Programm ausgeführt wird. Ein ausgeführtes Programm wird als Prozess betrachtet. Das Betriebssystem ordnet dem Prozess einen Speicheradressraum zu, der den Code und die Daten des Prozesses enthält. Der Prozess-Speicherplatz ist der Spielplatz, wo der Prozess ausgeführt und wird uns durch die gesamte Serie begleiten. Wir werden später tiefer eintauchen, um zu aufzuzeigen, wie dieser Raum strukturiert ist.

In der Zwischenzeit liegt das Interesse im Prozessadressraum an der Tatsache, dass ein ausgeführter Prozess eine bloße Folge von Speicheradressen sein kann. Diese Adressen werden zu einem bestimmten Zeitpunkt vom Prozessor (Central Processing Unit, CPU) nach einer vorgezeichneten Sequenz abgerufen. Die CPU führt die Anweisungen in der abgerufenen Adresse aus und geht weiter zur nächsten und so weiter und so fort, bis zur letzte Anweisung den Prozess verlässt.

So läuft es ab, wenn die Datei ordnungsgemäß ist. Jedoch weicht in dem oben beschriebenen Szenario zu einem gewissen Punkt in der Sequenz der Ausführungsablauf ab. Die CPU wird aufgerufen von einer Adresse, die keine Anweisungen enthält, die Ausführung stoppt. Dies entspricht in etwa dem, was passiert, wenn ein Prozess/Programm abstürzt.

Bis zu diesem Zeitpunkt haben wir noch nichts Bösartiges beschrieben. Die Tatsache, dass Anwendungen fehlerhafte Eingabedateien akzeptieren, statt alle abzulehnen ist eine integrierte Komponente des Programmierens. Die Programmierer sind per Definition nicht in der Lage, alle möglichen Dateiveränderungen vorherzusagen.

Die Perspektive des Angreifers

Aus der Perspektive des Angreifers ist dies ein attraktives Szenario. Wenn eine bestimmte fehlerhafte Eingabe bewirkt, dass der Ausführungsablauf zu einer leeren Adresse abweicht, könnte eine Eingabe auch in Handarbeit erfolgen, um diese leere Stelle mit Anweisungen des Angreifers zu überschreiben. In diesem Fall würde der Ausführungsablauf nicht mehr abstürzen, sondern stattdessen umgeleitet werden.

An diesem Punkt verstehen wir, wie ein Angreifer die Kontrolle über die Prozessausführung gewinnen kann. Wir haben aber noch nicht verstanden, was es zu gewinnen gilt. Der Speicherplatz, in dem der Angreifer ist, ist immer noch der Speicherplatz, den der Prozess von Betriebssystem zugewiesen bekommen hat – und in diesem Raum ist der einzige gültige Code der Anwendungscode.

Wie der Angreifer endgültig die Kontrolle übernimmt

Was aber, wenn der Speicherraum einen schlafenden Schadcode enthält? In diesem Fall kann der Angreifer die Kontrolle nutzen und den Ausführungsfluss umleiten, um den Code auszuführen. Die CPU wird die Ausführung fortsetzen, da sie mit gültigen Anweisungen gespeist wird. Wenn dieses kleine Stück Code, zusätzlich zur Ausführung, eine Verbindung zwischen dem Computer des Angreifers und des Opfers öffnen würde, wäre der Angreifer in der Lage, den Computer mit legitimen Benutzerberechtigungen aus der Ferne zu steuern.

Um die Kontrolle über einen infizierten Computer zu übernehmen, muss der Angreifer eine Anwendungseingabe (in der Regel eine Datendatei) auf die folgende Weise in Handarbeit erstellen:

  • 1. Ein Stück Code in der Datei einbetten, die eine Verbindung zwischen dem Angreifer und dem Zielcomputer öffnen wird, wenn sie ausgeführt wird.
  • 2. Die Datei manipulieren, so dass der Ausführungsablauf von seinem Weg abweicht (wie bereits erklärt).
  • 3. Berechnen der vorhergesagten Position der Adresse, wohin des Prozesses abweicht und Füttern der Adresse mit dem Standort des Codes des Angreifers.

Nach Abschluss dieser vorbereitenden Schritte muss der Angreifer sicherstellen, dass der Zielbenutzer tatsächlich diese manipulierte Datei öffnen wird. Dies erfolgt in der Regel durch Social Engineering, in Form eines E-Mail-Anhangs (die manipulierten Dateien wären in diesem Fall Office-Dokumente, Reader etc.) oder durch die Kompromittierung einer gern besuchten Webseite.

Wenn der Benutzer auf der Webseite surft oder die Anlage öffnet, wird die Kette, wie beschrieben, ausgelöst: Die Anwendung startet die Ausführung. An einem bestimmten Punkt, ohne dass der Anwender es überhaupt bemerkt, weicht der Ausführungspfad ab, die umgeleitete Adresse wird überschrieben.

Der Ausführungspfad wird in Richtung eingebetteten Codes des Angreifers umgeleitet. Der Code wird ausgeführt werden und eine Verbindung zwischen der Maschine des Angreifers Maschine und dem Zielbenutzer wird eingerichtet. Von diesem Moment an ist der Endpunkt, also die Maschine des Benutzers, kompromittiert und der Angreifer kann jede Malware, je nach spezifischen Bedürfnissen, herunterladen.

Gängige Terminologie

Wir können nun die folgenden Begriffe definieren:

  • Eine Sicherheitslücke/Schwachstelle (Vulnerability) ist ein Fehler in der Anwendung, der beim Ausführungsfluss bewirkt, von seinem vorgesehenen Pfad abzuweichen, wenn versucht wird, eine fehlerhafte Datendatei zu verarbeiten. Verschiedene Schwachstellen entsprechen verschiedenen Manipulationsvarianten. Eine Schwachstelle ermöglicht es einem Angreifer, einen Prozessausführungsablauf abzufangen. Die Sicherheitslücke an sich bietet nur die Möglichkeit für eine Kompromittierung.
  • Ein Shellcode ist ein kleiner Code des Angreifers, eingebettet in der manipulierten Eingabedatei. Der Shellcode stellt die Verbindung zwischen dem Angreifer und dem Zielcomputer her. Diese Verbindung wird weiter genutzt, um das Ziel auszuspionieren und zusätzliche Malware herunterzuladen.
  • Ein Exploit ist der Code, der den Ausführungsablauf von der überschrieben Adresse zum schlafenden Shellcode umleitet. Ein erfolgreicher Angriff wird durchgeführt, wenn der Shellcode ausgeführt und eine Verbindung zwischen dem Angreifer und dem Zielrechner hergestellt wird.

Der Exploitation-Prozess setzt sich somit aus den folgenden Teilen zusammen: Überschreiben einer Adresse im Prozess-Speicherraum > Umleiten der Ausführungsabfolge zur Shellcode-Adresse > Ausführen des Shellcodes. In den kommenden Teilen dieser Reihe geht es um verschiedene Arten von Schwachstellen und die Hauptimplementierungen dieser drei Komponenten.

* Thorsten Henning, Senior Systems Engineering Manager Central & Eastern Europe bei Palo Alto Networks.

(ID:43725378)