web-dev-qa-db-fra.com

Est-il sûr de compiler un morceau de code source à partir d'un inconnu aléatoire?

Supposons que j'examine le code envoyé par les candidats pour prouver leurs compétences. De toute évidence, je ne veux pas exécuter les exécutables qu'ils envoient. Pas si clairement que je préfère ne pas exécuter le résultat de la compilation de leur code (juste par exemple, Java permet de masquer le code exécutable dans les commentaires ).

Et la compilation de leur code? Je veux des avertissements du compilateur le cas échéant, mais que faire si leur code contient des séquences de caractères intelligentes qui exploitent mon compilateur et mon compilateur compromet ma machine?

Lorsque je recherche les "vulnérabilités du compilateur" sur Google, les résultats que je reçois concernent les optimisations du compilateur et l'émission de code et si le code émis est aussi sûr que le code source d'origine était censé l'être.

Les compilateurs sont-ils généralement validés pour garantir qu'ils ne compromettent pas la machine de l'utilisateur lors de la compilation d'un morceau de code intelligent? Est-il sûr de compiler un morceau de code à partir d'un inconnu?

41
sharptooth

Ça dépend.

Ce morceau de makefile pourrait supprimer votre répertoire personnel:

all:
    rm -rf ~

Donc, si vous devez utiliser un outil (comme cmake ou makefile), ce n'est pas sûr. Cela dépend simplement de la malveillance du codeur.

De l'autre côté, les compilateurs sont programmés par des gens, donc ils ont des bugs. Il est donc possible que quelqu'un trouve un moyen d'exécuter du code malveillant pendant la compilation.

Comme suggéré dans les commentaires, si vous voulez être sûr qu'aucune chose amusante n'est faite à votre machine, utilisez une machine virtuelle.

34
BЈовић

Je suis sûr que quelque part dans l'entreprise, il y a des gars intelligents qui ont déjà créé un tel hack pour une langue et une version de compilateur spécifiques. Mon endroit préféré pour chercher quelque chose comme ça serait probablement le Concours International Obfuscated C - (je ne sais pas s'il y a quelque chose de comparable pour Java). Cependant, en réalité, à quel niveau considérez-vous le risque, supposez que

  • le candidat vous fait une impression plausible qu'il veut vraiment le travail dans votre entreprise (et non un procès)

  • le gars ne sait pas combien d'examen est effectué chez vous

  • il/elle ne sait pas quelle version exacte du compilateur vous utilisez

  • il/elle ne sait pas si vous utilisez un environnement virtuel ou un compilateur en ligne, juste pour être sûr

  • vous n'acceptez pas les programmes trop volumineux pour être examinés efficacement

  • vous ne compilez rien qui vous semble suspect

  • il n'y a pas beaucoup de gens dans le monde qui savent réellement comment accomplir techniquement une telle tâche (et googler seul ne vous donnera pas une "référence rapide" ou un tutoriel à ce sujet, comme vous l'avez déjà découvert par vous-même).

Donc, bien que la compilation ne soit pas "totalement sûre" en théorie, à mon humble avis, le risque est en réalité extrêmement faible que votre "compilateur soit alimenté".

23
Doc Brown

Il faut distinguer plusieurs cas:

  1. Un bug dans le compilateur. Comme tout programme complexe, un compilateur peut avoir des bogues et l'un de ces bogues peut être exploitable.
  2. Un cheval de Troie. L'attaquant peut vous faire exécuter du code arbitraire dans le cadre du processus de compilation. Un Makefile, un build.xml, un configure Script shell etc. Techniquement, cela n'est pas dû à la compilation du code de l'attaquant mais à la configuration de l'environnement de compilation.
  3. Langages permettant l'exécution de code arbitraire au moment de la compilation. Le langage macro de Scala est Scala, le langage macro Common LISP est Common LISP, le langage macro Template Haskell est Haskell. Scala possède également des plugins de compilation, qui sont à nouveau arbitraires Scala code qui s'exécute au moment de la compilation. F # a des fournisseurs de types.
  4. Langages permettant le calcul de Turing au moment de la compilation. Les systèmes de type Scala et Haskell sont complets de Turing, tout comme les modèles C++. Vous pouvez demander au compilateur d'effectuer des calculs de Turing arbitraires au moment de la compilation, y compris, mais sans s'y limiter, des boucles infinies. Notez que Turing-complete signifie seulement que vous pouvez calculer chaque fonction calculable de Turing, cela ne signifie pas que vous pouvez accéder au système de fichiers ou quelque chose comme ça. Mais, vous pouvez créer un programme qui prendra infiniment de temps à compiler.
  5. Temps de compilation très longs. Par exemple, les règles de C # pour la résolution de surcharge sont si complexes que vous pouvez coder tout problème 3-SAT en résolution de surcharge C #. Le 3-SAT est, bien sûr, réputé NP-complet. En d'autres termes, selon nos connaissances actuelles, il est impossible de trouver un algorithme efficace pour la résolution de surcharge en C #. Vous ne pouvez pas rendre la compilation infiniment longue, mais il ne faut pas un gros programme pour que la compilation prenne plus de temps que la durée de vie de l'univers, ce qui est pratiquement la même chose.

