
VFS pour Git ab95cf51 - Élevé - Local - Résidu de privilège - Les utilisateurs montent le pipe dehydrate/unmount
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vfs-mount-dehydrate
Classe : Privilège résiduel Portée : Locale
VFS for Git master ab95cf51 (tag v2.0.26259.1) - Microsoft
CreatePipeByName sur le pipe de montage par enlistment accorde à BUILTIN\Users ReadWrite | CreateNewInstance. Il n'y a aucune vérification du SID du propriétaire et aucun ImpersonateNamedPipeClient. HandleDehydrateFolders Path.Combine les noms de dossiers contrôlés par l'attaquant et les transmet à git via ProcessStartInfo.Arguments. Le chemin dehydrate de la CLI exécute IsFolderValid. Le gestionnaire de montage ne le fait pas.
Toute personne dans Users qui peut deviner \\.\pipe\GVFS_<ENLISTMENT> peut démonter ProjFS, déplacer des répertoires en tant qu'utilisateur du montage et forcer git reset HEAD --hard.
| ID | pas encore de CVE |
| Classe | Privilège résiduel (ACL de named-pipe) / traversée de chemin / injection d'arguments |
| Portée | Locale |
| CWE | CWE-284, CWE-22, CWE-88 |
| CVSS | Élevé : 7.8 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Produit | VFS for Git |
| Affecté | master ab95cf51d6ffd0ee0e2feae7180078fe9ecbbb3a ; tags de l'installeur v2.0.26229.1 / v2.0.26259.1. Windows uniquement. |
| Auth | Locale. Tout principal BUILTIN\Users tant que la victime a un montage |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement. how=gadget (pas de VM Windows / ProjFS réel). |
Protocole du pipe : UTF-8 Header ou Header|body, terminé par l'octet 0x03. Le nom du pipe est GVFS_ + la racine d'enlistment en majuscules avec : remplacé par _ (exemple C:\Repos\Foo -> \\.\pipe\GVFS_C_\REPOS\FOO).
La victime a gvfs mount sur une racine connue. L'attaquant est un autre principal Users sur la même machine. Intégrité et disponibilité en tant que la victime. Pas SYSTEM. Pas un shell à lui seul.
| Privilège | Méthode / sink | Ce que cela accorde | Recon / intégrité / disponibilité | Prouvé en lab ou déduit |
|---|---|---|---|---|
| Se connecter au pipe de montage de la victime | ACL CreatePipeByName BuiltinUsers ReadWrite | CreateNewInstance ; aucune vérification du propriétaire | Parler l'IPC de montage | Recon du pipe | Prouvé en lab (ACL du gadget). SID de l'attaquant accepté ; le mode propriétaire uniquement renvoie connect-denied |
| Lire le chemin d'enlistment, le chemin de cache, RepoUrl | GetStatus | Fuiter la racine utilisée pour le résidu #1 / #4 | Recon | Prouvé en lab. Le JSON de statut incluait RepoUrl et GVFS_C_\REPOS\FOO |
Démonter ProjFS et quitter gvfs.mount | message Unmount | Faire tomber l'enlistment | Disponibilité | Prouvé en lab. Répond Ack puis Complete ; état du montage Unmounted |
| Démonter sur un échec de parsing | ReleaseLock avec corps vide -> RequestData == null -> UnmountAndStopWorkingDirectoryCallbacks + Environment.Exit | Même démontage plus sortie du processus | Disponibilité | Prouvé en lab. ReleaseLock| vide a démonté |
| Détruire l'arbre de travail de la victime | Dehydrate|{"Folders":"--hard",...}. movedFolders.Add même si le dossier source est absent. Reset("HEAD", "\"--hard\" ") devient git reset HEAD --hard après suppression des guillemets | Détruire les fichiers suivis modifiés | Intégrité / disponibilité | Prouvé en lab. Un fichier suivi modifié a perdu la chaîne témoin |
| Déplacer un dossier hors de l'arbre de travail en tant que la victime | Path.Combine(WorkingDirectoryBackingRoot, folder) + MoveDirectory vers BackupFolderPath | Voler / déplacer un dossier de l'arbre de travail | Intégrité | Prouvé en lab. keepme a quitté src et est apparu sous le chemin de sauvegarde de l'attaquant |
Traverser .. (le IsFolderValid de la CLI n'est pas utilisé) | même Combine ; ..\secret | Déplacer un dossier frère que l'utilisateur du montage peut écrire | Intégrité | Prouvé en lab. Le frère secret a atterri sous le chemin de sauvegarde de l'attaquant. L'application de IsFolderValid l'a bloqué |
| Voler ou détruire d'autres répertoires inscriptibles par la victime | même déplacement avec une chaîne ..\ qui se résout hors de l'enlistment | Déplacement plus large en tant qu'utilisateur du montage | Intégrité | Déduit de Combine. Ce lab n'utilise qu'un arbre jetable |
| Exécution de code en tant que la victime | ce pipe | Création de processus d'une image attaquante | Intégrité | Fermé. Aucune création de processus d'image attaquante sur ce résidu (voir vfs-service-sid et vfs-hook-impersonate) |
| SYSTEM | IPC de montage | LocalSystem | Intégrité | Fermé. Le montage s'exécute en tant qu'utilisateur de l'enlistment |
--hard n'est pas un chemin ... Le IsFolderValid de la CLI l'autorise quand même. Un correctif doit aussi rejeter les noms de dossiers ressemblant à des options.
Mêmes résidus sur ce pin : vfs-quote-breakout, vfs-clone-acl, vfs-service-sid, vfs-hook-impersonate, vfs-install-cwd.
J'ai épinglé VFSForGit master ab95cf51 après le merge du 2026-09-28. Le pipe du service et le pipe de montage par enlistment partagent CreatePipeByName. Dehydrate sur la CLI valide les dossiers. Le gestionnaire de montage ne le fait pas.
Fausses pistes déjà consignées : traiter --hard comme une traversée de chemin (c'est une injection d'arguments après suppression des guillemets) ; revendiquer SYSTEM ; un reverse shell. Du théâtre. Windows natif était absent, donc le lab est un gadget de ces fonctions plus un arbre git jetable.
python3 vfs-mount-dehydrate-Abraxas-Labs.py
ou
cd lab
./run.sh
Gadget HTTP sur 127.0.0.1:19640 parlant la forme des messages du pipe. Arbre git jetable à l'intérieur du conteneur. Pas de reverse shell. Pas de vrai chemin de profil. La dernière ligne utilise how=gadget.
SUCCESS vfs-mount-dehydrate how=gadget unmount=yes reset-hard=yes dirty-gone=yes move-inside=yes move-dotdot=yes pipe-acl=users-no-owner is-folder-valid-not-on-pipe=yes VFS-MOUNT-DEHYDRATE-WITNESS