web-dev-qa-db-fra.com

Est-il dangereux de compiler du C arbitraire?

J'ai un petit serveur et je voudrais vérifier les temps de compilation sur les programmes C fournis par les utilisateurs. Les programmes ne seraient jamais exécutés uniquement compilés.

Quels risques y a-t-il à permettre aux utilisateurs de compiler du C arbitraire à l'aide de gcc 5.4.0?

69

Un peu bizarre, mais: c'est un risque de déni de service, ou une divulgation potentielle d'informations.

Parce que le préprocesseur de C inclura joyeusement tout fichier spécifié dans un #include directive, quelqu'un peut #include "../../../../../../../../../../dev/zero" et le préprocesseur essaiera de lire jusqu'à la fin de /dev/zero (bonne chance).

De même, surtout si vous laissez les gens voir le résultat de leurs tentatives de compilation, quelqu'un pourrait essayer d'inclure divers fichiers qui peuvent ou non être présents sur votre système, et pourrait apprendre des choses sur votre machine. Combiné avec une utilisation intelligente de #pragma poison , ils pourraient même apprendre des choses sur le contenu du fichier même si vous ne fournissez pas de messages d'erreur complets.

De même, les pragmas peuvent modifier de nombreux comportements du préprocesseur, du compilateur ou de l'éditeur de liens et sont spécifiés dans les fichiers source. Il n'y a probablement pas un qui permette à quelqu'un de faire quelque chose comme spécifier le nom du fichier de sortie ou quelque chose comme ça, mais s'il y en a un, il pourrait être utilisé abusivement pour remplacer sensible fichiers, ou se faire exécuter (en écrivant dans cron ou similaire). Il pourrait y avoir quelque chose de tout aussi dangereux. Vous devez vraiment faire attention à la compilation de code non fiable.

94
CBHacking

Bombe du compilateur

C est un langage très puissant, et certaines des choses terribles que vous pouvez en faire vous choqueraient. Par exemple, vous pouvez créer un programme C de 16 octets qui prend 27 minutes à compiler , et quand il se termine enfin, il se compile dans un fichier exécutable de 16 gigaoctets . Et cela n'utilise que 16 octets. Lorsque vous tenez compte du préprocesseur et des fichiers de code source plus volumineux, je suis sûr que vous pourriez créer des bombes de compilation beaucoup plus volumineuses.

Cela signifie que toute personne ayant accès à votre serveur pourrait efficacement lancer une attaque DoS sur votre serveur. Maintenant, pour être honnête, c'est beaucoup moins dangereux que d'avoir quelqu'un qui abuse d'une vulnérabilité dans le compilateur, ou d'inclure des fichiers sensibles pour obtenir des informations sur votre serveur (comme les autres répondeurs en ont parlé).

Mais c'est encore une autre gêne possible que vous rencontrerez lors de la compilation de code arbitraire. Je suis sûr que vous pouvez configurer une limite de temps sur toutes les versions et assurez-vous de ne jamais stocker les fichiers binaires. Bien sûr, vous devez toujours le conserver sur le disque pendant sa création , donc si quelqu'un a hypothétiquement fait une bombe de compilation plus grande que votre disque dur, vous serais en difficulté (si vous laissez la construction se terminer).

41
James

@ AndréBorie est correct. Les compilateurs et la configuration correspondante ne seront pas bien vérifiés pour les problèmes de sécurité, donc en règle générale, vous ne devez pas compiler du code non approuvé.

Le risque est qu'un débordement de tampon ou un certain type de vulnérabilité d'exécution de bibliothèque soit exploité, et l'attaquant accède au compte d'utilisateur (espérons-le non -root!) Qui a exécuté le compilateur. Même un hack nonroot est sérieux dans la plupart des cas. Cela pourrait être développé dans une question distincte.

La création d'un VM est une bonne solution, pour contenir tous les exploits potentiels afin qu'ils ne puissent pas nuire au reste de votre application.

Il est préférable d'avoir un modèle Linux VM vous pouvez lancer au besoin avec un environnement de compilateur de table rase.

