Question:
Est-il dangereux de compiler du C arbitraire?
Sriotchilism O'Zaic
2016-10-06 07:01:41 UTC
view on stackexchange narkive permalink

J'ai un petit serveur et j'aimerais 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 en utilisant gcc 5.4.0?

Je dirais que ce n'est pas la meilleure idée.Les vulnérabilités du compilateur ne sont pas si courantes en raison du fait que la plupart des gens compilent du code de confiance qui ne déclenche pas de telles vulnérabilités.Je suis sûr qu'il reste un certain nombre de ces vulnérabilités à exploiter.Si vous devez absolument le faire, je suggère de compiler le code dans des machines virtuelles jetables.
Il existe plusieurs services Web offrant exactement cela.Par exemple.sur Stack Overflow, ideone.com est populaire, tout comme godbolt.org.Le danger semble gérable.
@MSalters: Il y a aussi coliru.stacked-crooked.com, et je pense que Stacked Crooked a décrit comment il a sécurisé son compilateur en ligne en profondeur.
N'y avait-il pas des entrées entières de l'IOCCC construites autour de cela?Certes, si vous compilez un C ++ arbitraire, les gens peuvent gaspiller * beaucoup * de votre CPU à partir d'un petit programme.Je pense que l'entrée gagnante dans un concours de "messages d'erreur explosifs" a généré 55 Mo d'erreurs à partir de 1 Ko d'entrée.
Pas le temps d'écrire ceci pour le moment, mais vérifiez ceci: https://www.ece.cmu.edu/~ganger/712.fall02/papers/p761-thompson.pdf
C'est un risque gérable avec la technologie Linux actuelle.Déployez la source dans un conteneur docker, exécutez le compilateur conteneurisé et s'il ne se termine pas ou dépasse le quota de sortie, supprimez simplement le conteneur, enregistrez l'échec et demandez à fail2ban de détecter les utilisateurs à problèmes répétés.
Beaucoup de gens déconseillent cela, mais il existe un certain nombre de sites en ligne gratuits qui * font * compiler du code arbitraire, comme ideone comme démontré dans un commentaire.Cela vous fait vous demander comment ils se sécurisent.
@jpmc26 - "vous fait vous demander comment ils se sécurisent" Voir le commentaire ci-dessus de Matthieu M. à propos de `coliru.stacked-crooked.com`.
Six réponses:
CBHacking
2016-10-06 08:54:39 UTC
view on stackexchange narkive permalink

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

Comme le préprocesseur de C inclura joyeusement tout fichier spécifié dans une directive #include , 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 la sortie 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é à 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 beaucoup de comportement du préprocesseur, du compilateur ou de l'éditeur de liens, et sont spécifiés dans les fichiers source. Il n'y en a probablement pas un qui permet à 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 abusé pour remplacer des fichiers sensibles, 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 à ne pas compiler du code non fiable.

