Ken Thompson Hack (1984)
Ken Thompson a décrit une méthode pour corrompre un binaire du compilateur (et d'autres logiciels compilés, comme un script de login sur un système * nix) en 1984. J'étais curieux de savoir si la compilation moderne avait corrigé ou non cette faille de sécurité.
Brève description:
Réécrivez le code du compilateur pour qu'il contienne 2 failles:
- Lors de la compilation de son propre binaire, le compilateur doit compiler ces failles
- Lors de la compilation d’un autre code présélectionné (fonction de connexion), il doit compiler une porte dérobée arbitraire.
Ainsi, le compilateur fonctionne normalement - lorsqu'il compile un script de connexion ou similaire, il peut créer une porte dérobée de sécurité, et lorsqu'il compile de nouvelles versions de lui-même à l'avenir, il conserve les failles précédentes - et les failles n'existeront que dans le compilateur. binaires sont donc extrêmement difficiles à détecter.
Des questions:
Je n'ai trouvé aucune réponse à ces questions sur le Web:
- Comment cela se rapporte-t-il à la compilation juste à temps?
- Des fonctions telles que le programme gérant les connexions sur un système * nix sont-elles compilées lors de leur exécution?
- Est-ce toujours une menace valable, ou existe-t-il des développements dans la sécurité de compilation depuis 1984 qui empêchent que cela soit un problème important?
- Cela affecte-t-il toutes les langues?
Pourquoi est-ce que je veux savoir?
Je suis tombé sur cette idée en faisant des devoirs. Cela semblait intéressant, mais je n’ai pas suffisamment d’arrière-plan pour comprendre concrètement s’il s’agit d’un problème d'actualité ou d'un problème résolu.
Réponses:
Ce hack doit être compris dans son contexte. Il a été publié à une époque et dans une culture où Unix fonctionnant sur tout type de matériel était le système dominant.
Ce qui a rendu l’attaque si effrayante, c’est que le compilateur C était le logiciel central de ces systèmes. Presque tout dans le système passait par le compilateur lors de sa première installation (les distributions binaires étaient rares en raison du matériel hétérogène). Tout le monde compilait des trucs tout le temps. Les gens inspectaient régulièrement le code source (ils devaient souvent faire des ajustements pour le compiler), donc faire injecter le compilateur à l'arrière-plan semblait être une sorte de scénario de "crime parfait" où vous ne pourriez pas vous faire prendre.
De nos jours, le matériel est beaucoup plus compatible et les compilateurs jouent donc un rôle beaucoup moins important dans le fonctionnement quotidien d'un système. Un compilateur compromis n’est plus le scénario le plus effrayant: des rootkits et un BIOS compromis sont encore plus difficiles à détecter et à supprimer.
la source
Le but de ce discours n'était pas de mettre en évidence une vulnérabilité à traiter, ni même de proposer une vulnérabilité théorique dont nous devons être conscients.
Le but était que, en matière de sécurité, nous ne voulions faire confiance à personne, mais malheureusement, c'est impossible. Vous devez toujours faire confiance à quelqu'un (d'où le titre: "Réflexions sur la confiance")
Même si vous êtes un type paranoïaque qui crypte le disque dur de son ordinateur de bureau et refuse d’exécuter les logiciels que vous n’avez pas compilés vous-même, vous devez toujours faire confiance à votre système d’exploitation. Et même si vous compilez le système d'exploitation vous-même, vous devez toujours faire confiance au compilateur que vous avez utilisé. Et même si vous compilez votre propre compilateur, vous devez toujours faire confiance à ce compilateur! Et cela ne mentionne même pas les fabricants de matériel!
Vous ne pouvez tout simplement pas vous en tirer en ne faisant confiance à personne . C'est le point qu'il essayait de faire passer.
la source
Non
L'attaque, telle que décrite à l'origine, n'a jamais été une menace. Théoriquement, un compilateur pourrait le faire, mais pour en venir à bout de l'attaque, il faudrait le programmer pour qu'il
Cela implique de déterminer le fonctionnement du compilateur à partir de son code source, afin de pouvoir le modifier sans interruption.
Par exemple, imaginez que le format de liaison stocke les longueurs de données ou le décalage du code machine compilé quelque part dans l'exécutable. Le compilateur devrait déterminer lui-même lequel de ces éléments doit être mis à jour et où, lors de l'insertion de la charge utile de l'exploit. Les versions ultérieures du compilateur (version inoffensive) peuvent changer arbitrairement ce format, de sorte que le code d'exploitation aurait effectivement besoin de comprendre ces concepts.
C'est une programmation auto-dirigée de haut niveau, un problème d'intelligence artificielle difficile (la dernière fois que j'ai vérifié, l'état de l'art produisait du code qui est pratiquement déterminé par ses types). Regardez: peu d'humains peuvent même le faire; il vous faudrait d'abord apprendre le langage de programmation et comprendre la base de code.
Même si le problème de l'IA était résolu, les gens remarqueraient que si compiler leur compilateur minuscule aboutissait à un binaire avec une énorme bibliothèque d'IA liée à celui-ci.
Attaque analogue: amorçage de la confiance
Cependant, une généralisation de l'attaque est pertinente. Le problème fondamental est que votre chaîne de confiance doit commencer quelque part et que, dans de nombreux domaines, son origine pourrait subvertir toute la chaîne de manière difficile à détecter.
Un exemple qui pourrait facilement être tiré dans la vie réelle
Ubuntu Linux, votre système d’exploitation assure la sécurité (intégrité) des mises à jour en vérifiant les packages de mise à jour téléchargés par rapport à la clé de signature du référentiel (à l’aide de la cryptographie à clé publique). Mais cela ne garantit l' authenticité des mises à jour que si vous pouvez prouver que la clé de signature appartient à une source légitime.
Où avez-vous obtenu la clé de signature? Lorsque vous avez téléchargé pour la première fois la distribution du système d’exploitation.
Vous devez avoir la certitude que la source de votre chaîne de confiance, cette clé de signature, n'est pas mauvaise.
Toute personne pouvant disposer de la connexion Internet MITM entre vous et le serveur de téléchargement Ubuntu - qu'il s'agisse de votre fournisseur d'accès à Internet, d'un gouvernement qui contrôle l'accès à Internet (par exemple en Chine) ou du fournisseur d'hébergement Ubuntu - aurait pu détourner ce processus:
Dorénavant, vous obtiendrez vos mises à jour en toute sécurité du serveur de l'attaquant. Les mises à jour étant exécutées en tant que root, l’attaquant a le contrôle total.
Vous pouvez empêcher l'attaque en vous assurant que l'original est authentique. Mais cela nécessite que vous validiez l’image CD téléchargée à l’aide d’un hachage ( peu de gens le font réellement ). Le hachage doit lui-même être téléchargé de manière sécurisée, par exemple via HTTPS. Et si votre attaquant peut ajouter un certificat sur votre ordinateur (courant dans un environnement d'entreprise) ou contrôler une autorité de certification (par exemple, la Chine), même le protocole HTTPS ne fournit aucune protection.
la source
Premièrement, mon récit préféré de ce hack s'appelle Strange Loops .
Ce piratage particulier pourrait certainement (*) être fait aujourd'hui dans tous les grands projets de systèmes d'exploitation open source, en particulier Linux, * BSD, etc. Je m'attendrais à ce que cela fonctionne presque à l'identique. Par exemple, vous téléchargez une copie de FreeBSD avec un compilateur exploité pour modifier openssh. A partir de là, chaque fois que vous mettez à niveau openssh ou le compilateur par source, vous continuez le problème. En supposant que l'attaquant ait exploité le système utilisé pour empaqueter FreeBSD en premier lieu (vraisemblablement, étant donné que l'image elle-même est corrompue ou que l'attaquant est en fait le conditionneur), chaque fois que ce système reconstruira les fichiers binaires de FreeBSD, le problème sera réinjecté. Cette attaque peut échouer de nombreuses manières, mais elles ne diffèrent pas fondamentalement de la manière dont l'attaque de Ken aurait pu échouer (**). Le monde n'a vraiment pas beaucoup changé.
Bien entendu, des attaques similaires pourraient tout aussi bien (ou plus facilement) être injectées par leurs propriétaires dans des systèmes tels que Java, le SDK iOS, Windows ou tout autre système. Certains types de failles de sécurité peuvent même être intégrés au matériel (en particulier, affaiblir la génération de nombres aléatoires).
(*) Mais par "certainement", je veux dire "selon le principe". Devriez-vous vous attendre à ce que ce type de trou existe dans un système particulier? Non, je considérerais cela assez improbable pour diverses raisons pratiques. Avec le temps, au fur et à mesure que le code change, la probabilité que ce type de piratage provoque des bogues étranges augmente. Et cela augmente la probabilité que cela soit découvert. Des backdoors moins ingénieux nécessiteraient des complots à maintenir. Bien sûr, nous savons pertinemment que des portes dérobées "d'interception licite" ont été installées dans divers systèmes de télécommunication et de réseau, de sorte que, dans de nombreux cas, ce type de piratage élaboré est inutile. Le hack est installé ouvertement.
Alors toujours, défense en profondeur.
(**) En supposant que l'attaque de Ken ait réellement existé. Il a juste discuté de la façon dont cela pourrait être fait. Il n'a pas dit qu'il l'a réellement fait autant que je sache.
la source
Cela affecte-t-il toutes les langues?
Cette attaque affecte principalement les langues qui s'auto-hébergent. Ce sont les langues où le compilateur est écrit dans la langue elle-même. C, Squeak Smalltalk et l'interpréteur PyPy Python seraient affectés par cela. Perl, JavaScript et l'interpréteur CPython Python ne le feraient pas.
Comment cela se rapporte-t-il à la compilation juste à temps?
Pas beaucoup. C'est la nature auto-hébergée du compilateur qui permet de masquer le piratage. Je ne connais aucun compilateur JIT auto-hébergé. (Peut-être que LLVM?)
Des fonctions telles que le programme gérant les connexions sur un système * nix sont-elles compilées lors de leur exécution?
Pas habituellement. Mais la question n'est pas quand il est compilé, mais par quel compilateur . Si le programme de connexion est compilé par un compilateur corrompu, il sera corrompu. Si elle est compilée par un compilateur propre, elle le sera.
Est-ce toujours une menace valable, ou existe-t-il des développements dans la sécurité de compilation depuis 1984 qui empêchent que cela soit un problème important?
C'est toujours une menace théorique, mais ce n'est pas très probable.
Une solution consiste à utiliser plusieurs compilateurs. Par exemple, un compilateur LLVM qui est lui-même compilé par GCC ne passera pas par la porte arrière. De même, un GCC compilé par LLVM ne passera pas par une porte dérobée. Donc, si vous êtes inquiet à propos de ce type d'attaque, vous pouvez alors compiler votre compilateur avec un autre type de compilateur. Cela signifie que le pirate malveillant (chez votre fournisseur de système d'exploitation?) Devra souiller les deux compilateurs pour se reconnaître; Un problème beaucoup plus difficile.
la source
Il y a une chance théorique pour que cela se produise. Il existe toutefois un moyen de vérifier si un compilateur spécifique (avec le code source disponible) a été compromis, par le biais de la double compilation de David A. Wheeler .
Fondamentalement, utilisez le compilateur présumé et un autre compilateur développé indépendamment pour compiler la source du compilateur suspect. Cela vous donne SC sc et SC T . Maintenant, compilez la source suspecte à l'aide de ces deux fichiers binaires. Si les fichiers binaires résultants sont identiques (à l'exception d'une variété d'éléments qui peuvent légitimement varier, comme des horodatages assortis), le compilateur suspect n'abusait pas réellement de la confiance.
la source
En tant qu'attaque spécifique, il s'agit toujours d'une menace, qui n'en est quasiment pas une.
Je ne sais pas ce que vous entendez par là. Est-ce qu'un JITter est immunisé contre cela? Est-ce plus vulnérable? Pas vraiment. En tant que développeur, VOTRE application est plus vulnérable simplement parce que vous ne pouvez pas valider que cela n’a pas été fait. Notez que votre application encore non développée est fondamentalement à l'abri de cela et de toutes les variantes pratiques. Vous n'avez qu'à vous soucier d'un compilateur plus récent que votre code.
Ce n'est pas vraiment pertinent.
Il n'y a pas de réelle sécurité de compilation, et ne peut pas l'être. C'était vraiment le but de son discours, qu'à un moment donné, il faut faire confiance à quelqu'un.
Oui. Fondamentalement, à un moment ou à un autre, vos instructions doivent être transformées en quelque chose que l’ordinateur exécute, et cette traduction peut être mal faite.
la source
David Wheeler a un bon article: http://www.dwheeler.com/trusting-trust/
Moi, je suis plus inquiet pour les attaques de matériel. Je pense que nous avons besoin d’une chaîne d’outils de conception totalement VLSI avec du code source FLOSS, que nous pouvons modifier et compiler nous-mêmes, ce qui nous permet de construire un microprocesseur qui n’a pas de backdoors inséré par les outils. Les outils devraient également nous permettre de comprendre le but de tout transistor sur la puce. Ensuite, nous pourrions ouvrir un échantillon des puces finies et les inspecter avec un microscope, en nous assurant qu'elles avaient le même circuit que celui que les outils disaient être supposées avoir.
la source
Les systèmes dans lesquels les utilisateurs finaux ont accès au code source sont ceux pour lesquels vous devriez cacher ce type d'attaque. Ce seraient des systèmes open source dans le monde d'aujourd'hui. Le problème est que, même s’il existe une dépendance vis-à-vis d’un compilateur unique pour tous les systèmes Linux, l’attaque devrait toucher les serveurs de compilation pour toutes les principales distributions Linux. Puisque ceux-ci ne téléchargent pas directement les fichiers binaires du compilateur pour chaque version du compilateur, le source de l'attaque aurait dû se trouver sur leurs serveurs de génération dans au moins une version précédente du compilateur. Soit cette version, soit la toute première version du compilateur téléchargée en tant que binaire, aurait dû être compromise.
la source
Si on a le code source d'un système de compilation / compilation dont la sortie ne devrait dépendre que du contenu des fichiers sources fournis, et si on dispose de plusieurs autres compilateurs et sachant qu'ils ne contiennent pas tous le même hack de compilateur, on peut assurez-vous que vous obtenez un exécutable qui ne dépend que du code source.
Supposons que le paquetage d'un compilateur / éditeur de liens (par exemple, la suite Groucho) ait le code source écrit de telle sorte que sa sortie ne dépende d'aucun comportement non spécifié, ni d'aucun autre contenu que le contenu des fichiers source d'entrée, et on compile / des liens qui codent sur une variété de compilateurs / lieurs produits indépendamment (par exemple, les suites Harpo, les suites Chico et Zeppo), donnant un ensemble d'exeuctables différent pour chacun (appelez-les G-Harpo, G-Chico et G-Zeppo). Il n’est pas surprenant que ces exécutables contiennent différentes séquences d’instructions, mais elles doivent être fonctionnellement identiques. Prouver qu'ils sont fonctionnellement identiques dans tous les cas constituerait toutefois un problème insoluble.
Heureusement, une telle preuve ne sera pas nécessaire si vous utilisez les exécutables résultants dans un seul but: compiler à nouveau la suite Groucho. Si on compile la suite Groucho en utilisant G-Harpo (donnant GG-Harpo), G-Chico (GG-Chico) et G-Zeppo (GG-Zeppo), les trois fichiers résultants, GG-Harpo, GG-Chico , et GG-Zeppo, doivent tous être identiques octet par octet. Si les fichiers concordent, cela impliquerait que tout "virus du compilateur" existant dans l'un d'entre eux doit exister de manière identique dans chacun d'entre eux (les trois fichiers étant identiques octet par octet, il est impossible que leurs comportements diffèrent de quelque manière que ce soit). façon).
En fonction de l'âge et de la lignée des autres compilateurs, il peut être possible de s'assurer qu'un tel virus ne puisse exister de manière plausible dans ceux-ci. Par exemple, si vous utilisez un ancien Macintosh pour alimenter un compilateur écrit à partir de rien en 2007 avec une version de MPW écrite dans les années 1980, les compilateurs des années 1980 ne sauraient pas où insérer un virus dans le compilateur 2007. Il est peut-être possible aujourd'hui pour un compilateur de faire une analyse de code assez sophistiquée pour le comprendre, mais le niveau de calcul requis pour une telle analyse dépasserait de loin le niveau de calcul requis pour simplement compiler le code, et n'aurait peut-être pas passé inaperçu. dans un marché où la vitesse de compilation était un argument de vente majeur.
Je dirais que si on travaille avec des outils de compilation où les octets d'un fichier exécutable à produire ne doivent dépendre d'aucune autre manière que du contenu des fichiers sources soumis, il est possible d'obtenir une immunité relativement bonne d'un Thompson virus de style. Malheureusement, pour une raison quelconque, le non-déterminisme dans la compilation semble être considéré comme normal dans certains environnements. Je reconnais que sur un système multiprocesseur, un compilateur peut fonctionner plus rapidement s’il est autorisé à faire varier certains aspects de la génération de code en fonction de l’un des deux threads qui termine un travail en premier.
D'autre part, je ne vois pas pourquoi les compilateurs / éditeurs de liens ne devraient pas fournir un mode de "sortie canonique" dans lequel la sortie dépend uniquement des fichiers source et d'une "date de compilation" qui peut être remplacée par l'utilisateur. . Même si la compilation de code dans un tel mode prenait deux fois plus de temps qu'une compilation normale, je suggérerais qu'il serait extrêmement utile de pouvoir recréer n'importe quelle "release build", octet pour octet, entièrement à partir de sources, même si cela signifiait les versions de publication prendraient plus de temps que les "versions normales".
la source