
Une primitive d'exploitation dans le noyau Linux inspirée de DirtyPipe
Une primitive d'exploitation dans le noyau Linux inspirée par DirtyPipe (CVE-2022-0847).
Il y a quelques jours, comme beaucoup de mes aînés en sécurité, j'ai étudié et reproduit la vulnérabilité DirtyPipe (CVE-2022-0847), et j'ai profondément ressenti à quel point cette faille est pratique. Elle commence par un problème de mémoire non initialisée et aboutit à la modification de fichiers arbitraires, sans passer par un leak de KASLR ni par des opérations ROP, JOP, etc. Il n'est donc pas nécessaire de contourner SMEP, SMAP et autres protections.
Après l'avoir reproduite, j'ai commencé à réfléchir : pourquoi DirtyPipe est-elle si pratique ? Est-ce que, avec sa correction, elle ne serait qu'une étoile filante, sans aucune valeur pédagogique pour l'exploitation future de vulnérabilités ?
Soudain, je me suis rendu compte que la structure concernée par DirtyPipe — struct pipe_buffer — m'était très familière. Ah ! N'est-ce pas cette structure allouée avec le flag GFP_KERNEL_ACCOUNT, située dans slab-1k, et contenant un champ ops que j'utilise souvent pour faire du leak de KASLR et du détournement de RIP ?
Aussitôt, je me suis senti idiot : pourquoi avais-je modifié ops de pipe_buffer pour faire du ROP ? Modifier directement les flags de pipe_buffer et l'associer à splice ne permettait-il pas déjà d'écrire dans des fichiers arbitraires ? Ainsi, pas besoin de leak KASLR, pas besoin d'adapter l'exploit aux différentes versions du noyau, pas besoin de se soucier des gadgets, ni de contourner SMEP, SMAP, KPTI et autres protections.
J'ai immédiatement sorti les exploits que j'avais utilisés précédemment pour reproduire CVE-2021-22555 et d'autres impliquant la structure pipe_buffer ; après quelques petites modifications, ils fonctionnaient aussitôt sur différentes versions de noyaux non patchées. Voici quelques exemples :
Comme je n'avais vu personne utiliser cela comme une primitive dans les exploits du noyau Linux auparavant, je me suis permis de l'appeler « Pipe Primitive » XD.
En résumé, il faut obtenir la capacité de modifier la structure Pipe, par exemple via une UAF dans slab-1k, ou une écriture hors limites avec offset dans slab-1k (c'est-à-dire pas un débordement direct et séquentiel).
Ainsi, sous kernel >= 5.8, il suffit de modifier flag |= PIPE_BUF_FLAG_CAN_MERGE sur la page splice de pipe_buffer (si on en est capable, on peut aussi mettre offset et len à 0 pour pouvoir écrire depuis le début du fichier) ; sous kernel < 5.8, il faut d'abord leak anon_pipe_ops dans pipe_buffer, puis remplacer ops de la page splice par anon_pipe_ops (car dans les versions < 5.8, la possibilité de fusionner dépend de ops) (là encore, si on en est capable, on peut mettre offset et len à 0).
Quant à savoir comment faire une évasion de conteneur avec cela ? Ce que je voudrais faire devrait ressembler pas mal à CVE-2019-5736 XD.