http://ideone.com/c2UhRl
@Ville-ValtteriTiittanen Ajoutez quelques explications, pas seulement des liens.
@TorKlingberg L'explication est dans la question.Il vient de fournir une mise en œuvre fonctionnelle du deuxième paragraphe ideea
Dans quelle mesure ces attaques sont-elles atténuées grâce à l'utilisation d'un environnement chroot correctement configuré?Il n'est pas nécessaire d'avoir `cron` ou un` / etc / passwd` significatif (ailleurs), ce qui réduit considérablement la surface d'attaque.(Il est assez facile de nos jours de créer un chroot minimal avec `cdebootstrap` et` schroot` - c'est ainsi que je crée des environnements de compilation pour les anciennes distributions que je dois prendre en charge.)
J'ai oublié de dire, utilisez également `ulimit` pour lutter contre une certaine quantité de DoS.
@CBHacking.+1.Pouvez-vous expliquer comment #pragma poison peut être utilisé pour en savoir plus sur le contenu des fichiers?
Le chroot @TobySpeight: fonctionne bien contre ce type d'attaque.Par exemple, tenter de compiler le fichier @Ville's sur [Coliru] (http://coliru.stacked-crooked.com/) donne simplement une erreur de: `main.cpp: 1: 50: erreur fatale: ../../../../../../../../../../dev/zero: aucun fichier ou répertoire de ce type »(et similaire pour le fichier qu'il lie dans le commentaire à la réponse de Colin Cassidy).
AilidnychrCMT Yikes.
@PriyankGupta: En théorie, l'empoisonnement de certains jetons qui pourraient être dans un fichier, puis l'inclusion du fichier, échouera rapidement si ces jetons sont présents.Cela peut fournir une attaque de canal secondaire (timing) pour révéler des informations sur le contenu d'un fichier même si vous (l'attaquant) n'obtenez pas la sortie réelle du compilateur.Le fichier devrait toujours être valide C, ou au moins proche de celui-ci, ou l'analyseur échouerait avant que la vérification du poison ne soit appliquée.Vous choisiriez également les noms de fichiers à l'aveugle.Pas une attaque facile, mais peut-être significative dans certaines circonstances.
@Ville-ValtteriTiittanen Essayez-vous de démontrer que cela * est * un problème ou * n'est pas * un problème?Ne semble pas avoir causé de tort à l'idéone.
De nombreux utilitaires Linux lisent les fichiers par `open` /` fstat` / `mmap`, donc la lecture de fichiers de zéro octet ou de" fichiers "sans longueur ne fonctionnerait pas.Ils ne peuvent pas non plus lire les faux "fichiers normaux" «/ proc».J'ai été battu par cela quand certains programmes ont insisté pour avoir un "fichier régulier" normal `/ etc / fstab` et non un lien / montage de` / proc / mount`.
James
2016-10-06 19:10:05 UTC
view on stackexchange narkive permalink

Compilateurs bombes

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 de 16 octets C qui prend 27 minutes à compiler , et quand il se termine finalement, il se compile en un 16 gigaoctets fichier exécutable. Et cela n'utilise que 16 octets. Lorsque vous prenez en compte le préprocesseur et les fichiers de code source plus volumineux, je suis sûr que vous pourriez créer des bombes de compilateur beaucoup plus volumineuses.

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

Mais c'est encore une autre ennui possible que vous rencontrerez lors de la compilation de code arbitraire. Je suis sûr que vous pouvez définir une limite de temps pour toutes les versions et vous assurer 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 fabriqué une bombe de compilateur plus grande que votre disque dur, vous auriez des problèmes (si vous laissez la compilation terminer).

Curieusement, la raison pour laquelle je pose la question est que je voulais lancer un défi PPCG pour créer une bombe de compilateur, et que je voulais mettre en place un serveur de notation.
Bryan Field
2016-10-06 08:01:24 UTC
view on stackexchange narkive permalink

@ AndréBorie a raison. Les compilateurs et la configuration correspondante ne seront pas bien contrôlés pour les problèmes de sécurité, donc de manière générale, vous ne devriez pas compiler de code non fiable.

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 le l'attaquant accède au compte utilisateur (espérons-le non root !) qui a exécuté le compilateur. Même un piratage non root est sérieux dans la plupart des cas. Cela pourrait être développé dans une question distincte.

Créer une VM est une bonne solution, pour contenir tous les exploits potentiels afin qu'ils ne puissent pas nuire au reste de votre application.

C'est mieux pour avoir un modèle de VM Linux, vous pouvez le lancer selon vos besoins avec un environnement de compilateur clean slate.

Idéalement, vous le jetteriez après chaque utilisation, mais cela peut ne pas être strictement nécessaire. Si vous isolez suffisamment bien la machine virtuelle et nettoyez correctement les données de réponse de la machine virtuelle, ce que vous devriez faire de toute façon; alors le pire qu'un hack puisse faire est DoS ou créer de faux temps de compilation. Ce ne sont pas des problèmes graves en soi; au moins pas aussi grave que d'accéder au reste de votre application.

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

Certains systèmes d'exploitation proposent des conteneurs comme alternative aux VM. C'est peut-être une approche plus légère, mais les mêmes principes s'appliquent.

