Telerik Remote Code Execution

Telerik Remote Code Execution 100 Mal schneller erreichen

Zusammenfassung 

Eine 2017 entdeckte kryptografische Schwachstelle in der Entwicklungssoftware Telerik UI galt lange Zeit als nicht ausnutzbar. Bis jetzt. Untersuchungen von Security Research Labs (SRLabs) zeigen, dass diese Nicht-Ausnutzbarkeit nur auf die nicht optimierte Natur des öffentlich verfügbaren Exploits zurückzuführen war. Durch Optimierungsstrategien wurde ein praktikabler Exploit für die Remotecodeausführung innerhalb der Infrastruktur enthüllt. Erfahre, wie die Telerik-Schwachstelle aus dem Jahr 2017 in einem großen Unternehmen im Jahr 2021 erfolgreich ausgenutzt wurde, welche Optimierungstechniken eingesetzt wurden, die auch auf ähnliche kryptografische Probleme in anderer Software angewendet werden können, und wie du deine Infrastruktur schützen kannst.  

Dieser Beitrag vermittelt ein Verständnis für die Sicherheitslücke und den ursprünglichen Exploit. Vor diesem Hintergrund wird eine neue, optimierte Version des Exploits entwickelt. Abschließend werden die wichtigsten Erkenntnisse in Bezug auf die Optimierung des Exploits zusammenfassend dargestellt. 

Einführung 

Während eines Red Team-Einsatzes wurde bei der Tochtergesellschaft eines Fortune500-Unternehmens eine Schwachstelle gefunden: eine kryptografische Schwachstelle in Telerik UI (CVE-2017-9248). Der öffentlich verfügbare Exploit war jedoch ineffizient und verhinderte einen schnellen und unentdeckbaren Zugriff. 

Durch verschiedene Optimierungsstrategien konnte das Team die Geschwindigkeit des Exploits für den durchschnittlichen Fall um etwa das 100-fache erhöhen. 

Die Geschwindigkeit des Exploits erhöhte sich um das 250-fache, was zu 78k/314 und 39k für den schlimmsten Fall führte. 

Dadurch konnte das Red Team Fuß fassen und schließlich zum Hauptquartier vordringen. 

Hacken von Anwendungen mit Progress Telerik Produkten 

Progress Telerik entwickelt User Interface (UI) Controls und Komponenten für .NET- und JavaScript-Frameworks, um ansprechende Anwendungen zu entwickeln. Mehr als 275.000 Kunden, darunter Visa, Microsoft und Samsung, setzen Telerik-Produkte ein. Allerdings ist nur ein Produkt, Telerik UI for ASP.NET AJAX, von dieser speziellen Sicherheitslücke betroffen. 

Das von CVE-2017-9248 ausgehende Risiko 

Im Jahr 2017 identifizierten Forscher eine kryptografische Schwachstelle in einer Komponente des Telerik-Produkts. Die Komponente DialogHandler ruft Dateibrowser (Web UI Dialog Windows) auf und empfängt Klartext und verschlüsselte Parameter über eine URL. Zwei dieser verschlüsselten Parameter spielen eine entscheidende Rolle bei der Bestimmung, ob Datei-Uploads erlaubt sind, und bei der Angabe der zulässigen Dateierweiterungen. Wenn ein Hacker das Geheimnis erraten oder sich Zugang dazu verschaffen kann, kann er einen Dateibrowser aufrufen und Dateien hochladen, wodurch anfällige Websites durch das Hochladen von .aspx-Web-Shells kompromittiert werden könnten. Obwohl Forscher diese Sicherheitslücke 2017 entdeckten, ist sie selbst bei aktuellen Einsätzen noch weit verbreitet. 

Langsamer und leicht aufzuspürender öffentlicher Exploit 

Das Team fand schnell den Exploit, der ihm theoretisch den Zugriff auf die Infrastruktur des Unternehmens ermöglichen würde. Das Team entschied sich jedoch, die Ausführung des Exploits abzubrechen, als es feststellte, dass das Knacken des Schlüssels zu langsam war und eine erhebliche Menge an Rauschen erzeugte. Ein begrenzter Zeichensatz des Schlüssels und die Nichtberücksichtigung von Zeitbeschränkungen bei Simulationen können zu anderen Ergebnissen führen. 

Um einen praktikablen Exploit zu entwickeln, beschäftigte sich das Team eingehender mit der Schwachstelle und versuchte, sie zu optimieren. 

Vertiefter Einblick in CVE-2017-9248 

