Coroutine Frame-Oriented Programming: Explotación de software en la era de Control Flow Integrity
Author: Marcos Bajo (h3xduck)
Bypass de CFI usando corrutinas en C++
Charla de Marcos, estudiante de doctorado en CISPA (instituto de investigación en Alemania)
Idea principal
El tío presenta un ataque nuevo que bypasea las defensas de Control Flow Integrity (CFI), que son básicamente las protecciones modernas contra técnicas de explotación de memoria tipo ROP/JOP. El enfoque concreto: explotar cómo funcionan las corrutinas de C++ para saltarse estas defensas sin ni tocar los punteros que CFI protege.
Conceptos clave
- La guerra ataque-defensa lleva décadas: primero aparece ASLR, stack canaries, NX... luego el atacante inventa ROP/JOP para saltárselo todo
- ROP y JOP funcionan encadenando "gadgets" (trozos pequeños de código existente) para construir un exploit
- CFI ataca la raíz del problema: restringe cómo puede moverse la ejecución por el programa, usando el control flow graph legítimo del binario
- Hay dos tipos de punteros vulnerables: backward edge (return addresses) y forward edge (llamadas indirectas)
- Para backward: Shadow Stack (copia protegida de los return addresses, comparada en hardware)
- Para forward: IBT de Intel (landing pads al inicio de funciones) o equivalentes en software como CFGuard en Windows
- Cuanto más granular es el CFI, más overhead tiene. Hay un trade-off seguridad/rendimiento
- Las corrutinas son funciones que se pueden suspender y reanudar, con su estado guardado en el heap dentro de un Coroutine Frame
- Dentro del frame hay dos punteros clave: resume pointer y destroy pointer, que se usan con llamadas indirectas
Desarrollo/contexto
El punto gordo del ataque es este: el Coroutine Frame vive en el heap, en memoria escribible. Eso significa que si un atacante tiene una primitiva de escritura arbitraria (o un overflow que llega al heap), puede sobreescribir el contenido del frame. Hasta aquí normal. Pero lo interesante es que Marcos propone hacer "data-only attacks", es decir, atacar solo los datos del frame (argumentos, variables locales, el índice de suspensión) sin tocar ningún puntero. Como CFI solo protege punteros, este tipo de ataque pasa completamente desapercibido para las defensas.
Por ejemplo: si una corrutina usa un argumento para llamar a system() en algún punto de suspensión, sobreescribir ese argumento con "/bin/sh" y ajustar el coroutine index para saltar directo a ese punto es suficiente. No has tocado ni un puntero, CFI no dice nada, y ya tienes RCE. Además señala que los compiladores a veces reordenan mal las variables dentro del frame, lo que facilita overflows que en teoría no deberían ser posibles.
Términos técnicos
- CFI (Control Flow Integrity): mecanismo que restringe los saltos válidos en un programa a los previstos en tiempo de compilación
- Shadow Stack: copia protegida (hardware) de los return addresses para detectar modificaciones
- IBT / Landing Pad (ENDBR64): instrucción que marca los inicios de función válidos como destinos de saltos indirectos
- Coroutine Frame: objeto en heap que contiene el estado completo de una corrutina (variables, índice, punteros de control)
- Data-only attack: ataque que solo modifica datos, no punteros de código, para evadir CFI
- Gadget: secuencia de instrucciones reutilizadas de código legítimo para construir un exploit

Conclusiones
Lo que me llevo es que CFI, aunque es un salto enorme respecto a las defensas anteriores, no es la bala de plata. La abstracción de las corrutinas introduce superficie de ataque nueva que los modelos de amenaza actuales no contemplan bien. El hecho de que puedas hacer bypass sin tocar un solo puntero es bastante elegante y preocupante a la vez. Vale la pena seguir de cerca cómo evolucionan los esquemas de CFI para incorporar también protecciones sobre datos críticos.
Para investigar más
- Intel CET: documentación técnica completa del Shadow Stack e IBT
- LLVM CFI y clang-CFI: cómo funciona la instrumentación a nivel compilador
- "Data-oriented programming" (DOP): el área de investigación donde se enmarca este tipo de ataque
- Heap exploitation moderno (house of mind, etc.) mencionado de pasada pero no desarrollado