KI-gestützte Cyberangriffe: Wie man intelligente Bedrohungen erkennt, verhindert und abwehrt

Jetzt lesen
Wir verwenden künstliche Intelligenz für Website-Übersetzungen, und obwohl wir uns um Genauigkeit bemühen, kann es sein, dass sie nicht immer 100%ig präzise sind. Wir danken Ihnen für Ihr Verständnis.

Schutz vor Deserialisierungsangriffen in Spring für Apache Kafka

von OPSWAT
Jetzt teilen
Ein professionelles Bild von Nguyen Phu Hung und Tran Anh Huy, das ihre Zugehörigkeit zu HUTECH und der HCMC University of Science zeigt.

Deserialisierungsangriffe - die unbefugte Manipulation von serialisierten Daten zur Ausführung von bösartigem Code - können Unternehmen schweren Schaden zufügen. Entwickler und Sicherheitsteams müssen proaktiv wichtige Schwachstellen identifizieren, die Aufschluss darüber geben, wie, wann und wo der Angriff erfolgte.  

Ein aktuelles Beispiel für diese Bedrohung ist CVE-2023-34040, ein Deserialisierungs-Angriffsvektor in Spring für Apache Kafka, der zu RCE (Remotecodeausführung) führen kann. Die Verbreitung von Deserialisierungsschwachstellen wird in der OWASP-Top-10-Liste hervorgehoben, in der die "Deserialisierung nicht vertrauenswürdiger Daten" als eines der 10 kritischsten Sicherheitsrisiken für Webanwendungen aufgeführt ist.  

Tools wie OPSWAT MetaDefender Core™ mit seiner SBOM-EngineSoftware Bill of Materials) sind für die Erkennung und Verhinderung von Deserialisierungsangriffen unerlässlich. Diese ermöglichen es Entwicklern, ihren Code effizient zu scannen und zu analysieren, um sicherzustellen, dass keine Schwachstellen übersehen werden.  

In diesem Blog erörtern unsere Graduate Fellows die Details von CVE-2023-34040 und dessen Ausnutzung sowie die Frage, wie man Open-Source-Komponenten gegen ähnliche Bedrohungen schützen kann. 

Über CVE-2023-34040

CVE-2023-34040 offenbart einen Deserialisierungs-Angriffsvektor in Spring für Apache Kafka, der ausgenutzt werden kann, wenn eine ungewöhnliche Konfiguration angewendet wird. Diese Schwachstelle ermöglicht es einem Angreifer, ein bösartiges serialisiertes Objekt in einem der Deserialisierungsausnahme-Datensatz-Header zu konstruieren, was zu einem RCE führen kann. Die Schwachstelle betrifft die Spring for Apache Kafka Versionen 2.8.1 bis 2.9.10 und 3.0.0 bis 3.0.9.

Ein Screenshot, der die CVSS 3.x-Schweregrade für Schwachstellen anzeigt, mit hohen und mittleren Risikostufen von NIST und VMware.

Im Einzelnen ist eine Anwendung/ein Verbraucher unter den folgenden spezifischen Konfigurationen und Bedingungen anfällig: 

  • Die ErrorHandlingDeserializer-Klasse ist nicht für den Schlüssel und/oder Wert des Datensatzes konfiguriert. 
  • Die Eigenschaften checkDeserExWhenKeyNull und/oder checkDeserExWhenValueNull des Konsumenten werden auf true gesetzt. 
  • Nicht vertrauenswürdige Quellen dürfen in einem Kafka-Thema veröffentlichen.

Apache Kafka

Apache Kafka, entwickelt von der Apache Software Foundation, ist eine verteilte Event-Streaming-Plattform zur Erfassung, Verarbeitung, Beantwortung und Weiterleitung von Echtzeit-Datenströmen aus verschiedenen Quellen, einschließlich Datenbanken, Sensoren und mobile Geräten. 

So können beispielsweise Benachrichtigungen an Dienste gestreamt werden, die auf Kundenaktivitäten wie den Abschluss einer Produktbestellung oder eine Zahlung reagieren.

Ein Diagramm, das eine Apache Kafka-basierte Datenverarbeitungspipeline veranschaulicht, die Produkt-Microservices mit SMS-, Push-Benachrichtigungs- und E-Mail-Microservices verknüpft.

In Apache Kafka dient ein Ereignis - auch als Datensatz oder Nachricht bezeichnet - als Dateneinheit, die ein Ereignis in der Anwendung darstellt, wenn Daten gelesen oder geschrieben werden. Jedes Ereignis enthält einen Schlüssel, einen Wert, einen Zeitstempel und optionale Metadaten-Kopfzeilen.

