Die Evolution von Angriff und Verteidigung
Wie Schutzmechanismen wiederholt ausgetrickst werden
Wenn ein Ethical Hacker eine Schwachstelle in einem Softwareprodukt findet, zum Beispiel im Rahmen eines Penetrationstests, wird die Schwachstelle an die Hersteller gemeldet. So haben die Entwickler die Möglichkeit Gegenmaßnahmen zu ergreifen und die gefundene Schwachstelle zu beheben. Manchmal kommt es dabei jedoch vor, dass die Lösung der Entwickler nicht die eigentlich zugrundeliegende Schwachstelle behebt.
Jon Erikson hat in seinem Buch “Hacking – Die Kunst des Exploits” ein Beispiel aus der Tierwelt genommen, um eine ständige (Weiter-) Entwicklung von Angreifern und Verteidigern zu beschreiben. Der goldene Pfeilgiftfrosch verfügt über ein außerordentlich toxisches Gift. Bereits eine geringe Menge ist für erwachsene Menschen tödlich. Der Grund, warum diese Frösche eine so starke Verteidigung besitzen ist eine bestimmte Schlangenart, die eine Resistenz gegen das Gift der Frösche entwickelte und die Frösche somit weiterhin als Fressfeindin bedrohte. Im Laufe der Evolution entwickelten die Frösche daher ein immer stärkeres Gift. Eine ähnliche Art der evolutionären Entwicklung ist auch bei Hackern und ihren Gegenspielern zu beobachten.
Ein einfaches XSS Beispiel
Nachfolgend ein einfaches, aber sehr anschauliches Beispiel für eine sehr schlecht geschlossene Schwachstelle: Ein klassischer Cross-Site-Scripting Angriff (XSS) besteht darin, Script-Tags, also:
<script> … </script>
und darin enthaltenen Javascript Code in die Ziel-Webseite einzuschleusen. Eine Lösung, um diesen Angriff abzuwehren, könnte nun darin bestehen, im Backend eine Funktion in den Code einzubauen, die nach diesem Angriff sucht und den schadhaften Code herausfiltert. Dazu wird geprüft, ob der Input des Users die unerwünschten Zeichen enthält. Ist dies der Fall, werden diese einfach gelöscht, bevor der Input weiterverarbeitet wird. Was passiert aber, wenn ein Hacker folgenden Code einschleust:
<scr<script>ipt> </scr<script>ipt>
Die Filter-Funktion im Backend macht ihren Job und filtert das unerwünschte <script> heraus. Übrig bleibt in diesem Fall aber noch das <scr ipt>, was sich in der weitern Verarbeitung und schließlich auf der Webseite automatisch wieder zu einem Script-Tag zusammensetzt und den schädlichen Javascript Code trotzdem ausführt. Als Gegenmaßnahme könnte nun <scr<script>ipt> gefiltert werden und so weiter, aber wirklich zielführend wäre das nicht, denn da wären wir wieder beim Beispiel vom Pfeilgiftfrosch, der sein Gift immer weiter verbessert. Außerdem würde der Filter auch <sCrIpT> nicht erkennen. Das Beispiel soll veranschaulichen, was das Problem mit Filtern ist. Es wird immer Möglichkeiten geben, die Filter auszutricksen.
Daten oder Code? Es kommt drauf an
Das Wesentliche, um zu verstehen, wie das immer wieder gelingt, ist zu realisieren, dass Computersysteme aus vielen einzelnen Teilen bestehen, die miteinander verbunden sind. Das ganze System besteht also aus kleinen Subsystemen, die jeweils eigene Aufgaben haben. Das Problem ist aber, dass die einzelnen Komponenten sehr oft auch auf ganz eigene Weise mit den Daten umgehen, die sie verarbeiten sollen. Es gibt also viele verschiedene Kontexte, in denen Daten verarbeitet werden. Ein Sonderzeichen wird in einem Kontext nur als Text verarbeitet, aber in einem anderen als Teil des Codes. Wenn ein Programm die zu verarbeitenden Zeichen nicht als problematisch erkennt und zum nächsten Programm durchreicht, können sie dort aber ganz neue Probleme verursachen, da sie in einem anderen Kontext verarbeitet werden. Besser wäre es, von Anfang an den Input auf alle möglichen Zeichen abzusuchen, die im gesamten Kontext der Verarbeitung falsch interpretiert werden können und diese entsprechend mit harmlosen Zeichen zu ersetzen. Das kann aber, wie oben beschrieben, aus unterschiedlichsten Gründen nicht immer umgesetzt werden und es entstehen immer wieder Lücken an Stellen, an denen es vorab niemand für möglich gehalten hätte. Eine sehr umfangreiche Auflistung verschiedener Techniken zum Thema Cross-Site-Scripting wurde von der OWASP-Stiftung zusammengestellt und ist unter https://owasp.org/www-community/xss-filter-evasion-cheatsheet zu finden.
Sicherheitssoftware
Mit dem gerade gezeigten XSS-Beispiel wird ein Hacker heutzutage aber eher wenig Erfolg haben. Denn bis auf die sogenannten Zero-Day-Exploits, also bisher unveröffentlichte Schwachstellen, sind die meisten Hacking-Techniken und Exploits im Laufe der Zeit bekannt geworden. Dadurch ist eine ganze Reihe von Technologien entstanden, deren Ziel es ist Exploits zu erkennen und zu verhindern. Das fängt zum Beispiel mit normaler Anti-Virus Software an, die fast jeder User auf dem PC installiert hat und reicht über Firewalls bis hin zu komplexen Intrusion Detection und Prevention Systemen (IDS/IPS). Ein Intrusion Detection System ist eine Sicherheitssoftware, die auf einer hardwarenahen Ebene die Netzwerkpakete abfangen kann. Dadurch wird der gesamte Netzwerkverkehr auf Schadcode untersucht und bei einem Treffer Alarm auslöst. Das IDS verhält sich jedoch rein passiv. Intrusion Prevention Systeme können dagegen nicht nur Alarm schlagen, sondern auch die Pakete zurückweisen, sodass sie gar nicht erst ins Netzwerk gelangen. Hacker wären aber keine Hacker, wenn sie ihre Techniken und Methoden nicht weiterentwickeln und anpassen würden. Eine vermeintlich abgesicherte Schwachstelle wirkt vielleicht gegen eine bestimmte Form eines Angriffs, muss deswegen aber noch lange nicht vollständig sicher sein und bei einer Variation des Angriffs ebenfalls wirken. Ein Schutzmechanismus, oder ein Filter, kann vielleicht trotzdem umgangen werden. Trotz all dieser Maßnahmen zum Schutz gegen Angriffe gibt es also immer wieder Hacker, die zum Teil auf besonders kreativen und ungewöhnlichen Wegen die Abwehrmechanismen umgehen, austricksen oder durchdringen. Wirklich sicher ist kein System und keine Software. Und selbst, wenn zum jetzigen Zeitpunkt eine Sicherheitssoftware umfassenden Schutz bietet, gilt das nur solange, bis ein findiger Angreifer eine neue Lücke findet.
Filter mit besonderen Zeichen austricksen
Im Folgenden noch zwei Beispiele, welche die Evolution von Abwehr- und Angriffsmethoden plastischer machen und verdeutlichen. Eine immer wieder verwendete Technik, schädlichen Code zu verschleiern, bietet die Zeichenkodierung. Ein Zeichen lässt sich auf verschiedene Weisen darstellen, da es im Computer ja im Grunde nur aus Einsen und Nullen besteht und erst auf den von uns sichtbaren Oberflächen als Zeichen interpretiert wird. Auf unserer Welt gibt es aber durch verschiedene Kulturen und Sprachen eine unglaublich große Anzahl an Zeichen, die alle eigene Bedeutungen haben. Durch verschiedene historische Entwicklungen haben sich eine Reihe von unterschiedlichen Zeichensätzen entwickelt. Definiert ein Entwickler also nicht genau, welche Zeichenkodierung in seiner Anwendung zum Einsatz kommen soll, kann ein Hacker versuchen Zeichen aus einem anderen Zeichensatz einzuschleusen, deren Bits das System dann anders als erwartet interpretiert. Dieser Tweet von Samet Sahin (https://twitter.com/sametsahinnet/status/1251968347203424256) verdeutlicht, welche Ausmaße das Ganze annehmen kann, recht anschaulich mit folgenden erfolgreich eingeschleusten Zeichen:
“?<<sVg/onload?=/svg/onload=svg/onmouseOver=confirm`1`><!–?//=”
Hier wurde ein Filter erfolgreich mit Emojis umgangen und eine Cross-Site-Scripting Schwachstelle ausgenutzt. Die Web Application Firewall (WAF) konnte nichts mit den Emoji-Zeichen anfangen und hat den Angriff durchgelassen. Vermutlich werden die Hersteller bald nachziehen und ihre Firewalls mit entsprechenden Updates für Emojis ausstatten. Doch es ist nur eine Frage der Zeit, bis eine neue, noch spezialisiertere Technik erfunden wird, die den Filter wieder umgehen kann.
Druckbarer Shellcode (Für Experten):
Eine andere, sehr spezialisierte Methode ist das Umgehen von Intrusion-Detection/Prevention-Systemen mit alphanumerischem Shellcode. Wir gehen hier nicht auf alle Details ein, aber das Konzept dahinter ist sehr spannend. Stellen wir uns vor, dass eine Anwendung, die Nutzereingaben über eine Netzwerkverbindung empfängt, eine Schwachstelle hat, die zu einem Buffer-Overflow führen kann. Das kann zum Beispiel ein Webserver sein. Wenn ein Hacker nun eine Anfrage mit unerwartet vielen Zeichen sendet, wird der Buffer-Overflow ausgelöst. Nun muss der Hacker es noch schaffen, sogenannten Shellcode einzuschleusen, um den Code-Fluss umzuleiten und die Schwachstelle auszunutzen. Die betroffenen Betreiber der Webanwendung wollen aber auf Nummer sicher gehen und installieren ein Intrusion-Prevention-System, das auf Netzwerkebene alle Bytes, die nicht in den Bereich der druckbaren ASCII-Zeichen fallen, herausfiltert. Shellcode ist Programmcode, der in Maschinensprache geschrieben ist. Das bedeutet, er besteht nur noch aus den Instruktionen, die von der CPU verarbeitet werden können, also zum großen Teil nicht aus druckbaren Zeichen. Die Übermittlung des Shellcodes sieht das IDS/IPS natürlich und lässt nur die Bytes durch, die gleichzeitig auch als Text interpretiert werden können, da es sich dabei ja um reguläre Eingaben eines Nutzers handeln könnte. Ein Shellcode der Bytes wie \x00\x02\xFF beinhaltet, würde also nicht funktionieren, da sie nicht als normale Zeichen darstellbar sind. Was aber, wenn es ein Hacker schafft, seinen Shellcode wie einen regulären Text aussehen zu lassen, in dem er nur Anweisungen wählt, die auch einem gültigen Zeichen entsprechen? Die Shellcode-Instruktion pop rax zum Beispiel, besteht aus dem Byte \x58, was als ASCII Zeichen den Buchstaben X darstellt. Folgende Zeichenkette ist eine Reihe von Assembler Instruktionen, die am Ende eine Shell auf dem System (/bin/sh) ausführen:
Xxj0TYX45Pk13VX40473At1At1qu1qv1qwHcyt14yH34yhj5XVX1FK1FSH3FOPTj0X40PP4u4NZ4jWSEW18EF0V
(https://www.exploit-db.com/exploits/35205) Das Erstaunliche und Kreative hier ist, dass es ausführbarer Shellcode ist, also Bytes, die von der CPU als Instruktionen gelesen werden, der aber gleichzeitig komplett in den Bereich darstellbarer ASCII Zeichen fällt und damit auf einer Filterebene als Text gelesen und als harmlos eingestuft wird.
Fazit:
Diese Beispiele verdeutlichen, dass ein Hack im Grunde das Vermischen von Daten und Code in unterschiedlichsten Kontexten bedeuten kann. Das System weiß nicht mehr, was als Daten verarbeitet und was als Code ausgeführt werden soll. Außerdem wird auch deutlich, wie kreativ Hacker vorgehen, um neue Möglichkeiten zu identifizieren und dabei selbst hoch entwickelte Schutzmaßnahmen überwinden können. Letztlich wird das Katz- und Mausspiel (bzw. Schlange- und Froschspiel) wohl ewig weitergehen.