# 4. et # 5. entraînera tout au plus un déni de service. En pratique, C++ et Scala limitent la quantité de récursivité que vous pouvez faire, de sorte qu'il n'est pas en fait possible d'écrire une boucle infinie. Dans Scala, c'est juste un contrainte d'implémentation, mais en C++, c'est explicitement autorisé par la spécification, je crois.

# 2. est techniquement hors de portée de la question car la question portait sur la compilation de code ne l'exécutant pas (OTOH, il y a la profonde question philosophique: si la vérification de type d'un programme Haskell peut effectuer un calcul de Turing arbitraire, est-ce que la compilation ou l'exécution d'un programme?)

#1. est peu probable. D'une part, les compilateurs de production sont très complexes, donc la probabilité de bugs est élevée. D'un autre côté, ils sont rigoureusement testés, après tout, la gestion gracieuse des entrées mal formées fait partie de la description de travail d'un compilateur. Même s'ils ne sont pas testés, ils seront de toute façon bombardés de code mal formé… il suffit de regarder quelques questions sur StackOverflow pour des exemples de ce que les gens indésirables jettent sur leurs compilateurs!

Cela nous laisse avec 3. Certains compilateurs peuvent limiter le type d'accès du code temporel de compilation au système, mais pour certains cas d'utilisation, avoir un accès complet est inévitable. Le but des fournisseurs de types de F #, par exemple, est de "faux" types synthétiques pour les données dont le système de type ne correspond pas aux F #, afin que vous puissiez interagir avec, par exemple, un service Web qui a un schéma WSDL dans un type fortement typé mode. Cependant, pour ce faire, le fournisseur de type doit avoir accès à la ressource de schéma WSDL sur le système de fichiers ou sur le Web, il doit donc disposer d'un accès au système de fichiers et au réseau.

Alors, est-ce sûr? Techniquement, non. Est-ce risqué? Pas vraiment.

13
Jörg W Mittag

Il ne devrait pas y avoir de risque juste compilation le code. Dans théorie il pourrait y avoir un bogue dans le compilateur dont un pirate intelligent pourrait tirer parti, mais cela semble extrêmement improbable.

Sachez que bâtiment peut être dangereux. Par exemple, en C #, "événement de génération" vous permet de spécifier des lignes de commande arbitraires à exécuter avant et après la construction, ce qui est évidemment dangereux et beaucoup plus facile à exploiter que les débordements de tampon dans le code du compilateur.

3
JacquesB

Au lieu de spéculer, j'ai pris la peine de faire des recherches sur ce sujet avant de répondre, en allant à la ressource la plus fiable à laquelle je pouvais penser ( Détails CVE ). Cette liste complète d'exploits de sécurité divulgués publiquement est probablement la meilleure que l'on puisse faire pour évaluer les niveaux de menace de divers types de logiciels.

Je n'ai pas pris le temps de lire tout du matériel disponible, bien sûr, mais j'ai sélectionné quelques compilateurs, IDE et éditeurs de texte "principaux" pour arriver à un exemple d'évaluation des menaces. Si vous envisagez sérieusement d'exécuter un logiciel, vous devriez au moins voir quelles menaces existent. Notez également que les logiciels plus anciens sont généralement plus bogues que les logiciels plus récents, donc exécuter la dernière version de ce que vous utilisez est idéal.

Tout d'abord, nous pouvons jeter un œil à différents éditeurs de texte. Il semble que les meilleurs éditeurs soient les plus simples. Vi si vous utilisez un shell Linux, ou Bloc-notes si vous êtes sous Windows. Quelque chose sans capacité de formatage, sans analyse, juste une visualisation directe des données et une interruption automatique de l'analyse si un seul caractère est en dehors du schéma de codage actuel. Même Notepad ++ a eu une poignée de vulnérabilités. Évitez tout ce qui est complexe lorsque vous consultez des fichiers non fiables.

Deuxièmement, nous pouvons examiner les IDE. Si vous choisissez d'ouvrir le fichier dans un IDE, vous devez savoir que certains IDE ont signalé des bogues. Apparemment, Visual Studio a eu des exploits via le mécanisme d'extensions, donc l'ouverture d'une solution peut être problématique. Éviter les IDE évite toute une classe de problèmes entre vous et le code non approuvé. Rester avec VI semble beaucoup plus sûr.

