Control de Flow Guard para la seguridad de la plataforma

¿Qué es Control Flow Guard?

Control Flow Guard (CFG) es una característica de seguridad de plataforma altamente optimizada que se creó para combatir las vulnerabilidades de daños en la memoria. Al colocar restricciones estrictas en la ubicación desde la que una aplicación puede ejecutar código, hace que sea mucho más difícil que las vulnerabilidades de seguridad ejecuten código arbitrario a través de vulnerabilidades como desbordamientos de búfer. CFG amplía las tecnologías de mitigación de vulnerabilidades anteriores, como /GS, DEP y ASLR.

  • Evitar daños en la memoria y ataques de ransomware.
  • Restrinja las funcionalidades del servidor a lo que sea necesario en un momento determinado para reducir la superficie expuesta a ataques.
  • Haga que sea más difícil aprovechar el código arbitrario a través de vulnerabilidades, como desbordamientos de búfer.

Esta característica está disponible en Microsoft Visual Studio 2015 y se ejecuta en versiones "compatibles con CFG" de Windows, las versiones x86 y x64 para escritorio y servidor de Windows 10 y Windows 8.1 Update (KB3000850).

Recomendamos encarecidamente a los desarrolladores que habiliten CFG para sus aplicaciones. No es necesario habilitar CFG para cada parte del código, ya que una combinación de CFG habilitado y código no habilitado para CFG se ejecutará correctamente. Pero no se puede habilitar CFG para todo el código puede abrir brechas en la protección. Además, el código habilitado para CFG funciona bien en las versiones "CFG-Unware" de Windows y, por lo tanto, es totalmente compatible con ellos.

¿Cómo puedo habilitar CFG?

En la mayoría de los casos, no es necesario cambiar el código fuente. Todo lo que tiene que hacer es agregar una opción al proyecto de Visual Studio 2015 y el compilador y enlazador habilitarán CFG.

El método más sencillo es navegar a Project | Propiedades | Propiedades de configuración | | de C/C++ Generación de código y elija Sí (/guard:cf) para Control Flow Guard.

cfg property in visual studio

Como alternativa, agregue /guard:cf a Project | Propiedades | Propiedades de configuración | | de C/C++ | de línea de comandos Opciones adicionales (para el compilador) y /guard:cf para Project | Propiedades | Propiedades de configuración | | del vinculador | de línea de comandos Opciones adicionales (para el enlazador).

cfg property for compilercfg property for linker

Consulta /guard (Habilitar control Flow Guard) para obtener más información.

Si va a compilar el proyecto desde la línea de comandos, puede agregar las mismas opciones. Por ejemplo, si va a compilar un proyecto denominado test.cpp, use cl /guard:cf test.cpp /link /guard:cf.

También tiene la opción de controlar dinámicamente el conjunto de direcciones de destino de icall que CFG considera válidas mediante SetProcessValidCallTargets de memory Management API. La misma API se puede usar para especificar si las páginas no son válidas o son destinos válidos para CFG. Las funciones VirtualProtect y VirtualAlloc tratarán de forma predeterminada una región especificada de páginas ejecutables y confirmadas como destinos de llamada indirectos válidos. Es posible invalidar este comportamiento, como al implementar un compilador Just-In-Time, especificando PAGE_TARGETS_INVALID al llamar a VirtualAlloc o PAGE_TARGETS_NO_UPDATE al llamar a VirtualProtect como se detalla en Constantes de protección de memoria.

¿Cómo puedo saber que un binario está bajo control Flow Guard?

Ejecute la herramienta dumpbin (incluida en la instalación de Visual Studio 2015) desde el símbolo del sistema de Visual Studio con las opciones /headers y /loadconfig: dumpbin /headers /loadconfig test.exe. La salida de un binario en CFG debe mostrar que los valores de encabezado incluyen "Guard" y que los valores de configuración de carga incluyen "CF Instrumented" y "FID table present".

output from dumpbin /headers

output from dumpbin /loadconfig

¿Cómo funciona REALMENTE CFG?

Las vulnerabilidades de software suelen aprovecharse proporcionando datos poco probables, inusuales o extremos a un programa en ejecución. Por ejemplo, un atacante puede aprovechar una vulnerabilidad de desbordamiento de búfer proporcionando más entrada a un programa de la esperada, lo que supera la ejecución del área reservada por el programa para contener una respuesta. Esto podría dañar la memoria adyacente que puede contener un puntero de función. Cuando el programa llama a través de esta función, puede saltar a una ubicación no deseada especificada por el atacante.

Sin embargo, una combinación potente de compatibilidad en tiempo de compilación y ejecución de CFG implementa la integridad del flujo de control que restringe estrechamente dónde se pueden ejecutar las instrucciones de llamada indirectas.

El compilador hace lo siguiente:

  1. Agrega comprobaciones de seguridad ligeras al código compilado.
  2. Identifica el conjunto de funciones de la aplicación que son destinos válidos para las llamadas indirectas.

Compatibilidad con tiempo de ejecución, proporcionada por el kernel de Windows:

  1. Mantiene eficazmente el estado que identifica destinos de llamada indirectos válidos.
  2. Implementa la lógica que comprueba que un destino de llamada indirecta es válido.

Para ilustrar:

cfg pseudocode

Cuando se produce un error en una comprobación de CFG en tiempo de ejecución, Windows finaliza inmediatamente el programa, lo que interrumpe cualquier vulnerabilidad de seguridad que intente llamar indirectamente a una dirección no válida.