Die Komponente DialogHandler.aspx zieht die Aufmerksamkeit von Hackern auf sich, da sie beim Aufrufen von Fenstern Funktionen zum Hochladen und Erweitern von Dateien bietet. Die Anfrage gibt diese Parameter im Argument „dp“ an, und sie werden mehrfach umgewandelt, bis die Klartextargumente abgeleitet sind (siehe Abbildung 1). Der Exploit zielt darauf ab, den auf dem Server gespeicherten geheimen Schlüssel zu ermitteln, den er dann in einer XOR-Operation zur Entschlüsselung der Parameter einsetzt. 

Das Senden verschiedener Parameter an den Server führt zu unterschiedlichen Fehlermeldungen (Hinweis: Die im Blog gezeigten Fehlermeldungen sind Abkürzungen). Diese Fehlermeldungen können zum Erraten des geheimen Schlüssels verwendet werden. 

 

Abbildung 1: Erstellung eines Dialogfensters anhand von URL-Parametern 

Tabelle 1 zeigt die drei potenziellen Fehlermeldungen, die zum Erraten des geheimen Schlüssels verwendet werden, und gibt ihre jeweilige Position in der serverseitigen Abfolge an: Die positive Fehlermeldung, die als „Index out of range“-Fehlermeldung bezeichnet wird, tritt während Schritt 4 auf und bedeutet, dass der erratene Schlüssel ein potenzieller Kandidat ist (ohne seine Richtigkeit zu bestätigen). Die Meldung „No valid base64“ zeigt an, dass er falsch ist. Die Meldung „String ist zu kurz“ muss hier der Vollständigkeit halber nicht aufgeführt werden, da der Server immer base64-kodierte Strings empfängt und diese immer ein Vielfaches von 4 sind. 

 

Tabelle1: Drei mögliche Fehlermeldungen und ihre Bedeutung 

Abbildung 2 zeigt die kodierten Zeichenfolgen, die an den Server gesendet wurden, und die entsprechenden Fehlermeldungen. Die Fehlermeldung von Anfrage 7 zeigt eine erfolgreiche Dekodierung, XOR-Verknüpfung und gültige base64-Generierung. 

Hinweis: Dieses Vorkommnis kann zufällig sein und bestätigt nicht die Richtigkeit des von uns erratenen Schlüssels

 

Abbildung 2: Verschiedene verschlüsselte Zeichenfolgen und entsprechende Fehlermeldungen 

Abbildung 3 gibt einen detaillierteren Überblick über die Kette der Vorgänge auf der Serverseite. Sie veranschaulicht den Austausch zwischen dem Senden der verschlüsselten Zeichenfolge an den Server und dem Empfang der Antwort von diesem. 

 

Abbildung 3: Unterschiedliche verschlüsselte Zeichenfolgen im Kontext der Prozesskette 

Grundlegende Annahmen für Exploits 

Bevor auf die Exploits eingegangen wird, müssen zwei grundlegende Annahmen geklärt werden, um die Vergleichbarkeit der Exploits zu gewährleisten: 

  • Das Team ging davon aus, dass der geheime Schlüssel aus allen 95 druckbaren ASCII-Zeichen bestehen kann. 
  • Wenn der Benutzer in der web.config keinen Schlüssel festlegt, gibt es mehrere Fallback-Methoden, die automatisch einen Schlüssel mit einer Länge von 48 Zeichen erzeugen. Das Team nahm daher an, dass der geheime Schlüssel eine Standardlänge von 48 Zeichen hat. 
  • Um die Schwachstelle auszunutzen, ist es notwendig, die genaue Version von Telerik UI zu haben (z.B. 2017.3.913) und diese zusammen mit den anderen Parametern zu verschlüsseln. Der Einfachheit halber wurde dieses spezifische Detail in der ursprünglichen Studie weggelassen. 

Die Forscher analysierten 3 Möglichkeiten, die Schwachstelle auszunutzen: 

  1. Exploit 0: Triviales nicht-optimiertes Brute-Forcing
  2. Exploit 1: Ein optimierter erster praktikabler Exploit 
  3. Exploit 2: Ein vollständig optimierter Exploit 

Exploit 0: Triviales Brute-Forcing 

Der trivialste Ansatz zum Brute-Forcing des geheimen Schlüssels besteht aus drei verschachtelten Schleifen: ‍ 

  1. Schleife 1 durchläuft jeden der 12 geheimen Schlüsselblöcke, die jeweils aus 4 Zeichen bestehen (12).‍ 
  2. Schleife 2 durchläuft jede Schlüsselzeichenkombination für jeden dieser geheimen Schlüsselblöcke (95^4). ‍ 
  3. Schleife 3 durchläuft alle möglichen Kombinationen für den Klartext (64^4) und verschlüsselt jede dieser Kombinationen mit den Schlüsselzeichenkombinationen aus Schleife 2. 

