La integridad del flujo de control ( CFI , por sus siglas en inglés) es un término general para las técnicas de seguridad informática que impiden que una amplia variedad de ataques de malware redirijan el flujo de ejecución (el flujo de control ) de un programa.
Fondo
Un programa informático suele modificar su flujo de control para tomar decisiones y utilizar distintas partes del código. Estas transferencias pueden ser directas , cuando la dirección de destino está escrita en el propio código, o indirectas , cuando la dirección de destino es una variable en memoria o un registro de la CPU. En una llamada a función típica , el programa realiza una llamada directa, pero regresa a la función que la llamó utilizando la pila : una transferencia indirecta por flanco hacia atrás . Cuando se llama a un puntero a función , por ejemplo, desde una tabla virtual , decimos que hay una transferencia indirecta por flanco hacia adelante . [ 1 ] [ 2 ]
Los atacantes buscan inyectar código en un programa para aprovechar sus privilegios o extraer datos de su memoria. Antes de que el código ejecutable se hiciera comúnmente de solo lectura, un atacante podía modificarlo arbitrariamente durante su ejecución, apuntando a transferencias directas o incluso sin realizar ninguna transferencia. Tras la generalización de W^X , un atacante busca redirigir la ejecución a un área separada y desprotegida que contenga el código a ejecutar, utilizando transferencias indirectas: se podría sobrescribir la tabla virtual para un ataque de borde hacia adelante o modificar la pila de llamadas para un ataque de borde hacia atrás ( programación orientada a retorno ). CFI está diseñado para proteger las transferencias indirectas e impedir que se ejecuten en ubicaciones no deseadas. [ 1 ]
Técnicas
Las técnicas asociadas incluyen la separación de punteros de código (CPS), la integridad de punteros de código (CPI), los canarios de pila , las pilas de sombra (SS) y la verificación de punteros de tabla virtual . [ 3 ] [ 4 ] [ 5 ] Estas protecciones se pueden clasificar como de grano grueso o de grano fino según el número de objetivos restringidos. Una implementación CFI de borde hacia adelante de grano grueso podría, por ejemplo, restringir el conjunto de objetivos de llamadas indirectas a cualquier función que pueda ser llamada indirectamente en el programa, mientras que una de grano fino restringiría cada sitio de llamada indirecta a funciones que tengan el mismo tipo que la función a ser llamada. De manera similar, para un esquema de borde hacia atrás que protege los retornos, una implementación de grano grueso solo permitiría que el procedimiento regresara a una función del mismo tipo (de las cuales podría haber muchas, especialmente para prototipos comunes), mientras que una de grano fino impondría una coincidencia de retorno precisa (por lo que solo puede regresar a la función que lo llamó).
Implementaciones
Se encuentran implementaciones relacionadas en Clang ( front-end de LLVM ), [ 6 ] , GNU Compiler Collection [ 7 ] , Control Flow Guard de Microsoft [ 8 ] [ 9 ] [ 10 ] y Return Flow Guard, [ 11 ] Indirect Function-Call Checks de Google [ 12 ] y Reuse Attack Protector (RAP). [ 13 ] [ 14 ]
LLVM/Clang
El front-end C/C++ del compilador LLVM, Clang, proporciona varios esquemas "CFI" que funcionan en el borde de avance comprobando errores en tablas virtuales y conversiones de tipo. No todos los esquemas son compatibles con todas las plataformas y la mayoría de ellos, con la excepción de dos esquemas "kcfi" destinados al software de kernel de bajo nivel, dependen de la optimización en tiempo de enlace (LTO) para saber qué funciones deben llamarse en casos normales. [ 15 ]
También se proporciona una pasada de instrumentación de " pila de llamadas en la sombra " (SCS) independiente que protege el borde posterior comprobando las modificaciones de la pila de llamadas, disponible solo para las arquitecturas ISA aarch64 y RISC-V . Y debido al uso de un registro de procesador compartido , SCS solo es aplicable en ciertas ABI o si de otro modo se garantiza que ningún otro software que utilice el conjunto de registros (hilo/procesador) interfiera con este uso. [ 16 ]
Google ha distribuido Android con el kernel de Linux compilado por Clang con optimización en tiempo de enlace (LTO) y CFI habilitados desde 2018. [ 17 ] Aunque SCS está disponible para el kernel de Linux como opción, y también hay soporte disponible para los componentes del sistema de Android, se recomienda habilitarlo solo para componentes para los que se pueda garantizar que no se cargue código de terceros. [ 18 ]
GCC
La colección de compiladores GNU implementó una "pila de llamadas en la sombra" compatible con Clang para aarch64 en la versión 12, publicada en 2022. [ 19 ] [ 20 ] Esta característica está destinada principalmente a la compilación del kernel de Linux, ya que las bibliotecas de espacio de usuario de GCC no ofrecen soporte para ello. [ 7 ]
Tecnología de aplicación de control de flujo de Intel
La tecnología de aplicación de control de flujo (CET) de Intel detecta compromisos para controlar la integridad del flujo con una pila de sombra (SS) y seguimiento de bifurcación indirecta (IBT). [ 21 ] [ 22 ]
El núcleo debe asignar una región de memoria para la pila de sombra que no sea modificable por programas del espacio de usuario, salvo mediante instrucciones especiales. La pila de sombra almacena una copia de la dirección de retorno de cada llamada. En caso de retorno (RET), el procesador comprueba si las direcciones de retorno almacenadas en la pila normal y en la pila de sombra son iguales. Si las direcciones no coinciden, el procesador genera una interrupción INT #21 (Fallo de protección del flujo de control).
El seguimiento de bifurcaciones indirectas detecta instrucciones JMP o CALL indirectas dirigidas a destinos no autorizados. Se implementa añadiendo una nueva máquina de estados interna al procesador. El comportamiento de las instrucciones JMP y CALL indirectas se modifica para que cambien la máquina de estados de IDLE a WAIT_FOR_ENDBRANCH. En el estado WAIT_FOR_ENDBRANCH, la siguiente instrucción a ejecutar debe ser la nueva instrucción ENDBRANCH (ENDBR32 en modo de 32 bits o ENDBR64 en modo de 64 bits), lo que cambia la máquina de estados interna de WAIT_FOR_ENDBRANCH de nuevo a IDLE. Por lo tanto, cada destino autorizado de una instrucción JMP o CALL indirecta debe comenzar con ENDBRANCH. Si el procesador se encuentra en el estado WAIT_FOR_ENDBRANCH (es decir, la instrucción anterior fue una instrucción JMP o CALL indirecta) y la siguiente instrucción no es una instrucción ENDBRANCH, el procesador genera una INT #21 (Fallo de protección del flujo de control). En los procesadores que no admiten el seguimiento de bifurcaciones indirectas CET, las instrucciones ENDBRANCH se interpretan como NOP y no tienen ningún efecto.
Microsoft Control Flow Guard
Control Flow Guard (CFG) se lanzó por primera vez para Windows 8.1 Update 3 (KB3000850) en noviembre de 2014. Los desarrolladores pueden agregar CFG a sus programas agregando la /guard:cfbandera del enlazador antes de enlazar el programa en Visual Studio 2015 o posterior. [ 23 ]
A partir de Windows 10 Creators Update (versión 1703 de Windows 10), el kernel de Windows se compila con CFG. [ 24 ] El kernel de Windows utiliza Hyper-V para evitar que el código malicioso del kernel sobrescriba el mapa de bits CFG. [ 25 ]
CFG funciona creando un mapa de bits por proceso , donde un bit activado indica que la dirección es un destino válido. Antes de realizar cada llamada a función indirecta, la aplicación comprueba si la dirección de destino está en el mapa de bits. Si la dirección de destino no está en el mapa de bits, el programa finaliza. [ 23 ] Esto dificulta que un atacante explote una vulnerabilidad de uso después de la liberación reemplazando el contenido de un objeto y luego utilizando una llamada a función indirecta para ejecutar una carga útil. [ 26 ]
Detalles de implementación
Para todas las llamadas a funciones indirectas protegidas, _guard_check_icallse llama a la función, que realiza los siguientes pasos: [ 27 ]
- Convierte la dirección de destino en un desplazamiento y un número de bit en el mapa de bits.
- Los 3 bytes más significativos son el desplazamiento de bytes en el mapa de bits.
- El desplazamiento de bits es un valor de 5 bits. Los primeros cuatro bits son los bits de menor orden del 4.º al 8.º de la dirección.
- El quinto bit del desplazamiento de bits se establece en 0 si la dirección de destino está alineada con 0x10 (los últimos cuatro bits son 0) y en 1 si no lo está.
- Examine el valor de la dirección del objetivo en el mapa de bits.
- Si la dirección de destino está en el mapa de bits, devuelva el resultado sin error.
- Si la dirección de destino no se encuentra en el mapa de bits, finalice el programa.
Técnicas de derivación
Existen varias técnicas genéricas para eludir el CFG:
- Establezca el destino en el código ubicado en un módulo que no sea CFG cargado en el mismo proceso. [ 26 ] [ 28 ]
- Encuentra una llamada indirecta que no esté protegida por CFG (ya sea CALL o JMP). [ 26 ] [ 28 ] [ 29 ]
- Utilizar una llamada a función con un número de argumentos diferente al previsto, provoca una desalineación de la pila y la ejecución de código después de que la función retorne (parcheado en Windows 10). [ 30 ]
- Utilice una llamada a función con el mismo número de argumentos, pero uno de los punteros pasados se trata como un objeto y escribe en un desplazamiento basado en punteros, lo que permite sobrescribir una dirección de retorno. [ 31 ]
- Sobrescribir la llamada a la función utilizada por el CFG para validar la dirección (parcheado en marzo de 2015) [ 29 ]
- Establezca el mapa de bits CFG en todos 1, permitiendo todas las llamadas a funciones indirectas [ 29 ].
- Utilice una primitiva de escritura controlada para sobrescribir una dirección en la pila (ya que la pila no está protegida por CFG) [ 29 ].
Microsoft eXtended Flow Guard
eXtended Flow Guard (XFG) aún no se ha lanzado oficialmente, pero está disponible en la vista previa de Windows Insider y se presentó públicamente en Bluehat Shanghai en 2019. [ 32 ]
XFG extiende CFG validando las firmas de las llamadas a funciones para asegurar que las llamadas indirectas se realicen únicamente al subconjunto de funciones con la misma firma. La validación de la firma de la llamada a función se implementa agregando instrucciones para almacenar el hash de la función objetivo en el registro r10 inmediatamente antes de la llamada indirecta y almacenar el hash de la función calculado en la memoria inmediatamente anterior al código de la dirección objetivo. Cuando se realiza la llamada indirecta, la función de validación XFG compara el valor en r10 con el hash almacenado de la función objetivo. [ 33 ] [ 34 ]
Véase también
Referencias
- 1 2 Payer, Mathias. "Integridad del flujo de control: una introducción" . nebelwelt.net .
- ↑ Burow, Nathan; Carr, Scott A.; Nash, Joseph; Larsen, Per; Franz, Michael; Brunthaler, Stefan; Payer, Mathias (31 de enero de 2018). "Integridad del flujo de control: precisión, seguridad y rendimiento" . ACM Computing Surveys . 50 (1): 1– 33. doi : 10.1145/3054924 .
- ↑ Payer, Mathias ; Kuznetsov, Volodymyr. "Sobre las diferencias entre las propiedades CFI, CPS y CPI" . nebelwelt.net . Consultado el 1 de junio de 2016 .
- ↑ "El descubrimiento de un fallo en Adobe Flash conduce a un nuevo método de mitigación de ataques" . Dark Reading . 10 de noviembre de 2015. Consultado el 1 de junio de 2016 .
- ↑ Endgame. "Endgame estará presente en Black Hat USA 2016" . www.prnewswire.com (Comunicado de prensa) . Consultado el 1 de junio de 2016 .
- ↑ "Integridad del flujo de control — Documentación de Clang 3.9" . clang.llvm.org . Consultado el 1 de junio de 2016 .
- 1 2 "Manual de GCC - Opciones de instrumentación del programa" . Proyecto GCC . Consultado el 19 de marzo de 2026 .
- ↑ Pauli, Darren. "El mitigador de malware de Microsoft se actualiza, pero incluso Redmond dice que ya no es necesario" . The Register . Consultado el 1 de junio de 2016 .
- ↑ Mimoso, Michael (22 de septiembre de 2015). "Desarrollo de una vulnerabilidad para Microsoft Memory Protection, Control Flow Guard" . Threatpost | La primera parada para noticias de seguridad . Consultado el 1 de junio de 2016 .
- ↑ Smith, Ms. (23 de septiembre de 2015). "DerbyCon: Un antiguo ganador del premio BlueHat eludirá Control Flow Guard en Windows 10" . Network World . Archivado del original el 27 de septiembre de 2015. Recuperado el 1 de junio de 2016 .
- ↑ "Return Flow Guard" . Tencent . 2 de noviembre de 2016. Consultado el 19 de enero de 2017 .
- ↑ Tice, Caroline; Roeder, Tom; Collingbourne, Peter; Checkoway, Stephen; Erlingsson, Úlfar; Lozano, Luis; Pike, Geoff (2014-01-01). Garantizando la integridad del flujo de control de borde directo en GCC y LLVM . págs. 941–955 . ISBN 9781931971157.
- ^ Seguridad, heise (4 de mayo de 2016). "PaX Team creó protección para los exploits de reutilización de código" . Seguridad (en alemán) . Consultado el 1 de junio de 2016 .
- ↑ "Preguntas frecuentes sobre RAP" . Consultado el 1 de junio de 2016 .
- ↑ "Integridad del flujo de control — Documentación de Clang 23.0.0git" . clang.llvm.org . Consultado el 19 de marzo de 2026 .
- ↑ "ShadowCallStack — Documentación de Clang 23.0.0git" . clang.llvm.org . Consultado el 19 de marzo de 2026 .
- ↑ "Parches LTO de Clang actualizados para el kernel de Linux - Phoronix" .
- ↑ "ShadowCallStack" . Proyecto de código abierto de Android .
- ↑ "Serie de lanzamientos de GCC 12 - Mejoras generales" . Proyecto GCC . Consultado el 19 de marzo de 2026 .
- ↑ "Serie de versiones GCC 12 - Historial de versiones" . Proyecto GCC . Consultado el 19 de marzo de 2026 .
- ↑ "Especificación de la tecnología de aplicación del flujo de control" (PDF) . Zona de desarrolladores de Intel . Archivado del original (PDF) el 14 de agosto de 2017. Consultado el 5 de enero de 2021 .
- ↑ "RIP ROP: CET Internals in Windows 20H1" . Winsider Seminars & Solutions Inc. 5 de enero de 2020. Consultado el 5 de enero de 2021 .
- 1 2 "Control Flow Guard" . MSDN . Consultado el 19 de enero de 2017 .
- ↑ "Análisis de la publicación de Shadow Brokers y mitigación con la seguridad basada en virtualización de Windows 10" . Microsoft Technet . 16 de junio de 2017. Consultado el 20 de junio de 2017 .
- ↑ "Evitando universalmente CFG mediante el abuso de mutabilidad" (PDF) . Blog de Alex Ionescu . Consultado el 7 de julio de 2017 .
- 1 2 3 Falcón, Francisco (2015-03-25). "Explotando CVE-2015-0311, Parte II: Eludiendo Control Flow Guard en Windows 8.1 Update 3" . Core Security . Recuperado el 2017-01-19 .
- ↑ "Control Flow Guard" (PDF) . Trend Micro . Consultado el 19 de enero de 2017 .
- 1 2 "Windows 10 Control Flow Guard Internals" (PDF) . Power of Community . Consultado el 19 de enero de 2017 .
- 1 2 3 4 "Bypass Control Flow Guard Comprehensive" (PDF) . BlackHat . Recuperado el 19 de enero de 2017 .
- ↑ "Un detalle interesante sobre Control Flow Guard" . Bromium . Consultado el 19 de enero de 2017 .
- ↑ Thomas, Sam (18 de agosto de 2016). "Explotación orientada a objetos: nuevas técnicas para eludir la mitigación de Windows" . Slideshare . Recuperado el 19 de enero de 2017 .
- ↑ "Mejoras en la seguridad de Windows" . Consultado el 19 de mayo de 2021 .
- ↑ "PROTECCIÓN DE FLUJO EXTENDIDA BAJO EL MICROSCOPIO" . 18 de mayo de 2021. Consultado el 19 de mayo de 2021 .
- ↑ "Desarrollo de exploits: Entre la espada y la pared (Xtended Flow) Guard Place: Examinando XFG" . 23 de agosto de 2020. Consultado el 19 de mayo de 2021 .
- Seguridad informática
- Integridad del flujo de control