Heu les fichiers de configuration de Vim sont turing complet...
Oui, désolé pour la confusion, c'est de ma faute. J'ai expliqué le modèle simplifié, alors qu'avec des applis dotés de fichiers de configuration problématiques, voire Turing-complets, le schéma sera différent. Milles excuses, je n'aurais pas dû prendre vim comme exemple.
Dans le cas de vim, on a deux groupes de fichiers spécifiques à un utilisateur : ceux relevant de l'historique des commandes (.viminfo), et ceux relevant de la configuration (.vimrc). Pour ceux de l'historique, ils seront bien en lecture-écriture par vim, sans autres formes de procès; du coup, un exploit jour zéro dedans permettrait une telle transmission de l'attaque. Heureusement, je ne crois pas qu'il existe de programmes dont les fichiers d'historiques soient Turing-complets - s'il en existait, il faudrait vraisemblablement les désactiver ou renoncer partiellement à la protection contre les exploits.
Par contre, les fichiers de configuration seront marqués lecture-seule-non-renommable-non-supprimable (côté implémentation, je pense que ce sera fait avec les attributs étendus), et l'application elle-même n'aura pas les privilèges requis pour retirer ou passer outre ce marquage. En revanche, le shell de l'utilisateur aura les privilèges requis pour les ignorer, et le lanceur de vim en fera usage pour marquer les fichiers à éditer de façon appropriée.
Voici une description du scénario, pour être plus clair :
Créateur des userdirs: tiens, on me demande de créer un userdir correspondant à l'uid 1017 pour le programme vim? Bon, c'est parti, je recopie l'userdir modèle et je le chown en 1017... Ah tiens, le fichier .vimrc du modèle est marqué lecture-seule-non-renommable-non-supprimable? Bon, je marque sa copie de la même façon.
Utilisateur: tiens, je vais éditer mon fichier de conf' vim, ça faisait longtemps. Alors, vim ~/userdirs/std/0.0.1/vim/7.3/vim/.vimrc ... (Oui, je sais, le chemin n'est pas pratique. On pourra sans doute proposer à l'utilisateur d'ajouter des liens matériels dans son $HOME pour lui simplifier le travail, à condition qu'il n'utilise qu'une seule version de vim ou de ses fichiers de conf'.)
Shell : "vim ~/userdirs/std/0.0.1/vim/7.3/vim/.vimrc", vous dites? OK, fork(), et execve() sur /usr/bin/vim.
Lanceur de vim : Je ne suis pas vim, mais son lanceur! Bon, au vu de la ligne de commande, je dois éditer le fichier ~/userdirs/std/0.0.1/vim/7.3/vim/.vimrc . Soit. J'appelle xchroot(), et je lui demande de créer une entrée dans mon répertoire /... correspondant au fichier .vimrc correspondant, et simultanément, de me changer de chroot au profit de celui du vrai vim. Ah, et je marque l'entrée de /... de ce fichier avec le flag BYPASS_READONLY_NOREMOVE.
Noyau : D'accord pour le flag BYPASS_READONLY_NOREMOVE, tu as les privilèges requis, mais xchroot() implique chdir(), donc ton nouveau chemin courant devient la racine du chroot de vim.
Lanceur de vim : C'était prévu! Maintenant, capset(ABANDONNE, BYPASS_READONLY_NOREMOVE);
Noyau : Pas de problème, j'ai l'esprit large, j'autorise n'importe qui à diminuer ses privilèges.
Lanceur de vim : et maintenant, execve() sur /usr/bin/vim !
Vim : Ah, tiens, je dois éditer le fichier /.../home/username/userdirs/std/0.0.1/vim/7.3/vim/.vimrc . Bon, open() dessus...
Noyau : Ah, il est marqué lecture-seule-non-renommable-non-supprimable dans le système de fichiers, mais BYPASS_READONLY_NOREMOVE dans ton entrée /... . Bon, d'accord, tu peux l'éditer, je ferme les yeux.
Utilisateur : Ben voilà, ça marche très bien!
Maintenant, le scénario d'attaque :
Utilisateur : Tiens, je vais éditer /.../home/username/ultra_piégé_dans_tous_les_sens.txt .
Shell : Bon, ben, j'obéis, mais là, je ne réponds de rien, hein... fork(), et execve() sur /usr/bin/vim.
Lanceur de vim : Je ne suis pas vim, mais son lanceur! Bon, au vu de la ligne de commande, je dois éditer le fichier /.../home/username/ultra_piégé_dans_tous_les_sens.txt . Ben dis donc, y'en a vraiment qui ne manquent pas d'air, ici! Mais soit. J'appelle xchroot(), et je lui demande de créer une entrée dans mon répertoire /... correspondant au fichier ultra_piégé_dans_tous_les_sens.txt, et simultanément, de me changer de chroot au profit de celui du vrai vim. Ah, et je marque l'entrée de /... de ce fichier avec le flag BYPASS_READONLY_NOREMOVE.
Noyau : D'accord pour le flag BYPASS_READONLY_NOREMOVE, tu as les privilèges requis, mais xchroot() implique chdir(), donc ton nouveau chemin courant devient la racine du chroot de vim.
Lanceur de vim : C'était prévu! Maintenant, capset(ABANDONNE, BYPASS_READONLY_NOREMOVE);
Noyau : Pas de problème, j'ai toujours l'esprit large, j'autorise n'importe qui à diminuer ses privilèges.
Lanceur de vim : et maintenant, execve() sur /usr/bin/vim !
Vim : Ah, tiens, je dois éditer le fichier /.../home/username/ultra_piégé_dans_tous_les_sens.txt . Bon, open() dessus...
Noyau : Ah, il ne comporte pas de marquage particulier dans le système de fichiers, donc, c'est bon, vas-y. (Oui, l'entrée est marquée BYPASS_READONLY_NOREMOVE dans /... , mais je m'en moque, ça ne change rien.)
Vim : Je l'ouvre, et.... Aaaaaaaaaaaaargh, un Balrog!
Balrog : Hahahahaha! Maintenant, j'ai le contrôle de vim! Tremblez, mortels! Tout d'abord, modifions son fichier de configuration...
Noyau : Bien essayé, mais il est marqué lecture-seule-non-renommable-non-supprimable, et tu viens de te débarrasser des privilèges requis pour l'ignorer.
Balrog : Koa?! Eh bien, rends-moi mes privilèges!
Noyau : j'ai l'esprit large, mais pas à ce point. Va voir dans la Moria si j'y suis, permission denied.
Balrog : Que?! Alors, retire ce marquage!
Noyau : De nos jours, les démons ne doutent plus de rien. Cause toujours, permission denied.
Balrog : Heu... Et... Il me reste quoi, comme droits, au juste?
Noyau : Bon, il n'y a pas d'appel-système pour te fournir d'un coup une telle analyse, mais je vais te répondre quand même. Tu as le droit d'éditer le fichier dont tu es issu, ainsi que l'historique des commandes de cet utilisateur. Tu as aussi le droit d'exécuter vim, de réduire la taille de ton chroot ainsi que tes privilèges, et d'appeler exit(2).
Balrog [fait une dépression nerveuse]
Bon, en pratique, l'attaquant pourrais tenter sa chance en recopiant le code d'exploit dans le fichier d'historique au niveau du tampon de copier-coller de vim, à condition que son exploit soit compatible avec le passage par ce tampon, et que soit la seule lecture de l'exploit dans le fichier d'historique suffise à l'exploiter, soit qu'il parvienne à amener l'utilisateur à le coller quelque part. C'est vrai, et donc certaines classes rares d'exploits pourront théoriquement progresser, très lentement, à travers le système (à moins que l'utilisateur, ou sa distribution, ne désactive le fichier d'historique).
Mais ce ne sera pas discret (trace claire dans le système de fichiers), ce sera lent (ce qui est catastrophique pour un exploit jour zéro, qui repose justement sur la vitesse d'action), et seul un très faible sous-ensemble des exploits précédents pourront tenter des choses de ce genre.
Mais c'est vrai, dans l'absolu, tu as raison, pour les applications dotées de fichiers spécifiques à un utilisateur modifiables par l'application elle-même sans ordre explicite, la sécurité ne sera pas absolument parfaite. D'ailleurs, un exploit noyau aussi, ça suffirait à passer. Mais elle sera renforcée, et très significativement; et pour la plupart des applications, elle sera complète hors bogue noyau.
[^] # Re: Intéressant
Posté par Emmanuel Colbus . En réponse au journal Annonce : Manux 0.0.1. Évalué à 9.
Oui, désolé pour la confusion, c'est de ma faute. J'ai expliqué le modèle simplifié, alors qu'avec des applis dotés de fichiers de configuration problématiques, voire Turing-complets, le schéma sera différent. Milles excuses, je n'aurais pas dû prendre vim comme exemple.
Dans le cas de vim, on a deux groupes de fichiers spécifiques à un utilisateur : ceux relevant de l'historique des commandes (.viminfo), et ceux relevant de la configuration (.vimrc). Pour ceux de l'historique, ils seront bien en lecture-écriture par vim, sans autres formes de procès; du coup, un exploit jour zéro dedans permettrait une telle transmission de l'attaque. Heureusement, je ne crois pas qu'il existe de programmes dont les fichiers d'historiques soient Turing-complets - s'il en existait, il faudrait vraisemblablement les désactiver ou renoncer partiellement à la protection contre les exploits.
Par contre, les fichiers de configuration seront marqués lecture-seule-non-renommable-non-supprimable (côté implémentation, je pense que ce sera fait avec les attributs étendus), et l'application elle-même n'aura pas les privilèges requis pour retirer ou passer outre ce marquage. En revanche, le shell de l'utilisateur aura les privilèges requis pour les ignorer, et le lanceur de vim en fera usage pour marquer les fichiers à éditer de façon appropriée.
Voici une description du scénario, pour être plus clair :
Créateur des userdirs: tiens, on me demande de créer un userdir correspondant à l'uid 1017 pour le programme vim? Bon, c'est parti, je recopie l'userdir modèle et je le chown en 1017... Ah tiens, le fichier .vimrc du modèle est marqué lecture-seule-non-renommable-non-supprimable? Bon, je marque sa copie de la même façon.
Utilisateur: tiens, je vais éditer mon fichier de conf' vim, ça faisait longtemps. Alors, vim ~/userdirs/std/0.0.1/vim/7.3/vim/.vimrc ... (Oui, je sais, le chemin n'est pas pratique. On pourra sans doute proposer à l'utilisateur d'ajouter des liens matériels dans son $HOME pour lui simplifier le travail, à condition qu'il n'utilise qu'une seule version de vim ou de ses fichiers de conf'.)
Shell : "vim ~/userdirs/std/0.0.1/vim/7.3/vim/.vimrc", vous dites? OK, fork(), et execve() sur /usr/bin/vim.
Lanceur de vim : Je ne suis pas vim, mais son lanceur! Bon, au vu de la ligne de commande, je dois éditer le fichier ~/userdirs/std/0.0.1/vim/7.3/vim/.vimrc . Soit. J'appelle xchroot(), et je lui demande de créer une entrée dans mon répertoire /... correspondant au fichier .vimrc correspondant, et simultanément, de me changer de chroot au profit de celui du vrai vim. Ah, et je marque l'entrée de /... de ce fichier avec le flag BYPASS_READONLY_NOREMOVE.
Noyau : D'accord pour le flag BYPASS_READONLY_NOREMOVE, tu as les privilèges requis, mais xchroot() implique chdir(), donc ton nouveau chemin courant devient la racine du chroot de vim.
Lanceur de vim : C'était prévu! Maintenant, capset(ABANDONNE, BYPASS_READONLY_NOREMOVE);
Noyau : Pas de problème, j'ai l'esprit large, j'autorise n'importe qui à diminuer ses privilèges.
Lanceur de vim : et maintenant, execve() sur /usr/bin/vim !
Vim : Ah, tiens, je dois éditer le fichier /.../home/username/userdirs/std/0.0.1/vim/7.3/vim/.vimrc . Bon, open() dessus...
Noyau : Ah, il est marqué lecture-seule-non-renommable-non-supprimable dans le système de fichiers, mais BYPASS_READONLY_NOREMOVE dans ton entrée /... . Bon, d'accord, tu peux l'éditer, je ferme les yeux.
Utilisateur : Ben voilà, ça marche très bien!
Maintenant, le scénario d'attaque :
Utilisateur : Tiens, je vais éditer /.../home/username/ultra_piégé_dans_tous_les_sens.txt .
Shell : Bon, ben, j'obéis, mais là, je ne réponds de rien, hein... fork(), et execve() sur /usr/bin/vim.
Lanceur de vim : Je ne suis pas vim, mais son lanceur! Bon, au vu de la ligne de commande, je dois éditer le fichier /.../home/username/ultra_piégé_dans_tous_les_sens.txt . Ben dis donc, y'en a vraiment qui ne manquent pas d'air, ici! Mais soit. J'appelle xchroot(), et je lui demande de créer une entrée dans mon répertoire /... correspondant au fichier ultra_piégé_dans_tous_les_sens.txt, et simultanément, de me changer de chroot au profit de celui du vrai vim. Ah, et je marque l'entrée de /... de ce fichier avec le flag BYPASS_READONLY_NOREMOVE.
Noyau : D'accord pour le flag BYPASS_READONLY_NOREMOVE, tu as les privilèges requis, mais xchroot() implique chdir(), donc ton nouveau chemin courant devient la racine du chroot de vim.
Lanceur de vim : C'était prévu! Maintenant, capset(ABANDONNE, BYPASS_READONLY_NOREMOVE);
Noyau : Pas de problème, j'ai toujours l'esprit large, j'autorise n'importe qui à diminuer ses privilèges.
Lanceur de vim : et maintenant, execve() sur /usr/bin/vim !
Vim : Ah, tiens, je dois éditer le fichier /.../home/username/ultra_piégé_dans_tous_les_sens.txt . Bon, open() dessus...
Noyau : Ah, il ne comporte pas de marquage particulier dans le système de fichiers, donc, c'est bon, vas-y. (Oui, l'entrée est marquée BYPASS_READONLY_NOREMOVE dans /... , mais je m'en moque, ça ne change rien.)
Vim : Je l'ouvre, et.... Aaaaaaaaaaaaargh, un Balrog!
Balrog : Hahahahaha! Maintenant, j'ai le contrôle de vim! Tremblez, mortels! Tout d'abord, modifions son fichier de configuration...
Noyau : Bien essayé, mais il est marqué lecture-seule-non-renommable-non-supprimable, et tu viens de te débarrasser des privilèges requis pour l'ignorer.
Balrog : Koa?! Eh bien, rends-moi mes privilèges!
Noyau : j'ai l'esprit large, mais pas à ce point. Va voir dans la Moria si j'y suis, permission denied.
Balrog : Que?! Alors, retire ce marquage!
Noyau : De nos jours, les démons ne doutent plus de rien. Cause toujours, permission denied.
Balrog : Heu... Et... Il me reste quoi, comme droits, au juste?
Noyau : Bon, il n'y a pas d'appel-système pour te fournir d'un coup une telle analyse, mais je vais te répondre quand même. Tu as le droit d'éditer le fichier dont tu es issu, ainsi que l'historique des commandes de cet utilisateur. Tu as aussi le droit d'exécuter vim, de réduire la taille de ton chroot ainsi que tes privilèges, et d'appeler exit(2).
Balrog [fait une dépression nerveuse]
Bon, en pratique, l'attaquant pourrais tenter sa chance en recopiant le code d'exploit dans le fichier d'historique au niveau du tampon de copier-coller de vim, à condition que son exploit soit compatible avec le passage par ce tampon, et que soit la seule lecture de l'exploit dans le fichier d'historique suffise à l'exploiter, soit qu'il parvienne à amener l'utilisateur à le coller quelque part. C'est vrai, et donc certaines classes rares d'exploits pourront théoriquement progresser, très lentement, à travers le système (à moins que l'utilisateur, ou sa distribution, ne désactive le fichier d'historique).
Mais ce ne sera pas discret (trace claire dans le système de fichiers), ce sera lent (ce qui est catastrophique pour un exploit jour zéro, qui repose justement sur la vitesse d'action), et seul un très faible sous-ensemble des exploits précédents pourront tenter des choses de ce genre.
Mais c'est vrai, dans l'absolu, tu as raison, pour les applications dotées de fichiers spécifiques à un utilisateur modifiables par l'application elle-même sans ordre explicite, la sécurité ne sera pas absolument parfaite. D'ailleurs, un exploit noyau aussi, ça suffirait à passer. Mais elle sera renforcée, et très significativement; et pour la plupart des applications, elle sera complète hors bogue noyau.