Das Testen aller möglichen Kombinationen des Klartextes und das Erhalten einer konsistenten positiven Fehlermeldung von einem geheimen Schlüsselblock zeigt an, dass der richtige geheime Schlüsselblock gefunden wurde. Dieser Ansatz kann extrem lange dauern, da er die verfügbaren Informationen nicht nutzt. So lässt sich z. B. nicht feststellen, welches Zeichen des Schlüssels die Entschlüsselung überhaupt erst zum Scheitern gebracht hat. Daher können bis zu 12 * 95^4 * 64^4 Anfragen erforderlich sein, was astronomisch hoch ist. 

Abbildung 4: Pseudocode des Exploits 0 

Die Methode, die SRLabs ganz am Anfang ausprobiert hat, besteht aus vier verschachtelten Hauptschleifen: 

  1. Schleife 1 durchläuft die gesamte Schlüssellänge (48), um jedes Schlüsselzeichen einzeln zu erraten. 
  2. Schleife 2 durchläuft alle Auffüllungszeichen. Base64 erfordert Auffüllzeichen, da die Eingabe in Vielfachen von 4 erfolgen muss, und der Exploit-Code prüft jedes Schlüsselzeichen einzeln. Zur Ermittlung des zweiten Schlüsselzeichens sind beispielsweise zwei Auffüllungszeichen erforderlich. Das Auffüllen (wenn es korrekt ist) hilft auch, sich auf jeweils ein Schlüsselzeichen zu konzentrieren, d. h. es hilft, einen Fehler für ein einzelnes Zeichen auszulösen. 
  3. Schleife 3 durchläuft den Schlüsselzeichensatz, der aus allen möglichen Zeichen für den Schlüssel besteht. 
  4. Schleife 4 durchläuft die Genauigkeitsschwelle, die aus allen möglichen Zeichen besteht, die im (base64-kodierten) Klartext vorkommen können (d. h. 64 Zeichen). In dieser letzten Schleife wird der Klartext erstellt, für den geprüft wird, ob der (bisher vermutete) Schlüssel funktioniert. Es wird davon ausgegangen, dass bei einem korrekten Schlüssel jeder Klartext, der auf der Hackerseite verschlüsselt wurde, auf der Serverseite entschlüsselbar sein sollte. 

Wenn der Klartext nicht funktioniert, wird in Schleife 3 ein neues Schlüsselzeichen für dasselbe Padding gewählt. Sobald der Exploit alle Schlüsselzeichen durchlaufen hat, wird er das gleiche Verfahren beim nächsten Auffüllen durchlaufen. Bei einer Drosselung von einer Sekunde könnte dies bis zu 2,37 Jahre dauern oder 48 (Anzahl der Zeichen im Schlüssel) * 256 (Anzahl der Auffüllzeichen) * 95 (Anzahl der Zeichen im Schlüsselzeichensatz) * 64 (Genauigkeitsiterationen) Anfragen. 

In Wirklichkeit ist der ungünstigste Fall etwas schneller, da die Suche nach einem gültigen Auffüllzeichen mit abnehmenden Auffüllzeichen in jedem Block schwieriger ist. Um das erste Schlüsselzeichen eines Blocks zu finden, sind 3 Auffüllungszeichen erforderlich, während für die Bestimmung des dritten Schlüsselzeichens nur 1 Auffüllungszeichen notwendig ist. Daher gibt es verschiedene Worst-Case-Szenarien in Abhängigkeit von der Anzahl der benötigten Auffüllzeichen. 

Abbildung 5: Pseudocode des Exploits 1 

Exploit 1 verwendet mehrere Optimierungsstrategien. Er konzentriert sich auf die Verringerung des Möglichkeitsraums durch die Verwendung von Auffüllungen und vordefinierten Zeichensätzen für den geheimen Schlüssel. Eine weitere Optimierung ist jedoch erforderlich, um die Informationen über die Arbeitsauffüllungen aus Schleife 2 für jede neue Iteration der Schlüsselzeichen wiederzuverwenden. 

Exploit 2: Der vollständig optimierte Exploit 