Instantanés du système de fichiers (par exemple ZFS) + un conteneur (donc pas de temps de démarrage du noyau) et vous pourriez probablement nettoyer entre les requêtes dans les 5 secondes.Et si vous voulez plusieurs conteneurs, vous pouvez même utiliser des clones CoW.
Ça sonne bien.Je suppose que vous voulez dire une réinitialisation réelle (ne nécessitant pas de démarrage du noyau), afin que les démons malveillants soient détruits.
La plupart des solutions de conteneurisation implémentent une opération «d'arrêt» qui tuera tous les processus démarrés dans le conteneur.Je crois que LXD (`stop --force`) fait cela en les mettant tous dans un groupe de contrôle.Mais comme la création d'un clone CoW à partir d'un instantané dans ZFS est bon marché, vous pouvez même créer un tout nouveau conteneur avant que l'ancien ne se termine.La plupart du temps serait probablement passé à démarrer init à l'intérieur du conteneur.
Assurez-vous d'exécuter les VM sur un serveur distinct pour ne pas provoquer d'attaques de synchronisation et d'autres attaques de canal secondaire sur votre serveur Web!
Matt G
2016-10-07 19:13:49 UTC
view on stackexchange narkive permalink

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 sur 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 de VM avec peu d'autorisations pour faire quoi que ce soit. Le réseau est sévèrement limité avec seul le port 80 visible et ssh activé uniquement à partir des adresses IP de la liste blanche (la mienne).
  • Chaque instance de compilation s'exécute dans un conteneur Docker jetable avec encore moins d'autorisation
  • Le compilateur est exécuté à partir d'un script qui définit toutes les limites de 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 ici) 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 de ce genre (pas que cela aiderait tant que ça).
  • En fin de compte, j'analyse les options de ligne de commande et n'exécute pas le compilateur si 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 ça" au lieu de LD_PRELOAD attraper un mauvais comportement.

Toute la source est sur GitHub, tout comme la source des images de conteneur de docker et des compilateurs et autres.

J'ai écrit un article de blog expliquant comment le toute la configuration est également exécutée.

La technique `LD_PRELOAD` est presque inutile.Il est absolument simple de contourner une fois que vous avez obtenu l'exécution de code via une vulnérabilité de compilateur.Cela pourrait aider pour des problèmes d'adjoint confus, mais pas grand-chose d'autre ... De plus, même si cela fonctionnait, vous avez manqué beaucoup de fonctions qui peuvent être utilisées pour ouvrir des fichiers à la place.
Colin Cassidy
2016-10-06 13:20:24 UTC
view on stackexchange narkive permalink

Vous ne voudriez pas exécuter le compilateur en tant que root, même si j'ai 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 aura leurs bogues qui pourraient être vulnérables, il serait trop facile pour quelqu'un de simplement brouiller les programmes C et causer des problèmes.

La plupart des applications de sécurité se concentreront d'abord et avant tout sur la validation des entrées, malheureusement, définir 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é :)

http://ideone.com/ZzPHMw http://ideone.com/xc4s5a
mon point exactement, il y en a d'autres qui sont sensibles au etc / shadow one
Mais les messages d'erreur seront envoyés à * votre * terminal, et vous pouvez simplement _cat / etc / passwd_ de toute façon.
oui je veux que les messages d'erreur me reviennent, je cherche à obtenir les hachages de mot de passe.En ce qui concerne cat / etc / passwd, cela dépend de la configuration, peut-être que le code C est soumis à un serveur séparé, auquel cas maintenant j'ai les hachages pour le système distant que je peux commencer à craquer hors ligne.
cym13
2016-10-07 04:13:46 UTC
view on stackexchange narkive permalink

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

ld suit des 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 le 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 / allowed_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 un mot de passe.



Ce Q&R a été automatiquement traduit de la langue anglaise.Le contenu original est disponible sur stackexchange, que nous remercions pour la licence cc by-sa 3.0 sous laquelle il est distribué.
Loading...