Schlüssel-binär
(kann null sein)
Wert-binär
(kann null sein)
Komprimierungsart
[keine, gzip, snappy, lz4, zstd]
Kopfzeilen (optional)
SchlüsselWert
SchlüsselWert
Teilung + Versatz
Zeitstempel (System- oder Benutzereinstellung)

Ereignisse werden dauerhaft gespeichert und in Topics organisiert. Client-Anwendungen, die Ereignisse an Kafka-Themen senden (schreiben), werden als Produzenten bezeichnet, während diejenigen, die Ereignisse abonnieren (lesen und verarbeiten), als Konsumenten bezeichnet werden. 

Ein Flussdiagramm, das zeigt, wie Benutzereingaben durch einen Produzenten verarbeitet, aufgezeichnet, konsumiert und an einen Endpunkt geliefert werden.

Spring für Apache Kafka

Um Apache Kafka mit dem Spring-Ökosystem zu verbinden, können Entwickler Spring für Apache Kafka verwenden, was die Integration in Java-Anwendungen vereinfacht.  

Spring for Apache Kafka bietet robuste Tools und APIs, die das Senden und Empfangen von Ereignissen mit Kafka vereinfachen und es Entwicklern ermöglichen, diese Aufgaben ohne umfangreiche und komplexe Programmierung zu erledigen.

Eine Grafik mit Logos für Spring Boot und Apache Kafka, die die Integration für ereignisgesteuerte Anwendungen verdeutlicht.

Serialisierung und Deserialisierung

Die Serialisierung ist ein Mechanismus zur Umwandlung des Zustands eines Objekts in eine Zeichenfolge oder einen Bytestrom. Im Gegensatz dazu ist die Deserialisierung der umgekehrte Prozess, bei dem die serialisierten Daten wieder in ihr ursprüngliches Objekt oder ihre ursprüngliche Datenstruktur umgewandelt werden. Durch die Serialisierung können komplexe Daten so umgewandelt werden, dass sie in einer Datei gespeichert, über ein Netzwerk gesendet oder in einer Datenbank gespeichert werden können. Serialisierung und Deserialisierung sind für den Datenaustausch in verteilten Systemen unerlässlich und fördern die Kommunikation zwischen den verschiedenen Komponenten einer Softwareanwendung. In Java wird writeObject() für die Serialisierung und readObject() für die Deserialisierung verwendet.

Ein technisches Diagramm, das zeigt, wie Datenobjekte in Speicher, Dateien oder Datenbanken serialisiert und später wieder in Objekte deserialisiert werden.

Da die Deserialisierung die Umwandlung eines Bytestroms oder einer Zeichenkette in ein Objekt ermöglicht, kann eine unsachgemäße Handhabung oder das Fehlen einer ordnungsgemäßen Validierung der Eingabedaten zu einer erheblichen Sicherheitsschwachstelle führen, die möglicherweise einen RCE-Angriff zur Folge hat.

Schwachstellenanalyse

Gemäß der CVE-Beschreibung konfigurierten die OPSWAT checkDeserExWhenKeyNull und checkDeserExWhenValueNull auf true, um die Sicherheitslücke auszulösen. Durch das Senden eines Datensatzes mit einem leeren Schlüssel/Wert und die Durchführung einer detaillierten Analyse durch Debuggen des Verbrauchers, während er einen Kafka-Datensatz vom Produzenten empfängt, deckten unsere Stipendiaten den folgenden Arbeitsablauf während der Datensatzverarbeitung auf: 

Schritt 1: Empfang von Datensätzen (Nachrichten)

Beim Empfang von Datensätzen ruft der Verbraucher die Methode invokeIfHaveRecords() auf, die dann die Methode invokeListener() aufruft, um einen registrierten Datensatz-Listener (eine mit der Annotation @KafkaListener annotierte Klasse) für die eigentliche Verarbeitung der Datensätze auszulösen. 

Ein Screenshot des Java-Codes, der einen Kafka Message Listener Container für die Verarbeitung von Datensätzen in einem ereignisgesteuerten System definiert.

Der invokeListener() ruft dann die Methode invokeOnMessage() auf.

Schritt 2: Überprüfung der Aufzeichnungen

In der Methode invokeOnMessage() werden mehrere Bedingungen anhand des Datensatzwertes und der Konfigurationseigenschaften ausgewertet, die anschließend den nächsten auszuführenden Schritt bestimmen.

Ein hervorgehobener Java-Codeausschnitt zur Demonstration der Ausnahmebehandlung bei der Deserialisierung von Nachrichten in einem Kafka-Konsumenten.

Wenn ein Datensatz einen Null-Schlüssel oder -Wert hat und die Eigenschaften checkDeserExWhenKeyNull und/oder checkDeserExWhenValueNull ausdrücklich auf true gesetzt sind, wird die Methode checkDeser() aufgerufen, um den Datensatz zu untersuchen.