Idéalement, vous le jeteriez après chaque utilisation, mais cela peut ne pas être strictement nécessaire. Si vous isolez le VM assez bien et désinfectez correctement les données de réponse de la VM, ce que vous devriez faire de toute façon; alors le pire qu'un piratage pourrait faire est DoS ou créer de faux temps de compilation. Ce sont pas de problèmes graves en soi, du moins pas aussi graves que l'accès au reste de votre application.

Cependant, la réinitialisation de VM après chaque utilisation (c'est-à-dire au lieu de tous les jours) fournit un environnement plus stable dans l'ensemble et peut améliorer la sécurité dans certains cas Edge.

Certains systèmes d'exploitation fournissent des conteneurs comme alternative aux machines virtuelles. Cela peut être une approche plus simple, mais les mêmes principes s'appliquent.

28
Bryan Field

Oui, c'est dangereux: mais comme les gens l'ont dit, c'est possible. Je suis l'auteur et le mainteneur des compilateurs en ligne à https://gcc.godbolt.org/ , et je l'ai trouvé assez pratique pour le rendre sûr en utilisant une combinaison de:

  • L'ensemble du site fonctionne sur une instance VM avec peu d'autorisations pour faire quoi que ce soit. Le réseau est sévèrement limité avec seulement le port 80 visible, et ssh activé uniquement à partir des adresses IP sur liste blanche (la mienne).
  • Chaque instance de compilation s'exécute dans un conteneur Docker jetable avec encore moins d'autorisations
  • Le compilateur est exécuté à partir d'un script qui définit toutes les limites du processus (mémoire, temps CPU, etc.) à des limites basses pour éviter les bombes de code.
  • Le compilateur est exécuté avec un LD_PRELOAD wrapper ( source here ) qui empêche le compilateur d'ouvrir des fichiers ne figurant pas sur une liste blanche explicite. Cela l'empêche de lire/etc/passwd ou d'autres trucs du genre (pas que ça aiderait beaucoup).
  • Par gentillesse, j'analyse les options de ligne de commande et n'exécute pas le compilateur s'il y a quelque chose de particulièrement suspect. Ce n'est pas une vraie protection; juste un moyen de donner un message d'erreur "sérieusement, n'essayez pas ceci" au lieu du LD_PRELOAD attraper un mauvais comportement.

La source entière est sur GitHub , tout comme la source des images de conteneur docker et des compilateurs et autres.

J'ai écrit un article de blog expliquant comment l'ensemble de l'installation est également exécuté.

14
Matt G

Vous ne voudriez pas exécuter le compilateur en tant que root, bien que j'aie vu cela se produire pour des raisons de "facilité et de commodité". Il serait trop facile pour un attaquant d'inclure quelque chose comme:

#include "../../../../etc/passwd"
#include "../../../../etc/shadow"

et récupérer le contenu de ces fichiers dans le cadre du message d'erreur du compilateur.

Les compilateurs sont également des programmes comme tout le reste, et auront leurs bogues qui pourraient être vulnérables, il serait facile pour quelqu'un de simplement flouer les programmes C et de causer des problèmes.

La sécurité de la plupart des applications se concentrera d'abord et avant tout sur la validation des entrées, malheureusement la définition d'une entrée `` sûre et valide '' pour un compilateur C est probablement là-haut avec le problème d'arrêt en termes de difficulté :)

12
Colin Cassidy

Si vous autorisez un utilisateur à fournir une archive contenant le code, vous pouvez avoir des problèmes, pas exactement avec le compilateur mais l'éditeur de liens qu'il utilise;)

ld suit les liens symboliques s'ils pointent vers un fichier qui n'existe pas. Cela signifie que si vous compilez test.c vers la sortie a.out mais que vous avez déjà un lien symbolique nommé a.out dans votre répertoire pointant vers un fichier inexistant, l'exécutable compilé sera écrit à l'emplacement pointant vers la fichier (avec la limitation des droits d'utilisateur).

En pratique, un attaquant pourrait, par exemple, inclure une chaîne contenant une clé publique ssh dans son code et fournir un lien symbolique nommé a.out à ~/.ssh/authorized_keys . Si ce fichier n'existe pas déjà, cela permet à l'attaquant de planter sa clé ssh dans la machine cible lui permettant un accès externe sans avoir à craquer aucun mot de passe.

3
cym13