
VFS per Git ab95cf51 - Medio - Locale - Privilegio residuo - la named pipe del servizio si fida dell'OwnerSID nel JSON
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vfs-service-sid
Classe: Privilegio residuo Portata: Locale
VFS for Git master ab95cf51 (tag v2.0.26259.1) - Microsoft
GVFS.Service viene eseguito come LocalSystem. WindowsPlatform.CreatePipeByName concede a BUILTIN\Users ReadWrite | CreateNewInstance su GVFS.Service.pipe. RegisterRepoHandler.Run memorizza il JSON OwnerSID così com'è. Nulla invoca ImpersonateNamedPipeClient.
Qualsiasi principal di Users può registrare un percorso dell'attaccante sotto un SID della vittima. Al SessionLogon il servizio esegue CreateProcessAsUser di gvfs mount <attacker path> come la vittima. Il processo figlio non è NT AUTHORITY\SYSTEM.
| ID | nessuna CVE al momento |
| Classe | Privilegio residuo (autorizzazione mancante / esecuzione cross-utente) |
| Portata | Locale |
| CWE | CWE-862, CWE-284 |
| CVSS | Medio: 6.6 CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N |
| Prodotto | VFS for Git |
| Affetto | master ab95cf51d6ffd0ee0e2feae7180078fe9ecbbb3a; tag GitHub v2.0.26229.1 / v2.0.26259.1. Solo Windows. |
| Auth | Locale. Qualsiasi principal BUILTIN\Users. Logon della vittima per l'automount. |
| Licenza | GNU Affero GPL v3.0 |
| Lab | Solo 127.0.0.1. how=gadget (nessun GVFS.Service Windows reale). |
Git 2.35+ dubious-ownership può poi far fallire git all'interno di un albero di proprietà dell'attaccante. Il processo parte comunque come la vittima. Se il percorso è di proprietà della vittima ma scrivibile dall'attaccante (vfs-clone-acl), mount git, credential.helper e hook vengono eseguiti come quell'utente.
Qualsiasi principal BUILTIN\Users su una macchina dove il servizio è installato. Connettersi a \\.\pipe\GVFS.Service.pipe. Nessun privilegio aggiuntivo.
| Privilegio | Metodo / sink | Cosa concede | Recon / integrità / disponibilità | Provato in lab o dedotto |
|---|---|---|---|---|
| Elencare ogni root di enlistment attivo | GetActiveRepoListRequest senza controllo del SID (TryGetActiveRepos, non GetActiveReposForUser) | Percorsi usati come oracolo del nome della pipe per il residuo #2 | Recon | Provato in lab. Il gadget ha elencato /lab/repos/victim |
| Disattivare un enlistment della vittima in modo che non venga automontato | UnregisterRepoRequest {EnlistmentRoot} senza controllo del SID (TryDeactivateRepo) | I repo della vittima restano smontati | Disponibilità | Provato in lab. Riga della vittima rimossa dalla lista attiva |
| Persistere il percorso dell'attaccante sotto il SID della vittima | RegisterRepoRequest JSON EnlistmentRoot + OwnerSID; TryRegisterRepo memorizza entrambi | Riga di registro percorso-attaccante + SID vittima | Integrità | Provato in lab. Riga di registro /lab/repos/attacker + S-1-5-21-1000-2000-3000-1001 |
Avviare GVFS.exe mount <attacker path> come la vittima al logon | OnSessionChange SessionLogon -> AutoMountRepos(userId) -> TryRunAs / CreateProcessAsUser | Creazione di processo cross-utente come l'utente che effettua il logon | Integrità | Provato in lab sul gadget. Parent generato GVFS.Service, argv mount /lab/repos/attacker, uid 1002 victim, witness scritto |
| Eseguire come NT AUTHORITY\SYSTEM | Stesso automount | Figlio LocalSystem | Integrità | Chiuso. Il figlio whoami è la vittima, non SYSTEM (child-not-system=yes) |
Git / hook / credential.helper come la vittima all'interno di un albero di proprietà dell'attaccante | La creazione del processo avviene comunque; git 2.35+ safe.directory può fallire | RCE tramite hook come la vittima se l'albero è di proprietà della vittima ma scrivibile dall'attaccante | Integrità | Dedotto. Il lab non ha eseguito Microsoft git. Associare il percorso come di proprietà della vittima ma scrivibile dall'attaccante per l'RCE tramite hook |
Chiuso su questo pin: accesso remoto non autenticato (la named pipe è locale). Shell SYSTEM. L'ACL predefinita della pipe consente comunque l'accesso a Users; un register corretto che associa il SID del client (gadget X-Patched: 1) non automonta il percorso dell'attaccante per la vittima.
Altri residui dello stesso pin: vfs-quote-breakout, vfs-mount-dehydrate, vfs-clone-acl, vfs-hook-impersonate, vfs-install-cwd.
Ho fissato VFSForGit master ab95cf51 dopo il merge del 2026-09-28. L'ACL della pipe del servizio è Users ReadWrite. Register memorizza il JSON OwnerSID. SessionLogon automonta come quel SID. Nulla impersona il client della pipe.
Vicoli ciechi già registrati: chiamare questa cosa una shell SYSTEM (l'automount è CreateProcessAsUser del token di logon); trattare git safe.directory come autorizzazione dell'IPC; una reverse shell. Teatro. Windows nativo era assente, quindi il lab è un gadget degli handler del pin più un oracolo TCP Unix.
python3 vfs-service-sid-Abraxas-Labs.py
oppure
cd lab
./run.sh
Gadget HTTP su 127.0.0.1:19660. Witness VFS-SERVICE-SID-WITNESS. L'ultima riga usa how=gadget.
SUCCESS vfs-service-sid how=gadget register-forged-sid=yes automount-as-victim=yes child-not-system=yes VFS-SERVICE-SID-WITNESS
Impersonare il client della named pipe (ImpersonateNamedPipeClient / NamedPipeServerStream.RunAsClient). Ignorare il JSON OwnerSID; associare TryRegisterRepo al SID del client. Limitare CreatePipeByName all'utente interattivo e a LocalSystem (rimuovere BuiltinUsersSid ReadWrite / CreateNewInstance). GetActiveRepoList dovrebbe restituire solo i repo di quel client. UnregisterRepo dovrebbe richiedere la stessa corrispondenza di SID.