Schritt 3: Prüfen der Ausnahmen in den Kopfzeilen

In checkDesr() ruft der Verbraucher kontinuierlich getExceptionFromHeader() auf, um alle Ausnahmen aus den Metadaten des Datensatzes abzurufen, falls vorhanden, und speichert das Ergebnis in einer Variablen namens exception.

Die Java-Methode checkDeser ruft getExceptionFromHeader auf, um Deserialisierungsausnahmen bei der Verarbeitung von Kafka-Nachrichten zu behandeln.

Schritt 4: Extrahieren von Ausnahmen aus den Kopfzeilen

Die Methode getExceptionFromHeader() dient dazu, eine Ausnahme aus dem Header eines Kafka-Datensatzes zu extrahieren und zurückzugeben. Sie ruft zunächst den Header des Datensatzes ab und erhält dann den Wert des Headers, der in einem Byte-Array gespeichert ist.

Die Java-Methode getExceptionFromHeader extrahiert Deserialisierungsausnahmen aus den Kopfzeilen von Kafka-Nachrichten

Anschließend wird das Byte-Array mit dem Wert des Headers zur weiteren Bearbeitung an die Methode byteArrayToDeserializationException() weitergeleitet. 

Schritt 5: Daten deserialisieren

In der byteArrayToDeserializationException() wird die Funktion resolveClass() überschrieben, um die Deserialisierung nur auf erlaubte Klassen zu beschränken. Dieser Ansatz verhindert die Deserialisierung jeder Klasse, die nicht ausdrücklich erlaubt ist. Der Byte-Array-Wert des Headers kann innerhalb von byteArrayToDeserializationException() nur dann deserialisiert werden, wenn er die in resolveClass() festgelegte Bedingung erfüllt, die eine Deserialisierung ausschließlich für die Klasse DeserializationException erlaubt.

Java-Methode byteArrayToDeserializationException wandelt ein Byte-Array in eine Deserialisierungsausnahme um

Die Klasse DeserializationException erweitert jedoch die Standardklasse Exception und enthält einen Konstruktor mit vier Parametern. Der letzte Parameter, cause, stellt die ursprüngliche Ausnahme dar, die die DeserializationException ausgelöst hat, z. B. eine IOException oder eine ClassNotFoundException.

Java-Konstruktor für DeserializationException mit Parametern für message, data, key flag und throwable cause

Die Klasse Throwable dient als Oberklasse für alle Objekte, die in Java als Ausnahmen oder Fehler geworfen werden können. In der Programmiersprache Java können Klassen zur Behandlung von Ausnahmen wie Throwable, Exception und Error sicher deserialisiert werden. Wenn eine Ausnahme deserialisiert wird, erlaubt Java das Laden und Instanziieren der Throwable-Elternklassen mit weniger anspruchsvollen Prüfungen als bei regulären Klassen. 

Wenn die serialisierten Daten einer bösartigen Klasse entsprechen, die von der übergeordneten Klasse Throwable erbt, können die Bedingungsprüfungen umgangen werden, wie der Workflow und die umfassende Analyse zeigen. Dies ermöglicht die Deserialisierung eines bösartigen Objekts, das schädlichen Code ausführen und möglicherweise zu einem RCE-Angriff führen kann.

Ausbeutung

Diagramm eines Cyberangriffs, der von der Einspeisung bösartiger Daten durch einen Angreifer bis zur Remotecodeausführung reicht

Wie in der Analyse angegeben, müssen zur Ausnutzung dieser Schwachstelle bösartige Daten erzeugt werden, die über den Kafka-Header-Datensatz an den Verbraucher gesendet werden. Zunächst muss der Angreifer eine bösartige Klasse erstellen, die die Throwable-Klasse erweitert, und dann eine Gadget-Kette verwenden, um Remotecodeausführung zu erreichen. Gadgets sind ausnutzbare Codeschnipsel innerhalb der Anwendung. Durch Verkettung dieser Gadgets kann der Angreifer ein "Sink-Gadget" erreichen, das schädliche Aktionen auslöst. 

Im Folgenden finden Sie eine bösartige Klasse, die zur Ausnutzung dieser Schwachstelle in Spring für Apache Kafka verwendet werden kann: 

Java-Klasse CustomExceptionClass, die eine Sicherheitslücke bei der Ausführung von Nutzdaten mit PowerShell-Befehlen demonstriert

Als nächstes wird eine Instanz der bösartigen Klasse erstellt und als Argument an den Cause-Parameter im Konstruktor der DeserializationException-Klasse übergeben. Die Instanz der DeserializationException wird dann in einen Byte-Stream serialisiert, der anschließend als Wert im Header des bösartigen Kafka-Datensatzes verwendet wird.