Troisièmement, nous pouvons examiner les compilateurs réels. J'en ai parcouru quelques-uns, y compris Adobe, Microsoft, Java et GNU C/C++, et j'ai constaté qu'en général, compilation code (et même bâtiment, en supposant aucun fichier de création personnalisé) est relativement sûr, mais chacun de ces compilateurs a ou a eu des failles de sécurité qui pourraient résulter de l'exécution effective des binaires compilés. En d'autres termes, ils ne pouvaient pas prendre le contrôle de votre système simplement en compilant, mais ils pouvaient en exécutant du code.

Donc, en conclusion, en supposant que la méthode de livraison n'a pas déjà détourné votre système (par exemple, votre client de messagerie a été piraté, ou le lecteur USB sur lequel il est arrivé a été infecté ...), lire le code source et compiler le code source est probablement sûr. En recherchant votre logiciel spécifique, vous pouvez le rendre encore plus sûr en, par exemple, en validant le fichier dans la bonne page de code, etc. Pas une machine virtuelle, mais un ordinateur physiquement différent sans accès au réseau et sans fichiers sensibles ni périphériques externes. Même si vous pensez vous comprenez le code, de simples recherches montrent que même les compilateurs ont des bogues qui pourraient permettre à un exploit de dépassement de tampon caché de se faufiler par derrière et d'exécuter du code arbitraire, mais seulement si vous choisissez de exécuter ou déboguer le programme. La compilation réelle devrait être sûre.

3
phyrfox

Eh bien, je commencerais par "revoir leur code". Pourquoi est-il vraiment nécessaire d'exécuter le code?

En dehors de cela, il existe de nombreux compilateurs en ligne où vous pouvez simplement insérer le code et le compiler et/ou l'exécuter. Vous pouvez en faire une exigence: il compile dans tel ou tel compilateur en ligne.

Voici un exemple de page avec des compilateurs en ligne: compilateurs en ligne

Le code à réviser pour un entretien d'embauche ne devrait pas être si gros de toute façon que vous ne puissiez pas comprendre ce qui se passe.

2
Pieter B

Les compilateurs sont-ils généralement validés pour garantir qu'ils n'alimenteront pas la machine utilisateur lors de la compilation d'un morceau de code intelligent?

En général, ils sont trop complexes et souvent écrits dans des langages dans lesquels il n'est pas pratique de prouver cette propriété.

Peut-être pas avec cette intention spécifique, mais la notion de compilateurs de test fuzz est au moins connue ( LLVM peut maintenant se tester fuzz ). Les tests destinés à intercepter les entrées qui bloquent le compilateur en raison de bogues du compilateur auront tendance à révéler également des failles exploitables.

Naturellement, vous devez vérifier si le compilateur spécifique qui vous intéresse est testé ou testé pour trouver des plantages potentiels et si les bogues ainsi trouvés sont réellement corrigés. En règle générale, s'il y a des plantages pires que des exceptions de mémoire non détectées, alors sans approfondir les détails, vous devez envisager une possibilité sérieuse qu'ils pourraient être exploités en exploits.

Est-il sûr de compiler un morceau de code à partir d'un inconnu?

Malheureusement, combien de temps dure un morceau de ficelle. En principe l'e-mail peut exploiter votre client de messagerie, ou le code source peut exploiter votre éditeur de texte ou cppcheck, avant même d'atteindre votre compilateur. La suggestion de Sebastian dans les commentaires d'utiliser un compilateur en ligne est assez bonne, mais bien sûr, le code doit être sous une forme que le compilateur acceptera.

Tout langage ou compilateur disposant de fonctionnalités pour l'exécution au moment de la compilation du code général est bien sûr hautement suspect. Les modèles C++ sont fonctionnellement complets mais n'ont pas d'accès (prévu) au système, ils sont donc relativement à faible risque. BЈовић mentionne make comme extrêmement à haut risque (car il exécute le code de l'étranger, c'est juste que le code se trouve être écrit dans le langage make, pas en C++). Si le compilateur exécutera system alors vous êtes dans le même bateau. J'avais l'habitude de travailler avec un assembleur qui, si je me souviens bien, pouvait exécuter arbitrairement du code au moment de la compilation. Il était destiné au calcul des tables de recherche, mais je ne pense pas que quelque chose vous ait empêché de faire des appels système.

