Ken Thompson a décrit une méthode pour corrompre un binaire du compilateur (et d'autres logiciels compilés, comme un script de connexion sur un système * nix) en 1984. J'étais curieux de savoir si la compilation moderne a corrigé cette faille de sécurité ou non.
Réécrivez le code du compilateur pour qu'il contienne 2 défauts:
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 compilera de nouvelles versions de lui-même à l'avenir, il conservera les failles précédentes - et les failles ne existent dans le binaire du compilateur sont donc extrêmement difficiles à détecter.
Je n'ai trouvé aucune réponse à ces questions sur le Web:
Je suis tombé sur cela tout en faisant mes devoirs, et cela semblait intéressant, mais je n'ai pas les antécédents pour comprendre de manière concrète s'il s'agit d'un problème actuel ou d'un problème résolu.
Ce hack doit être compris dans son contexte. Il a été publié à une époque et dans une culture où Unix fonctionnant sur toutes sortes de matériel différent était le système dominant.
Ce qui a rendu l'attaque si effrayante, c'est que le compilateur C était le logiciel central pour ces systèmes. Presque tout dans le système est passé 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 qu'il soit compilé), donc le fait que le compilateur injecte des portes dérobées semblait être une sorte de "crime parfait" où vous ne pouviez pas être attrapé.
De nos jours, le matériel est beaucoup plus compatible et les compilateurs ont donc un rôle beaucoup plus petit dans le fonctionnement quotidien d'un système. Un compilateur compromis n'est plus le scénario le plus effrayant - les rootkits et un BIOS compromis sont encore plus difficiles à détecter et à éliminer.
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 toujours devez faire confiance quelqu'un (d'où le titre: "Reflections On Trusting Trust")
Même si vous êtes du genre paranoïaque qui chiffre son disque dur de bureau et refuse d'exécuter tout logiciel que vous n'avez pas compilé 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 encore devez faire confiance à compilateur! Et cela ne mentionne même pas les fabricants de matériel!
Vous ne pouvez tout simplement pas vous en sortir en faisant confiance personne. C'est le point qu'il essayait de faire passer.
L'attaque, telle que décrite à l'origine, n'a jamais été une menace. Alors qu'un compilateur pourrait théoriquement le faire, réussir l'attaque nécessiterait de programmer le compilateur pour
Cela implique de comprendre comment le compilateur fonctionne à partir de son code source, afin de pouvoir le modifier sans rupture.
Par exemple, imaginez que le format de liaison stocke les longueurs de données ou l'offset du code machine compilé quelque part dans l'exécutable. Le compilateur devrait déterminer lui-même lesquels doivent être mis à jour et où, lors de l'insertion de la charge utile d'exploit. Les versions ultérieures du compilateur (version inoffensive) peuvent modifier arbitrairement ce format, de sorte que le code d'exploitation devrait effectivement comprendre ces concepts.
Il s'agit d'une programmation auto-dirigée de haut niveau, un problème d'IA difficile (la dernière fois que j'ai vérifié, l'état de l'art générait du code qui est pratiquement déterminé par ses types). Regardez: peu d'humains peuvent même faire ça; vous devez d'abord apprendre le langage de programmation et comprendre la base de code.
Même si le problème de l'IA est résolu, les gens remarqueraient que la compilation de leur minuscule compilateur aboutit à un binaire avec une énorme bibliothèque d'IA liée.
Cependant, une généralisation de l'attaque est pertinente. Le problème de base est que votre chaîne de confiance doit commencer quelque part, et dans de nombreux domaines, son origine pourrait renverser la chaîne entière d'une manière difficile à détecter.
Votre système d'exploitation, par exemple Ubuntu Linux, garantit la sécurité (l'intégrité) des mises à jour en comparant les packages de mise à jour téléchargés à 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é la distribution du système d'exploitation pour la première fois.
Vous devez avoir confiance que la source de votre chaîne de confiance, cette clé de signature, n'est pas mauvaise.
Toute personne qui peut MITM la connexion Internet entre vous et le serveur de téléchargement Ubuntu — cela pourrait être votre FAI, un gouvernement qui contrôle l'accès à Internet (par exemple en Chine), ou Le fournisseur d'hébergement d'Ubuntu - aurait pu détourner ce processus:
Désormais, vous obtiendrez vos mises à jour en toute sécurité depuis le serveur de l'attaquant. Les mises à jour s'exécutent en tant que root, donc 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 du CD téléchargée à l'aide d'un hachage ( peu de gens le font réellement ) - et le hachage doit lui-même être téléchargé en toute sécurité, par exemple via HTTPS. Et si votre attaquant peut ajouter un certificat sur votre ordinateur (commun dans un environnement d'entreprise) ou contrôle une autorité de certification (par exemple la Chine), même HTTPS n'offre aucune protection.
Tout d'abord, mon écriture préférée de ce hack s'appelle Strange Loops .
Ce piratage particulier pourrait certainement (*) être effectué aujourd'hui dans l'un des principaux projets de système 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 qui a un compilateur exploité pour modifier openssh. À partir de là, chaque fois que vous mettrez à jour openssh ou le compilateur par source, vous continuerez le problème. En supposant que l'attaquant a exploité le système utilisé pour empaqueter FreeBSD en premier lieu (probablement, puisque l'image elle-même est corrompue, ou l'attaquant est en fait le packager), chaque fois que le système reconstruit les binaires FreeBSD, il réinjectera le problème. Il existe de nombreuses façons pour que cette attaque échoue, mais elles ne sont pas fondamentalement différentes de la façon dont l'attaque de Ken aurait pu échouer (**). Le monde n'a vraiment pas beaucoup changé.
Bien sûr, 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 dans le matériel (en particulier l'affaiblissement de la génération de nombres aléatoires).
(*) Mais par "certainement" je veux dire "en principe". Devriez-vous vous attendre à ce que ce type de trou existe dans un système particulier? Non. Je considérerais cela comme peu probable pour diverses raisons pratiques. Au fil du temps, à mesure que le code change et change, la probabilité que ce type de piratage provoque des bogues étranges augmente. Et cela augmente la probabilité qu'il soit découvert. Des portes dérobées moins ingénieuses nécessiteraient des complots pour se maintenir. Bien sûr, nous savons pertinemment que des portes dérobées à "interception légale" ont été installées dans divers systèmes de télécommunications et de mise en réseau, donc 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 jamais existé. Il vient de voir comment cela pourrait être fait. Il n'a pas dit qu'il l'avait fait pour autant que je sache.
Cette attaque affecte principalement les langues qui s'auto-hébergent. Ce sont des langues où le compilateur est écrit dans la langue elle-même. C, Squeak Smalltalk et l'interpréteur PyPy Python en serait affecté. Perl, JavaScript et CPython Python ne le serait pas).
Pas beaucoup. C'est la nature auto-hébergée du compilateur qui permet de masquer le hack. Je ne connais aucun compilateur JIT auto-hébergeant. (Peut-être LLVM?)
Pas habituellement. Mais la question n'est pas quand elle est compilée, mais par quel compilateur. Si le programme de connexion est compilé par un compilateur corrompu, il sera corrompu. S'il est compilé par un compilateur propre, il sera propre.
Il s'agit toujours d'une menace théorique, mais peu probable.
Une chose que vous pourriez faire pour l'atténuer est d'utiliser plusieurs compilateurs. Par exemple, un compilateur LLVM qui est lui-même compilé par GCC ne passera pas le long d'une porte dérobée. De même, un GCC compilé par LLVM ne passera pas le long d'une porte arrière. Donc, si vous êtes préoccupé par ce type d'attaque, vous pouvez compiler votre compilateur avec une autre race de compilateur. Cela signifie que le pirate malveillant (chez votre fournisseur de système d'exploitation?) Devra entacher les deux compilateurs pour se reconnaître; Un problème beaucoup plus difficile.
Il y a une chance théorique que cela se produise. Il existe cependant un moyen de vérifier si un compilateur spécifique (avec le code source disponible) a été compromis, grâce à David A. Wheeler Diverse double-compilation .
Fondamentalement, utilisez à la fois le compilateur suspect et un autre compilateur développé indépendamment pour compiler la source du compilateur suspect. Cela vous donne SCcaroline du Sud et SCT. 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é de choses qui peuvent bien légitimement varier, comme des horodatages assortis), le compilateur suspect n'abuse pas réellement de la confiance.
En tant qu'attaque spécifique, c'est autant une menace que jamais, ce qui n'est pratiquement pas une menace du tout.
Comment est-ce lié à la compilation juste à temps?
Je ne sais pas ce que tu veux dire par là. Un JITter est-il immunisé contre cela? Non. Est-il 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 non encore 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.
Les fonctions comme le programme gérant les connexions sur un système * nix sont-elles compilées lors de leur exécution?
Ce n'est pas vraiment pertinent.
Est-ce toujours une menace valable, ou y a-t-il eu des développements dans la sécurité de la compilation depuis 1984 qui empêchent que cela soit un problème important?
Il n'y a pas de réelle sécurité de compilation et ne peut pas l'être. C'était vraiment le point de son discours, qu'à un moment donné, vous devez faire confiance à quelqu'un.
Cela affecte-t-il toutes les langues?
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 effectuée.