Garantir l’intégrité d’exécution des programmes

L’exploitation d’une faille de sécurité passe souvent par le détournement d’un programme. D’où la nécessité de le protéger, y compris durant son exécution. Au Laboratoire de haute sécurité (LHS) de Rennes des chercheurs expérimentent une méthode consistant à chiffrer le déroulement des instructions de telle manière qu’il devienne impossible d’injecter du code illégitime pour prendre la main.


 

L’idée trottait dans les esprits depuis un moment. Il y avait bien eu quelques tentatives d’implémentations. Mais personne n’avait encore réalisé une preuve de concept offrant de grandes garanties théoriques. Et c’est ce que vient de parvenir à faire le Laboratoire de Haute Sécurité créé par Inria, CentraleSupelec, le CNRS, la Direction générale de l’armement et la Région Bretagne.  Question de départ : comment protéger l’exécution d’un logiciel ? Des attaques sophistiquées parviennent parfois à détourner certaines instructions qui circulent dans le processeur pour y injecter des commandes illégitimes.

 

 

“Il faut donc garantir que chaque instruction qui s’exécute est bien la bonne, résume Ronan Lashermes, ingénieur de recherche. Pour cela, nous utilisons une technique consistant à chiffrer ces instructions en utilisant le graphe de flot de contrôle. Dans un logiciel, les instructions successives ne s’exécutent pas toutes les unes derrière les autres de façon linéaire. En pratique, très souvent, le programme saute d’une instruction à une autre, pour toutes sortes de raisons, par le biais de branchements. Il peut y avoir aussi des instructions conditionnelles : s’il se passe telle chose, alors aller à tel endroit pour continuer le travail. Cette organisation des instructions forme ce que l’on appelle le graphe de flot de contrôle.”

Chiffrer avec l’historique des instructions

À partir de là, les scientifiques utilisent une technique connue sous le nom anglais d’Instruction Set Randomization (randomisation du jeu d’instructions). “Nous chiffrons le programme en encodant l’état à chaque moment, c’est à dire pour chaque instruction. À un instant t, cet état du programme correspond donc à l’historique de toutes les instructions déjà exécutées.” C’est comme si l’on photographiait chaque étape du déroulement du programme.

“Nous représentons chacun de ces états successifs par une valeur spécifique que nous calculons à partir du graphe. En l’occurrence, il s’agit d’un très grand nombre qui va nous servir à chiffrer l’instruction. Le processeur devra ensuite déchiffrer ces instructions à la volée.

Si l’on utilise la bonne valeur correspondant à l’état attendu, alors on peut déchiffrer l’instruction juste avant son exécution. En revanche, si une instruction illégitime s’est glissée dans le système, l’état s’en trouve modifié. Impossible alors de déchiffrer car la valeur calculée pour l’état n’est plus la bonne.”

Une parade à beaucoup d’attaques

Compliqué ? “Oui. Et cette technique présente aussi une limite. Dans nos travaux, nous sommes obligés de considérer que l’on connaît initialement le graphe. Or, en pratique, ce n’est pas toujours le cas. Car, à la compilation, certaines instructions pointent parfois vers des valeurs dynamiques, donc inconnues à l’avance.” Autre inconvénient : le coût de calcul pour chiffrer et déchiffrer la litanie d’instructions.

“Cette  méthode consomme de la ressource. C’est clair. Mais notre implémentation pourrait sans doute être largement optimisée. Ce qui nous intéressait avant tout, c’était de valider la preuve de concept dans une véritable implémentation offrant de bonnes garanties. Les résultats (1) que nous venons de publier avec mes collègues Hélène Le Bouder (IMT Atlantique) et Gaël Thomas (DGA) permettent d’affirmer que ce genre de schéma offre une protection qui met le logiciel à l’abri de beaucoup de types d’attaques. Les attaques électro-magnétiques, par exemple. Mais aussi des attaques par ROP (Return-Oriented Programming). Dans ce deuxième cas, l’attaquant ne va pas essayer de faire exécuter son propre programme car cela devient difficile en raison de toutes les protections qui apparaissent. Il va plutôt tenter de modifier le flot de contrôle pour ensuite réutiliser des instructions légitimes afin d’exécuter son propre programme. C’est beaucoup plus difficile à repérer. Mais avec notre technique de protection, le ROP devient impossible.”

Quel impact au niveau industriel ? “Les constructeurs ne vont pas utiliser ce schéma directement. Mais nos recherches vont nourrir leur réflexion. Dans les années qui viennent, nous allons certainement assister à une spécialisation des cœurs. Elle existe déjà pour l’énergie, par exemple, avec des optimisations différentes en fonction de l’utilisation. Et de la même façon, dans les processeurs, nous allons voir émerger un cœur dédié à la sécurité. Les cœurs sécurisés pourront exécuter du code arbitraire avec plus de garanties. C’est dans cet axe-là que notre travail (2) va plutôt s’inscrire.”

 

  • (1) Lire : Hardware-Assisted Program Execution Integrity: HAPEI. Par : Ronan Lashermes, Hélène Le Bouder et Gaël Thomas. Dans : The 23rd Nordic Conference on Secure IT Systems. Novembre 2018.


  • (2) Ces recherches se poursuivent dans le cadre d’une nouvelle thèse de doctorat par Mathieu Escouteloup au sein de Cidre, une équipe de cybersécurité d’Inria, CentraleSupélec, Université Rennes 1 et CNRS, commune à l’Irisa.

 

Les commentaires sont clos.