En pratique , si le code me semble OK et que je pense le comprendre, alors je considérerais qu'il y a un risque extrêmement faible de le compiler, bien plus bas risque que de dire "naviguer sur Internet avec un navigateur verrouillé". Je fais des choses plus risquées régulièrement sur ma machine polyvalente, mais je ne ferais pas beaucoup d'entre elles, par exemple dans un laboratoire antivirus ou sur un serveur critique. Si le code est drôle ou visiblement obscur, je ne risque pas de le compiler car, à part le risque qu'il puisse contenir un exploit caché dans les ordures illisibles, c'est du code de détritus. Le code sournois est difficile mais possible. Le code sournois qui commande la machine via un exploit de compilateur doit contenir une charge utile exécutable non triviale, donc est extrêmement difficile.

Si vous voulez approfondir cela, essayez de demander aux personnes qui hébergent des compilateurs en ligne. Si cela ne leur a pas été fait (à moins que vous ne veniez à l'attention du NSA ou équivalent), vous pouvez raisonnablement supposer que cela ne vous sera pas fait. exécuter leur compilateur dans un bac à sable approprié, ce qui pourrait représenter plus d'efforts que vous ne le souhaitez, mais ils pourraient au moins vous dire à quelle fréquence ce bac à sable leur évite des problèmes.

2
Steve Jessop

Lecture du code source: totalement sûr. Compilation du code source: totalement sûr. Exécuter des binaires compilés: eh bien ... cela dépend.

La compilation est juste l'ordinateur qui lit le code source et écrit son équivalent sous forme binaire. Après la compilation, vous n'avez que 2 documents: un lisible par l'homme et un autre lisible par ordinateur. À moins que vous ne demandiez à l'ordinateur de lire (c'est-à-dire d'exécuter) le 2e document, rien ne se passera.

0
gbjbaanb

Si la possibilité vous inquiète, prenez une machine plus ancienne (la plupart d'entre nous n'en avons pas?), Installez la version actuelle de Linux et du compilateur, copiez le code source, débranchez le câble réseau (ou désactivez le WiFi ) et effectuez les compilations. Si quelque chose de désagréable se produit, cela * n'affectera rien d'autre.

Et pour les logiciels malveillants dans le Makefile, exécutez-le avec l'indicateur -n (IIRC, RTMF) pour voir ce qu'il fera sans le faire.

* À moins bien sûr que votre programmeur ait codé le logiciel malveillant afin qu'il attende une reconnexion, mais dans ce cas, vous a) essuyez la machine; et b) transmettre le CV du gars à la NSA, car il est perdu dans le monde commercial :-)

0
jamesqf

L'essentiel est qu'il existe un risque . Le risque est assez faible comme le notent d'autres réponses, mais il y a un risque. Cela signifie que vous devez poser deux questions:

  1. Que puis-je faire pour atténuer le risque?
  2. Le risque est-il suffisamment élevé pour que je m'en soucie?

Le second est ce que vous avez posé ici dans cette question, mais ce n'est pas le bon objectif pour ce cas particulier. La réponse à l'atténuation du risque est claire et facilement disponible: ne compilez pas le code sur votre machine. Vous avez deux façons évidentes de le compiler sans utiliser votre machine:

  1. Utilisez une machine virtuelle (comme @FlorianMargaine l'a souligné immédiatement dans les commentaires). Il vous suffit de le prendre avant de le compiler, puis de le restaurer lorsque vous avez terminé.
  2. Utilisez un service hébergé (tel qu'un compilateur en ligne).

Ces moyens d'atténuer vos risques sont si évidents, bon marché et facilement accessibles qu'il ne vaut pas la peine de passer beaucoup de temps à essayer d'analyser l'ampleur du risque. Faites-en juste un et finissez-en.

0
jpmc26

Visual Studio vous avertit en fait si vous ouvrez un projet à partir d'un emplacement non approuvé (e, g, téléchargé ou partage réseau).

Un exemple de la façon dont cela pourrait être exploité serait avec un projet WPF: vous pouvez référencer des classes .NET à partir de XAML et fournir des charges IntelliSense, VS et exécuter les classes référencées au moment de la conception.

Cela signifie qu'un attaquant peut déposer un fichier .dll malveillant dans le répertoire bin, remplacer le code source par un fichier non malveillant, et au moment de la conception, le DLL est exécuté. Après votre première génération, chaque trace du binaire malveillant a disparu.

Ainsi, même si tout le code fourni est "propre", le compilateur est exempt de bogues et vous, bien sûr, n'exécutez jamais manuellement aucun .EXE fourni, le code malveillant pourrait toujours être exécuté en arrière-plan. (Pour être à l'abri de cette attaque spécifique, vous pouvez simplement vous assurer qu'il n'y a PAS de fichiers binaires dans l'arborescence de répertoires avant d'ouvrir la solution. VS vous invitera ensuite à créer la solution avant de fournir IntelliSense au moment du design.)

Des vecteurs similaires existent probablement avec d'autres langages/OS.

0
Lukas Rieger