Der Forschungsansatz von SRLabs, bei dem eine Drosselung von einer Sekunde angenommen wurde, führte zu einer Dauer von schlimmstenfalls 32 Minuten. Im Gegensatz zu anderen Exploits, die mögliche Schlüsselzeichen bestätigen, wurden bei diesem Ansatz Sonden gesendet, um Gruppen von potenziellen Schlüsselzeichen auszuschließen. Dabei wurden offline positive oder negative Fehlermeldungen für jedes verschlüsselte Zeichen und jedes mögliche Schlüsselzeichen ermittelt. Der Prozess bestand aus vier Schritten: 

  1. Schritt 1: Auswahl von drei verschlüsselten Zeichen, die den Schlüsselzeichensatz in drei Gruppen („Buckets“) gliedern 
  2. Schritt 2: Ermitteln aller möglichen Kombinationen dieser verschlüsselten Zeichen und Sortieren nach Wahrscheinlichkeit 
  3. Schritt 3: Verwendung der sortierten Kombinationen der verschlüsselten Zeichen, um herauszufinden, zu welchem Bucket die 4 Zeichen eines Schlüsselblocks gehörten 
  4. Schritt 4: Durchführen von Teilen und Überwinden für jedes Schlüsselzeichen 

Vereinfachtes Beispiel 

  • Angenommen, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E und F sind die möglichen Schlüsselzeichen
  • 0, 1, 2, 3, 4, 5, 6, 8 und 9 führen zu einer positiven Fehlermeldung, wenn sie mit dem verschlüsselten Byte ‚0x??‘ XOR-verknüpft werden (vereinfachtes Beispiel, es wird kein bestimmtes Byte angegeben)
  • A, B, C, D, E und F führen zu einer negativen Fehlermeldung
  • Wenn ‚0x??‘ an den Server gesendet wird und ein schlechtes Ergebnis liefert, sind die möglichen Schlüsselzeichen A, B, C, D, E und F
  • Im nächsten Schritt wird ein verschlüsseltes Zeichen ermittelt, das für die Hälfte der möglichen Schlüsselzeichen ein positives oder negatives Ergebnis liefert
  • Das Teilen und Erobern wird fortgesetzt, bis es nur noch ein mögliches Zeichen gibt. 

Schritt 1 

Zunächst werden die Detektor-Bytes benötigt, die die Schlüsselzeichen in Buckets unterteilen. Ein Detektorbyte eines Buckets führt immer zu einem gültigen Basis-64-Zeichen, wenn es mit Zeichen aus diesem Bucket XOR-verknüpft wird. Tabelle 2.1-4 zeigt die Ergebnisse von XOR-Kombinationen verschiedener Beispiel-Detektorbytes und Schlüsselzeichen. Die grüne Farbe zeigt an, dass das XOR-Ergebnis ein gültiges Basis-64-Zeichen ist (d. h. eine positive Fehlermeldung). 

 

Tabelle 2: Beispiel für XOR-Ergebnisse 

Das erste Erkennungsbyte sollte einen großen Bereich von Zeichen abdecken, um schnell eine positive Fehlermeldung für Divide-and-Conquer zu finden. Sie ermittelten drei Bytes für alle 95 druckbaren ASCII-Zeichen und teilten die Schlüsselzeichen in drei Bereiche ein (Tabelle 3). 

 

Tabelle 3: Schlüsselbereiche und ihre Detektor-Bytes 

Wenn ein Kennwort das Zeichen „=“ enthält, das ein gültiges base64-Zeichen ist, können Sie eine spezielle Technik oder Umgehung anwenden. Wir werden hier jedoch nicht auf die Einzelheiten dieser Technik eingehen. 

Schritt 2‍ 

Im nächsten Schritt müssen wir alle möglichen Kombinationen von Detektor-Bytes ermitteln. Die Anordnung nach der Wahrscheinlichkeit minimiert die Anzahl der Anfragen, die erforderlich sind, um die erste gültige Kombination herauszufinden. Es muss sichergestellt werden, dass jede Position der 4 Zeichen zunächst mit dem Byte des größten Buckets (d. h. 0x0) und dann nacheinander mit Bytes kleinerer Buckets (d. h. 0x6B und 0x8) geprüft wird. Der Grund hierfür ist folgender: Wenn 0x0 eine negative Fehlermeldung auslöst, bedeutet dies, dass die potenziellen Schlüsselzeichen in den mit 0x6B oder 0x8 verbundenen Buckets vorhanden sind. Wenn 0x6B einen negativen Fehler ergibt, bestätigt das Senden von 0x8 die Annahme druckbarer ASCII-Zeichen. 

  

Tabelle 4 zeigt die geordneten Detektorbytes nach Eintrittswahrscheinlichkeit. 

Schritt 3‍ 

