Portes arrière de microcode assemblées par processeur X86

Nous n'avons pas fait confiance aux logiciels depuis longtemps, et donc nous effectuons son audit, procédons à la rétro-ingénierie, les exécutons étape par étape, les exécutons dans le bac à sable. Qu'en est-il du processeur sur lequel notre logiciel fonctionne? - Nous faisons confiance aveuglément et sans réserve à ce petit morceau de silicium. Cependant, le matériel moderne a les mêmes problèmes que les logiciels: fonctionnalité secrète non documentée, bogues, vulnérabilités, logiciels malveillants, chevaux de Troie, rootkits, portes dérobées.



ISA (Instruction Set Architecture) x86 est l'une des plus longues «architectures de jeu d'instructions» en évolution constante de l'histoire. À partir de la conception 8086 développée en 1976, ISA subit des modifications et des mises à jour continues; tout en conservant la compatibilité descendante et la prise en charge de la spécification d'origine. Plus de 40 ans de croissance, l'architecture ISA a grandi et continue de croître avec de nombreux nouveaux modes et ensembles d'instructions, chacun ajoutant une nouvelle couche à la conception précédente, déjà surchargée. En raison de la politique de compatibilité descendante totale, les processeurs x86 modernes contiennent même des instructions et des modes qui sont déjà complètement oubliés. En conséquence, nous avons une architecture de processeur, qui est un labyrinthe complexe de technologies nouvelles et anciennes. Un tel environnement extrêmement complexe - provoque de nombreux problèmes avec la cybersécurité du processeur. Par conséquent, les processeurs x86 ne peuvent pas prétendre être la racine fiable de la cyber-infrastructure critique.


Faites-vous toujours confiance à votre processeur?


Sécurité des programmes et du système d'exploitation - est basée sur la sécurité du matériel sur lequel ils sont déployés. En règle générale, les développeurs de logiciels ne prennent pas en compte le fait que le matériel sur lequel leur logiciel est déployé peut être non fiable, malveillant. Lorsque le matériel se comporte de manière erronée (intentionnellement ou non), les mécanismes de sécurité des logiciels perdent toute valeur. Depuis de nombreuses années, différents modèles de processeurs sécurisés ont été proposés: Intel SGX, AMD Pacifica, etc. Néanmoins, la régularité enviable avec laquelle les informations sont publiées sur les défaillances critiques (de récentes, par exemple Meltdown et Spectre) et détecté des fonctions de «débogage» non documentées - conduit à l'idée que notre entière confiance dans les processeurs est sans fondement.


Les processeurs x86 modernes sont un entrelacement très lourd et complexe des technologies les plus récentes et anciennes. 8086 avait 29 mille transistors, Pentium 3 millions, Broadwell 3,2 milliards, Cannonlake plus de 10 milliards.



Avec autant de transistors, il n'est pas surprenant que les processeurs x86 modernes soient criblés d'instructions non documentées et de vulnérabilités matérielles. Parmi les non documentés, qui ont été découverts presque par accident, des instructions: ICEBP (0xF1), LOADALL (0x0F07), apicall (0x0FFFF0) [1], qui permettent de déverrouiller le processeur pour un accès non autorisé aux zones de mémoire protégées.


Quant aux nombreuses vulnérabilités matérielles des processeurs (voir deux figures ci-dessous), elles permettent à un cyber-attaquant d'augmenter ses privilèges [3], d'extraire des clés cryptographiques [4], de créer de nouvelles instructions d'assembleur [2], de changer la fonctionnalité des instructions d'assembleur déjà existantes [2] , installez des hooks sur les instructions de l'assembleur [2], prenez le contrôle de la «virtualisation accélérée matérielle» [7], intervenez dans les «calculs cryptographiques atomiques» [7], et, enfin, doux, entrez en «mode divin»: vous ive un matériel légitime porte dérobée Intel ME (ce qui vous permet de recevoir un accès à distance, même l'ordinateur est éteint). [8] Et tout cela - sans laisser de traces numériques.