Java-Klasse zur Konstruktion eines bösartigen serialisierten Objekts für Deserialisierungs-Exploits
Die Java-Methode sendMessage konstruiert und sendet eine Kafka-Nachricht, wobei eine bösartige serialisierte Nutzlast eingeschleust wird, wenn sowohl Schlüssel als auch Daten null sind

Wenn es dem Angreifer gelingt, das Opfer dazu zu bringen, seinen bösartigen Produzenten zu verwenden, kann er die Kafka-Datensätze kontrollieren, die an den Verbraucher gesendet werden, und so eine Möglichkeit schaffen, das System zu kompromittieren. 

UI für den Versand von Kafka-Nachrichten, die ein Nachrichtenformular und empfangene Nachrichten von zwei Produzenten anzeigt

Wenn der anfällige Verbraucher einen Kafka-Datensatz vom böswilligen Produzenten erhält, der Null-Schlüssel und -Werte sowie eine böswillige serialisierte Instanz im Datensatz-Header enthält, verarbeitet der Verbraucher den Datensatz, einschließlich des Deserialisierungsprozesses. Dies führt letztendlich zu einer Remotecodeausführung, die es dem Angreifer ermöglicht, das System zu kompromittieren.

Terminal und Kafka Message Sender UI, Demonstration der Nachrichteninjektion mit einer Befehlsausführung in einer Windows-Umgebung

Abschwächung von CVE-2023-34040 mit SBOM in MetaDefender Core

Um die mit CVE-2023-34040 verbundenen Risiken wirksam zu mindern, benötigen Unternehmen eine umfassende Lösung, die Transparenz und Kontrolle über ihre Open-Source-Komponenten bietet.  

SBOM, eine grundlegende Technologie innerhalb von MetaDefender Core, bietet eine leistungsstarke Antwort. SBOM dient als umfassendes Inventar aller verwendeten Softwarekomponenten, Bibliotheken und Abhängigkeiten und ermöglicht es Unternehmen, ihre Open-Source-Komponenten proaktiv und effizient zu verfolgen, zu sichern und zu aktualisieren.

Screenshot eines Dashboards, das eine blockierte XML-Datei mit kritischen und hohen Sicherheitslücken anzeigt

Mit SBOM können Sicherheitsteams:

  • Schnelles Auffinden anfälliger Komponenten: Identifizieren Sie sofort die Open-Source-Komponenten, die von Deserialisierungsangriffen betroffen sind. So können Sie schnell handeln und die gefährdeten Bibliotheken entweder patchen oder ersetzen. 
  • Sorgen Sie für proaktive Patches und Updates: Überwachen Sie Open-Source-Komponenten kontinuierlich mit SBOM, um Sicherheitslücken bei der Deserialisierung zu vermeiden. SBOM kann veraltete oder unsichere Komponenten erkennen, was rechtzeitige Updates ermöglicht und die Anfälligkeit für Angriffe verringert. 
  • Einhaltung von Vorschriften und Berichterstattung: SBOM unterstützt Unternehmen bei der Erfüllung von Compliance-Anforderungen, da gesetzliche Rahmenbedingungen zunehmend Transparenz in Software-Lieferketten vorschreiben.

Abschließende Überlegungen

Schwachstellen bei der Deserialisierung stellen eine erhebliche Sicherheitsbedrohung dar, die zur Ausnutzung einer Vielzahl von Anwendungen genutzt werden kann. Diese Schwachstellen treten auf, wenn eine Anwendung bösartige Daten deserialisiert, wodurch Angreifer beliebigen Code ausführen oder auf sensible Informationen zugreifen können. Die Sicherheitslücke CVE-2023-34040 in Spring für Apache Kafka führt uns die Gefahren von Deserialisierungsangriffen eindringlich vor Augen. 

Um Deserialisierungsangriffe zu verhindern, ist es wichtig, fortschrittliche Tools wie OPSWAT MetaDefender Core und seine SBOM-Technologie zu implementieren. Unternehmen können einen tiefen Einblick in ihre Software-Lieferkette gewinnen, das rechtzeitige Patchen von Schwachstellen sicherstellen und sich gegen die sich ständig weiterentwickelnde Bedrohungslandschaft schützen. Die proaktive Sicherung von Open-Source-Komponenten ist nicht nur eine bewährte Praxis, sondern eine Notwendigkeit, um moderne Systeme vor potenziellen Angriffen zu schützen.


Bleiben Sie auf dem Laufenden mit OPSWAT!

Melden Sie sich noch heute an, um die neuesten Unternehmensinformationen zu erhalten, Geschichten, Veranstaltungshinweise und mehr.