In Schritt 2 ordnete und sendete das Team Kombinationen von Detektor-Bytes, um gültige Bereiche für die 4 aufgedeckten Zeichen zu finden. Sie bezeichneten diesen Prozess als Entscheidungsbaum und stellten ihn in Abbildung 7 dar, da jede Serverantwort die nächste Anfrage beeinflusst. Wenn sie beispielsweise bei der dritten Anfrage eine positive Antwort erhielten (0x0 0x0 0x6B 0x0), schlossen sie daraus, dass das erste, zweite und vierte Zeichen zum ersten Bucket gehören, der alle base64-Zeichen umfasst. Das 3. Zeichen gehört zum zweiten Bucket (siehe Abbildung 7). 

 

Abbildung 6 Entscheidungsbaum zum Auffinden der ersten gültigen Kombination von Detektor-Bytes 

Schritt 4 

Die Forscher hatten eine gültige Detektor-Byte-Kombination für einen Schlüsselblock (z. B. {0x6B, 0x0, 0x0, 0x0}). Sie identifizierten ein Divide-and-Conquer-Byte (0x6B) für das erste Detektor-Byte. Die Hälfte der möglichen Schlüsselzeichen gibt eine positive Fehlermeldung zurück, die andere Hälfte eine negative, wobei eine positive Fehlermeldung die erste Hälfte und eine negative Fehlermeldung die zweite Hälfte des Schlüsselzeichens anzeigt. Auf diese Weise wird wiederum ein Entscheidungsbaum analog zum Entscheidungsbaum des Detektor-Bytes erstellt (Abbildung 7). Der Prozess wird solange wiederholt, bis das Schlüsselzeichen eindeutig identifiziert ist. Dann wird der gesamte Prozess für das zweite Detektorbyte (0x0) mit einem anderen Bucket wiederholt. Im schlimmsten Fall würde es 32 Minuten (Drosselung bei einer Sekunde) für die benötigten Anfragen dauern. 

Wichtigste Erkenntnisse 

Diese Forschungsarbeit zeigt, wie man durch Optimierung den ursprünglich langsamen öffentlichen Exploit praktikabel machen kann. Die SRLabs-Forscher fassten einige von ihnen angewandte Optimierungsstrategien zusammen, die Entwickler auch bei der Entwicklung anderer Exploits anwenden können: 

  1. Verstehe die Schlüsselkonzepte hinter dem Problem und seine Auswirkungen: Ein sehr einfaches Beispiel ist XOR. Das Verständnis seiner Funktionsweise und der Eigenschaft von XOR mit 0x0 ist entscheidend. Dieses Verständnis hat die Entwicklung des Konzepts rund um die Detektor-Bytes überhaupt erst ermöglicht. 
  2. Überlege vor der Ausnutzung, wie du aktiv Informationen generieren kannst: Beginne damit, so viele Informationen wie möglich zu sammeln und das Rauschen zu reduzieren. Es ist logisch, mögliche Simulationen zu untersuchen und herauszufinden, wie sie zusätzliche Informationen für die Ausbeutung beitragen können. In diesem Fall ermittelte das Team, wie der Zielserver auf bestimmte Eingaben reagieren würde, und machte sich das Wissen über das Verhalten zunutze. Dies funktionierte, ohne eine einzige Anfrage an den Zielserver zu senden. 
  3. Überlege, wie du Informationen während der Verwertung (wieder-)verwenden kannst: Bei der Optimierung geht es darum, verfügbare Informationen geschickt zu nutzen. Das bedeutet, dass alle hilfreichen Informationen in den Antworten früherer Anfragen in die nachfolgenden Anfragen einfließen sollten. Anstatt wie bei Exploit 1 die Paddings für jede Iteration immer wieder zu erraten, haben die Forscher sie nur einmal in Form einer funktionierenden Detektor-Byte-Kombination bestimmt. Dadurch konnten sie einen Faktor aus der Komplexitätsberechnung herausnehmen. 
  4. Reduziere das Problem auf seine Essenz: Im Gegensatz zu anderen Exploits verwendeten sie verschlüsselte Zeichenketten als Ausgangspunkt, anstatt Klartextzeichen zu verschlüsseln. Dadurch war SRLabs in der Lage, die Komplexität des Problems zu reduzieren. 
  5. Entscheide dich für eine geeignete, algorithmische Methode: Grob gesagt, kann man Schlüssel erraten, indem man entweder Möglichkeiten ausschließt oder sie bestätigt. Exploit 1 suchte nach einer Bestätigung für einen erratenen Schlüssel, während der optimierte Exploit falsche Möglichkeiten durch Divide-and-Conquer ausschloss. Dies erfordert Grundkenntnisse in Datenstrukturen und Algorithmen. 

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Nach oben scrollen