Les processeurs modernes sont plus logiciels que matériels


À proprement parler, les processeurs modernes ne peuvent même pas être appelés "matériel" au sens plein du terme. Parce que leur fonctionnalité la plus critique (y compris ISA) est fournie par le microcode clignotant. Initialement, le microcode était principalement responsable du contrôle du décodage et de l'exécution des instructions d'assembleurs complexes: opérations en virgule flottante, primitives MMX, gestionnaires de lignes avec le préfixe REP, etc. Cependant, au fil du temps, de plus en plus de responsabilités sont attribuées au microcode pour les opérations de traitement à l'intérieur du processeur. Par exemple, les extensions modernes des processeurs Intel, telles que AVX (Advanced Vector Extensions) et VT-d (virtualisation matérielle) sont implémentées sur microcode.


De plus, le microcode est aujourd'hui responsable, entre autres, du maintien de l'état du processeur, de la gestion du cache, et également de la gestion des économies d'énergie. Pour économiser de l'énergie, le microcode a un mécanisme d'interruption qui traite les états de puissance: état C (degré de sommeil à économie d'énergie: de l'état actif au sommeil profond) et état P (différentes combinaisons de tension et de fréquence). Ainsi, par exemple, le microcode est responsable de la réinitialisation du cache L2 lors de l'entrée dans l'état C4, ainsi que lors de sa sortie.


Pourquoi les fabricants de processeurs utilisent-ils un microcode?


