E-mail senden E-Mail Adresse kopieren

2025-08-04
Eva Michely

Verketten und kompromittieren: C++-Coroutinen anfällig für Code-Reuse-Angriffe trotz CFI

Ein Code-Reuse-Angriff namens „Coroutine Frame-Oriented Programming (CFOP)“ ist in der Lage, C++-Coroutinen über drei wichtige Compiler hinweg auszubeuten, nämlich Clang/LLVM, GCC und MSVC. CFOP kann sogar in Umgebungen ausgeführt werden, die durch Control Flow Integrity (CFI) geschützt sind, und zeigt somit relevante Sicherheitslücken in 15 dieser Abwehrmechanismen auf. Anstatt neuen Code einzuschleusen, verkettet CFOP bereits vorhandene Funktionen miteinander und erreicht die Ausführung beliebigen Codes, nachdem er coroutine-interne Speicherstrukturen beschädigt hat. Die Angriffsart wurde von Forschern des CISPA Helmholtz-Zentrums für Informationssicherheit entdeckt, die C++-Coroutinen als erste aus sicherheitstechnischer Perspektive untersucht haben. Um CFOP zu beheben, schlagen die Forscher strukturelle Änderungen an der Art und Weise vor, wie die Compiler C++-Coroutinen implementieren.

Mit einem neuartigen Code-Reuse-Angriff haben die beiden CISPA-Forscher Marcos Sanchez Bajo und Professor Dr. Christian Rossow gezeigt, dass alle bestehenden Implementierungen von C++-Coroutinen ausgenutzt werden können, um moderne CFI-Schutzmaßnahmen in Linux und Windows zu umgehen. Der Angriff namens „Coroutine Frame-Oriented Programming“ (CFOP) führt zu einer Beschädigung des Heap-Speichers, wodurch die Angreifenden Daten manipulieren und die vollständige Kontrolle über Anwendungen übernehmen können. Coroutinen sind eine relativ rezente Ergänzung in C++, aber bereits in mehr als 130 beliebten GitHub-Repositorys vorhanden. „Sie werden verwendet, um Funktionen anzuhalten und wiederaufzunehmen“, erklärt Bajo, „was für die asynchrone Programmierung, wie beispielsweise in Servern, Datenbanken und Webbrowsern, sehr nützlich ist.“

C++-Coroutinen verketten, um den Heap-Speicher zu beschädigen 

Mithilfe von Coroutinen können beispielsweise Generatoren erstellt werden, die eine Folge von Elementen erzeugen, wie etwa die Fibonacci-Folge. In der Fibonacci-Folge ist jede neue Zahl die Summe der beiden vorangegangenen Zahlen. Nach jeder neuen Zahl in der Folge wird die Coroutine angehalten, bis sie dazu aufgerufen wird, die nächste Zahl zu generieren. Bei CFOP werden ganze C++-Coroutinen und andere vorhandene Funktionen dazu genutzt, einen Code-Reuse-Angriff zu erstellen, wie Bajo erklärt: „Bei Code-Reuse-Angriffen verwenden Angreifende in der Regel Code-Schnipsel, die ohnehin schon zur Anwendung gehören, sodass kein neuer Code eingeschleust wird. Aus diesen Code-Schnipseln bilden sie dann Ketten, um den Ausführungsfluss des Programms zu manipulieren. Die Umgehung von CFI-Schutzmaßnahmen ist allerdings etwas schwieriger. Anstatt nur Code-Schnipsel zu nehmen und Ketten zu bilden, muss man vollständige Coroutine-Funktionen nehmen und sie auf intelligente Weise miteinander verbinden.“ Sobald die CFI-Schutzmaßnahmen auf diese Weise durch das Hijacking einer Coroutine-Funktion umgangen sind, kann jede andere vorhandene Funktion einem Code-Reuse-Angriff unterzogen werden.

Control Flow Integrity (CFI) versagt beim Schutz von C++-Coroutinen

CFI-Mechanismen wurden zum Schutz vor Code-Reuse-Angriffen eingeführt und sollen sicherstellen, dass der korrekte Programmablauf eingehalten wird. Programmiersprachen entwickeln sich jedoch dynamisch weiter, während CFI-Mechanismen nur die zum Zeitpunkt ihrer Erstellung vorhandenen Programmierparadigmen schützen. Bajo betont: „Das Hauptproblem bei CFI ist, dass es eine statische Abwehr ist, d. h. es deckt nur die Möglichkeiten einer Programmiersprache in ihrer bestehenden Form ab. Wenn zu einem späteren Zeitpunkt neue Funktionen in die Programmiersprache eingeführt werden, kann CFI diese nicht erkennen. Es kann nicht mit ihnen umgehen, da es auf einer älteren Version der Programmiersprache basiert.“ In ihrer Studie fanden Bajo und Rossow heraus, dass nur 7 von 15 ursprünglich betrachteten CFI-Mechanismen mit Coroutinen kompatibel waren. Von diesen 7 boten nur 2 (IBT und Control Flow Guard) einen teilweisen Schutz vor der Ausnutzung von Coroutinen, während die übrigen 5 gar keinen Schutz boten. „Letztendlich“, fasst Bajo zusammen, „waren wir in der Lage, alle zu umgehen. Mit CFOP kann man weiterhin all das tun, was vor CFI möglich war.“

Das Patchen von CFOP ist ein strukturelles Problem

Die Tatsache, dass C++-Coroutinen sich zunehmender Beliebtheit erfreuen, verstärkt das Potenzial von CFOP. Bajo erklärt: „Coroutinen wurden 2020 in C++ eingeführt und werden seitdem immer häufiger von Entwickler:innen verwendet. Leider haben wir festgestellt, dass Coroutinen bestimmte Strukturen im Speicher aufweisen, auf die Angreifende abzielen können. Soweit wir wissen, wurde dies bisher aber noch nicht in der Praxis ausgenutzt.“ Im Wesentlichen ist CFOP möglich, weil die drei wichtigsten Compiler C++-Coroutinen auf eine Art und Weise implementieren, die sie strukturell anfällig macht. Bajo fährt fort: „Diese Angriffstechnik zu entschärfen, ist nicht so einfach wie das Patchen eines Codes – es handelt sich um ein strukturelles Problem, und man muss die interne Funktionsweise der Anwendung überdenken.“ Bajo und Rossow haben erfolgreiche Implementierungsalternativen für C++-Coroutinen entwickelt und diese Abhilfemaßnahmen im November 2024 an Clang/LLVM, GCC und MVSC gemeldet. Die CISPA-Forschung zu CFOP wird am 07. August 2025 auf der „Black Hat USA“-Konferenz in Las Vegas vorgestellt.

 

Weitere Informationen:

Weitere Informationen zu "Coroutine Frame-Oriented Programming (CFOP)" sind verfügbar unter https://syssec.cispa.io/coroutine-cfop/

Wissenschaftlicher Kontakt:

Marcos Sanchez Bajo und Prof. Dr. Christian Rossow
CISPA Helmholtz-Zentrum für Informationssicherheit 
Stuhlsatzenhaus 5
66123 Saarbrücken
marcos.sanchez-bajo@cispa.de / rossow@cispa.de

Akademische Publikation:

Sanchez Bajo, Marcos; Rossow, Christian (2025) “Await() a Second: Evading Control Flow Integrity by Hijacking C++ Coroutines” In: 34th Usenix Security Symposium (USENIX-Security), 13-15 Aug 2025, Seattle, WA, USA. https://doi.org/10.60882/cispa.28718642.v1