
VFS for Git ab95cf51 - Hoch - Lokal - Verbleibendes Privileg - Benutzer mounten pipe dehydrate/unmount
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vfs-mount-dehydrate
Klasse: Privilegien-Überrest Reichweite: Lokal
VFS for Git master ab95cf51 (Tag v2.0.26259.1) - Microsoft
CreatePipeByName auf der pro-Enlistment-Mount-Pipe gewährt BUILTIN\Users ReadWrite | CreateNewInstance. Es gibt keine Owner-SID-Prüfung und kein ImpersonateNamedPipeClient. HandleDehydrateFolders Path.Combinet Angreifer-Ordnernamen und speist git über ProcessStartInfo.Arguments. Der CLI-Dehydrate-Pfad führt IsFolderValid aus. Der Mount-Handler nicht.
Jeder in Users, der \\.\pipe\GVFS_<ENLISTMENT> erraten kann, kann ProjFS unmounten, Verzeichnisse als der Mount-Benutzer verschieben und git reset HEAD --hard erzwingen.
| ID | noch kein CVE |
| Klasse | Privilegien-Überrest (Named-Pipe-ACL) / Path Traversal / Argument Injection |
| Reichweite | Lokal |
| CWE | CWE-284, CWE-22, CWE-88 |
| CVSS | Hoch: 7.8 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Produkt | VFS for Git |
| Betroffen | master ab95cf51d6ffd0ee0e2feae7180078fe9ecbbb3a; Installer-Tags v2.0.26229.1 / v2.0.26259.1. Nur Windows. |
| Auth | Lokal. Jedes BUILTIN\Users-Principal, während das Opfer einen Mount hat |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | Nur 127.0.0.1. how=gadget (keine Windows-VM / kein Live-ProjFS). |
Pipe-Protokoll: UTF-8 Header oder Header|body, terminiert durch Byte 0x03. Pipe-Name ist GVFS_ + großgeschriebener Enlistment-Root mit : ersetzt durch _ (Beispiel C:\Repos\Foo -> \\.\pipe\GVFS_C_\REPOS\FOO).
Opfer hat gvfs mount an einem bekannten Root. Angreifer ist ein anderes Users-Principal auf derselben Maschine. Integrität und Verfügbarkeit als das Opfer. Nicht SYSTEM. Keine Shell für sich allein.
| Privileg | Methode / Sink | Was es gewährt | Recon / Integrität / Verfügbarkeit | Lab-bewiesen oder abgeleitet |
|---|---|---|---|---|
| Verbindung zur Opfer-Mount-Pipe | CreatePipeByName ACL BuiltinUsers ReadWrite | CreateNewInstance; keine Owner-Prüfung | Mount-IPC ansprechen | Recon der Pipe | Lab-bewiesen (Gadget-ACL). Angreifer-SID akzeptiert; Owner-only-Modus liefert Connect-Denied |
| Enlistment-Pfad, Cache-Pfad, RepoUrl lesen | GetStatus | Den Root leaken, der für Überrest #1 / #4 verwendet wird | Recon | Lab-bewiesen. Status-JSON enthielt RepoUrl und GVFS_C_\REPOS\FOO |
ProjFS unmounten und gvfs.mount beenden | Nachricht Unmount | Das Enlistment lahmlegen | Verfügbarkeit | Lab-bewiesen. Antwortet Ack dann Complete; Mount-Status Unmounted |
| Unmount bei einem Parse-Fehler | ReleaseLock mit leerem Body -> RequestData == null -> UnmountAndStopWorkingDirectoryCallbacks + Environment.Exit | Derselbe Unmount plus Prozess-Exit | Verfügbarkeit | Lab-bewiesen. Leeres ReleaseLock| unmountete |
| Den Arbeitsbaum des Opfers verwerfen | Dehydrate|{"Folders":"--hard",...}. movedFolders.Add selbst wenn das Quellverzeichnis fehlt. Reset("HEAD", "\"--hard\" ") wird nach Quote-Strip zu git reset HEAD --hard | Dirty getrackte Dateien zerstören | Integrität / Verfügbarkeit | Lab-bewiesen. Dirty getrackte Datei verlor den Witness-String |
| Einen Ordner als das Opfer aus dem Worktree verschieben | Path.Combine(WorkingDirectoryBackingRoot, folder) + MoveDirectory nach BackupFolderPath | Einen Worktree-Ordner stehlen / verschieben | Integrität | Lab-bewiesen. keepme verließ src und erschien unter dem Angreifer-Backup-Pfad |
.. traversieren (CLI IsFolderValid wird nicht verwendet) | dasselbe Combine; ..\secret | Ein Geschwister verschieben, das der Mount-Benutzer schreiben kann | Integrität | Lab-bewiesen. Geschwister secret landete unter dem Angreifer-Backup-Pfad. Anwenden von IsFolderValid blockierte es |
| Andere vom Opfer beschreibbare Verzeichnisse stehlen oder zerstören | dasselbe Move mit einer ..\-Kette, die außerhalb des Enlistments auflöst | Breiteres Move als der Mount-Benutzer | Integrität | Abgeleitet aus Combine. Dieses Lab verwendet nur einen Wegwerf-Baum |
| Code-Ausführung als das Opfer | diese Pipe | Prozess-Erstellung eines Angreifer-Images | Integrität | Geschlossen. Keine Prozess-Erstellung eines Angreifer-Images bei diesem Überrest (siehe vfs-service-sid und vfs-hook-impersonate) |
| SYSTEM | Mount-IPC | LocalSystem | Integrität | Geschlossen. Mount läuft als der Enlistment-Benutzer |
--hard ist kein ..-Pfad. CLI IsFolderValid erlaubt es trotzdem. Ein Fix muss auch optionsähnliche Ordnernamen ablehnen.
Gleiche Pin-Überreste: vfs-quote-breakout, vfs-clone-acl, vfs-service-sid, vfs-hook-impersonate, vfs-install-cwd.
Ich pinnte VFSForGit master ab95cf51 nach dem Merge vom 2026-09-28. Die Service-Pipe und die Pro-Enlistment-Mount-Pipe teilen CreatePipeByName. Dehydrate auf der CLI validiert Ordner. Der Mount-Handler nicht.
Bereits festgehaltene Irrwege: --hard als Path Traversal behandeln (es ist Argument Injection nach Quote-Strip); SYSTEM behaupten; eine Reverse Shell. Theater. Natives Windows fehlte, also ist das Lab ein Gadget dieser Funktionen plus ein Wegwerf-git-Baum.
python3 vfs-mount-dehydrate-Abraxas-Labs.py
oder
cd lab
./run.sh
Gadget-HTTP auf 127.0.0.1:19640, das die Pipe-Nachrichtenform spricht. Wegwerf-git-Baum im Container. Keine Reverse Shell. Kein echter Profilpfad. Letzte Zeile verwendet 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
CreatePipeByName auf die Enlistment-Owner-SID plus LocalSystem beschränken. CreateNewInstance für Users entfernen. Den Client impersonieren und Owner verlangen. IsFolderValid in HandleDehydrateFolders replizieren und Namen ablehnen, die wie git-Optionen aussehen. ReleaseLock-Parse-Fehler nicht als Prozess-Exit behandeln.