Les fabricants de processeurs x86 utilisent un microcode pour décomposer des instructions d'assemblage complexes (pouvant aller jusqu'à 15 octets) en une chaîne de micro-instructions simples, afin de simplifier l'architecture matérielle et de faciliter les diagnostics. En fait, le microcode est un interprète entre l'architecture CISC externe (visible pour l'utilisateur) et l'architecture RISC interne (matérielle).


Si des erreurs sont détectées dans l'architecture CISC (principalement dans ISA), les fabricants publient une mise à jour du microcode qui peut être téléchargée sur le processeur via le BIOS / UEFI de la carte mère ou via le système d'exploitation (pendant le processus de démarrage). Grâce à un tel système de mise à jour basé sur des microcodes, les fabricants de processeurs se procurent flexibilité et réduction des coûts - tout en corrigeant les erreurs dans leurs équipements. L'erreur sensationnelle avec fdiv, qui a gravement fait tomber les processeurs Intel Pentium en 1994, a rendu le fait que les erreurs matérielles de haute technologie sujettes aux logiciels le rendent encore plus évident. Cet incident a donné aux fabricants encore plus d'intérêt pour l'architecture des processeurs à microcodes. Par conséquent, Intel et AMD ont commencé à construire leurs processeurs en utilisant la technologie des microcodes. Intel - à commencer par le Pentium Pro (P6), sorti en 1995. AMD - à commencer par le K7, sorti en 1999.


Tout secret devient clair


Malgré le fait que les fabricants de processeurs tentent de garder l'architecture des microcodes et le mécanisme de mise à jour dans la plus stricte confidentialité, l'ennemi n'est pas endormi. Des informations fragmentées (provenant principalement de brevets, tels que AMD RISC86 [5]) et une inversion réfléchie des mises à jour officielles du BIOS (comme c'était le cas avec K8 [6]), éclaircissent progressivement le secret du microcode (voir, par exemple, dans la figure ci-dessous " Mécanisme de mise à jour du microcode du processeur AMD »). Et grâce à l'évolution constante des outils d'inversion (logiciels et matériels) [2], aux techniques de fuzzing prometteuses [1] et à l'avènement des outils OpenSource tels que Microparse [9] et Sandsifter [10] - un cyber-attaquant peut tout apprendre sur un microcode nécessaire pour avoir à y écrire des logiciels malveillants à microcodes.



Ainsi, par exemple, dans [2] comme "Bonjour tout le monde!" (la première étape pour trojaniser le microcode) un «micro hook» (programme de microcode qui intercepte l'instruction d'assembleur) a été développé, qui compte combien de fois le processeur a accédé à la commande div. Ce micro-crochet est une injection dans le gestionnaire de la division instruction assembleur.



Ibid [2] présente un micro-crochet plus avancé, qui se trouve tranquillement dans l'instruction d'assembleur du div ebx, sans révéler sa présence, et n'est activé que lorsque des conditions spécifiques sont remplies en se référant au div ebx: le registre ebx contient la valeur B, et le registre eax contient la valeur A. Lorsqu'il est activé, ce micro-crochet augmente la valeur du registre eip (pointeur d'instruction courant) d'une unité. En conséquence, l'exécution du programme (qui a eu le courage de se référer à l'instruction div ebx) se poursuit avec un décalage: non pas à partir du premier octet de la commande suivant le div ebx, mais à partir de son deuxième octet. Si d'autres valeurs sont spécifiées dans les registres eax et ebx, alors la div ebx fonctionne comme d'habitude. Quelle en est la valeur pratique? Par exemple, pour activer discrètement une chaîne cachée d'instructions d'assembleur lors de l'utilisation de techniques d'obscurcissement avec des «instructions qui se chevauchent» [11].



Ces deux exemples montrent comment des instructions d'assembleur légitimes peuvent être utilisées pour y cacher du code cheval de Troie arbitraire.


Dans le même temps, un cyber-attaquant peut activer sa charge utile malveillante - y compris à distance. Par exemple, lorsque la condition nécessaire à l'activation est remplie sur une page Web contrôlée par un attaquant. Cela est possible grâce aux compilateurs Just-in-Time (JIT) et Ahead-of-Time (AOT) intégrés aux navigateurs Web modernes. Ces compilateurs vous permettent d'émettre un flux prédéfini d'instructions d'assembleur pour le code machine - même si vous écrivez le programme exclusivement en JavaScript de haut niveau (voir la dernière liste, juste au-dessus).


Bibliographie
  1. Christopher Domas . Briser le x86 ISA // DEFCON 25.07.2017.
  2. Philipp Koppe . Reverse Engineering x86 Processor Microcode // Actes du 26ème symposium de sécurité USENIX. 2017. pp. 1163-1180.
  3. Matthew Hicks . SPÉCIFICATIONS: Un mécanisme d'exécution léger pour protéger les logiciels contre les bogues des processeurs critiques pour la sécurité // Actes de la 28e Conférence internationale sur le support architectural des langages de programmation et des systèmes d'exploitation (ASPLOS). 2015. pp. 517-529.
  4. Adi Shamir . Bug Attacks // Actes de la 28e conférence annuelle sur la cryptographie: les progrès de la cryptologie. 2008. pp. 221–240.
  5. John Favor . Jeu d'instructions RISC86 // Brevet américain 6336178. 2002.
  6. Opteron Exposed: Reverse Engineering AMD K8 Microcode Updates . 2004.
  7. Saming Chen . Analyse de sécurité du microcode du processeur x86 .2014.
  8. Catalin Cimpanu . Un logiciel malveillant utilise la fonction de processeur Intel obscur pour voler des données et éviter les pare-feu . 2017.
  9. Daming Chen . Microparse: analyseur de microcodes pour les processeurs AMD, Intel et VIA // GitHub. 2014.
  10. Sandsifter: le processeur x86 fuzzer // GitHib. 2017.
  11. Karev V.M. Comment écrire un programme assembleur avec des instructions qui se chevauchent (une autre technique pour brouiller le code d'octet) // Habrahabr. 2018. URL: (Date d'accès: 25 octobre 2018).

Source: https://habr.com/ru/post/fr427757/


All Articles