Partager via


Control Flow Guard pour la sécurité de la plateforme

Qu'est-ce que le Control Flow Guard ?

Control Flow Guard (CFG) est une fonctionnalité de sécurité de plate-forme hautement optimisée qui a été créée pour lutter contre les vulnérabilités liées à la corruption de la mémoire. En imposant des restrictions strictes sur l'endroit où une application peut exécuter du code, il est beaucoup plus difficile pour les exploits d'exécuter du code arbitraire par le biais de vulnérabilités telles que les débordements de mémoire tampon. CFG étend les technologies précédentes d'atténuation des exploits telles que /GS (Buffer Security Check), Data Execution Prevention (DEP) et Address Space Layout Randomization (ASLR).

L'utilisation de CFG peut contribuer à

  • Prévenir la corruption de la mémoire et les attaques de ransomware.
  • Restreindre les capacités du serveur à ce qui est nécessaire à un moment donné afin de réduire la surface d'attaque.
  • rendre plus difficile l'exploitation d'un code arbitraire par le biais de vulnérabilités telles que les débordements de mémoire tampon.

Cette fonctionnalité est disponible dans Microsoft Visual Studio et s'exécute sur les versions CFG-Aware de Windows ; Windows 10 et Windows 11 sur le client et Windows Server 2019 et versions ultérieures côté serveur.

Les développeurs sont fortement encouragés à activer CFG pour leurs applications. Vous ne devez pas activer CFG pour chaque partie de votre code, car un mélange de code avec CFG activé et sans CFG activé s’exécute correctement. Cependant, le fait de ne pas activer CFG pour tout le code peut ouvrir des brèches dans la protection. En outre, le code activé par CFG fonctionne correctement sur les versions de Windows non compatibles avec CFG et est donc entièrement compatible avec elles.

Comment puis-je activer la CFG ?

Dans la plupart des cas, il n'est pas nécessaire de modifier le code source. Il vous suffit d'ajouter une option à votre projet Visual Studio pour que le compilateur et l'éditeur de liens activent CFG.

La méthode la plus simple consiste à naviguer dans Projet | Propriétés | Propriétés de configuration | C/C++ | Génération de code et à choisir Oui (/guard:cf) pour Control Flow Guard.

propriété cfg dans visual studio

Vous pouvez également ajouter /guard:cf à Projet | Propriétés | Propriétés de configuration | C/C++ | Ligne de commande | Options supplémentaires (pour le compilateur) et /guard:cf à Projet | Propriétés | Propriétés de configuration | Lieur | Ligne de commande | Options supplémentaires (pour le lieur).

propriété cfg pour le compilateurpropriété cfg pour l'éditeur de liens

Voir /guard (Enable Control Flow Guard) pour plus d'informations.

Si vous construisez votre projet à partir de la ligne de commande, vous pouvez ajouter les mêmes options. Par exemple, si vous compilez un projet appelé test.cpp, utilisez cl /guard:cf test.cpp /link /guard:cf.

Vous avez également la possibilité de contrôler dynamiquement l'ensemble des adresses cibles icall considérées comme valides par CFG à l'aide de SetProcessValidCallTargets de l'API de gestion de la mémoire. La même API peut être utilisée pour spécifier si les pages sont des cibles invalides ou valides pour CFG. Les fonctions VirtualProtect et VirtualAlloc traitent par défaut une région spécifiée de pages exécutables et engagées comme des cibles d'appel indirect valides. Il est possible de remplacer ce comportement, par exemple lors de l'implémentation d'un compilateur Just-in-Time, en spécifiant PAGE_TARGETS_INVALID lors de l'appel à VirtualAlloc ou PAGE_TARGETS_NO_UPDATE lors de l'appel à VirtualProtect, comme indiqué dans la section Constantes de protection de la mémoire.

Comment savoir si un binaire est sous Control Flow Guard ?

Exécutez l'outil dumpbin (inclus dans l'installation de Visual Studio) à partir de la requête de Visual Studio avec les options /headers et /loadconfig : dumpbin /headers /loadconfig test.exe. La sortie pour un binaire sous CFG devrait montrer que les valeurs de l'en-tête incluent « Guard », et que les valeurs de loadconfig incluent « CF Instrumented » et « FID table present ».

sortie de dumpbin /headers

sortie de dumpbin /loadconfig

Comment fonctionne réellement CFG ?

Les vulnérabilités logicielles sont souvent exploitées en fournissant des données improbables, inhabituelles ou extrêmes à un programme en cours d'exécution. Par exemple, un attaquant peut exploiter une vulnérabilité de dépassement de tampon en fournissant à un programme plus de données que prévu, dépassant ainsi la zone réservée par le programme pour contenir une réponse. Cela pourrait corrompre la mémoire adjacente qui peut contenir un pointeur de fonction. Lorsque le programme fait appel à cette fonction, il peut alors sauter à un emplacement involontaire spécifié par l'attaquant.

Cependant, une puissante combinaison de soutien à la compilation et à l'exécution de CFG met en œuvre l'intégrité du flux de contrôle qui limite étroitement l'endroit où les instructions d'appel indirect peuvent s'exécuter.

Le compilateur effectue les opérations suivantes

  1. Il ajoute des contrôles de sécurité légers au code compilé.
  2. Il identifie l'ensemble des fonctions de l'application qui sont des cibles valides pour les appels indirects.

Le support d'exécution, fourni par le noyau Windows :

  1. maintient efficacement l'état qui identifie les cibles d'appels indirects valides.
  2. Implémente la logique qui vérifie qu'une cible d'appel indirect est valide.

Pour illustrer :

pseudocode cfg

Lorsqu'une vérification CFG échoue au moment de l'exécution, Windows met immédiatement fin au programme, brisant ainsi tout exploit qui tente d'appeler indirectement une adresse non valide.

Voir aussi

/guard (Activer la protection du flux de contrôle)

/GUARD (Activer les contrôles de protection)