
VFS for Git ab95cf51 - 중간 - 로컬 - 권한 잔여 - 서비스 파이프가 JSON OwnerSID를 신뢰함
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vfs-service-sid
분류: 권한 잔여 도달 범위: 로컬
VFS for Git master ab95cf51 (태그 v2.0.26259.1) - Microsoft
GVFS.Service는 LocalSystem으로 실행된다. WindowsPlatform.CreatePipeByName은 GVFS.Service.pipe에 대해 BUILTIN\Users에게 ReadWrite | CreateNewInstance를 부여한다. RegisterRepoHandler.Run은 JSON OwnerSID를 그대로 저장한다. ImpersonateNamedPipeClient를 호출하는 곳은 없다.
모든 Users 주체가 피해자 SID 아래에 공격자 경로를 등록할 수 있다. SessionLogon 시 서비스는 gvfs mount <attacker path>를 피해자로서 CreateProcessAsUser한다. 자식 프로세스는 NT AUTHORITY\SYSTEM이 아니다.
| ID | 아직 CVE 없음 |
| 분류 | 권한 잔여 (인가 누락 / 교차 사용자 실행) |
| 도달 범위 | 로컬 |
| CWE | CWE-862, CWE-284 |
| CVSS | Medium: 6.6 CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N |
| 제품 | VFS for Git |
| 영향 받음 | master ab95cf51d6ffd0ee0e2feae7180078fe9ecbbb3a; GitHub 태그 v2.0.26229.1 / v2.0.26259.1. Windows 전용. |
| 인증 | 로컬. 모든 BUILTIN\Users 주체. 자동 마운트를 위한 피해자 로그온. |
| 라이선스 | GNU Affero GPL v3.0 |
| 랩 | 127.0.0.1 전용. how=gadget (실제 Windows GVFS.Service 없음). |
Git 2.35+의 dubious-ownership은 이후 공격자 소유 트리 내에서 git을 실패시킬 수 있다. 프로세스는 여전히 피해자로서 시작된다. 경로가 피해자 소유이지만 공격자가 쓰기 가능한 경우(vfs-clone-acl), mount git, credential.helper, 훅이 해당 사용자로서 실행된다.
서비스가 설치된 머신의 모든 BUILTIN\Users 주체. \\.\pipe\GVFS.Service.pipe에 연결. 추가 권한 없음.
| 권한 | 메서드 / 싱크 | 부여하는 것 | 정찰 / 무결성 / 가용성 | 랩 입증 또는 추론 |
|---|---|---|---|---|
| 모든 활성 enlistment 루트 나열 | SID 검사 없는 GetActiveRepoListRequest (GetActiveReposForUser가 아닌 TryGetActiveRepos) | 잔여 #2의 파이프 이름 오라클로 사용되는 경로 | 정찰 | 랩 입증. Gadget이 /lab/repos/victim을 나열함 |
| 피해자 enlistment를 비활성화하여 자동 마운트되지 않게 함 | SID 검사 없는 UnregisterRepoRequest {EnlistmentRoot} (TryDeactivateRepo) | 피해자 저장소가 마운트되지 않은 채로 유지됨 | 가용성 | 랩 입증. 활성 목록에서 피해자 행이 사라짐 |
| 피해자 SID 아래에 공격자 경로 지속 | RegisterRepoRequest JSON EnlistmentRoot + OwnerSID; TryRegisterRepo가 둘 다 저장 | 레지스트리 행 공격자 경로 + 피해자 SID | 무결성 | 랩 입증. 레지스트리 행 /lab/repos/attacker + S-1-5-21-1000-2000-3000-1001 |
로그온 시 피해자로서 GVFS.exe mount <attacker path> 시작 | OnSessionChange SessionLogon -> AutoMountRepos(userId) -> TryRunAs / CreateProcessAsUser | 로그온 사용자로서의 교차 사용자 프로세스 생성 | 무결성 | Gadget에서 랩 입증. 부모 GVFS.Service 스폰, argv mount /lab/repos/attacker, uid 1002 victim, witness 기록됨 |
| NT AUTHORITY\SYSTEM으로 실행 | 동일한 자동 마운트 | LocalSystem 자식 | 무결성 | 종료됨. 자식 whoami는 SYSTEM이 아닌 피해자임 (child-not-system=yes) |
공격자 소유 트리 내에서 피해자로서 Git / 훅 / credential.helper | 프로세스 생성은 여전히 발생; git 2.35+ safe.directory가 실패할 수 있음 | 트리가 피해자 소유이지만 공격자가 쓰기 가능한 경우 피해자로서의 훅 RCE | 무결성 | 추론됨. 랩에서 Microsoft git을 실행하지 않음. 훅 RCE를 위해 경로를 피해자 소유이지만 공격자가 쓰기 가능하게 바인딩 |
이 핀에서 종료됨: 원격 비인증 접근 (named pipe는 로컬). SYSTEM 셸. 기본 파이프 ACL은 여전히 Users를 허용; 클라이언트 SID를 바인딩하는 패치된 register (gadget X-Patched: 1)는 피해자에 대해 공격자 경로를 자동 마운트하지 않음.
동일 핀 잔여: vfs-quote-breakout, vfs-mount-dehydrate, vfs-clone-acl, vfs-hook-impersonate, vfs-install-cwd.
2026-09-28 머지 이후 VFSForGit master ab95cf51을 핀했다. 서비스 파이프 ACL은 Users ReadWrite. Register는 JSON OwnerSID를 저장. SessionLogon은 해당 SID로서 자동 마운트. 파이프 클라이언트를 임퍼소네이트하는 곳은 없음.
이미 기록된 잘못된 방향: 이것을 SYSTEM 셸이라고 부르는 것 (자동 마운트는 로그온 토큰의 CreateProcessAsUser); git safe.directory를 IPC의 인가로 취급하는 것; 리버스 셸. 연극. 네이티브 Windows가 없었으므로, 랩은 핀 핸들러의 gadget과 Unix TCP 오라클이다.
python3 vfs-service-sid-Abraxas-Labs.py
또는
cd lab
./run.sh
Gadget HTTP는 127.0.0.1:19660. Witness VFS-SERVICE-SID-WITNESS. 마지막 줄은 how=gadget을 사용.
SUCCESS vfs-service-sid how=gadget register-forged-sid=yes automount-as-victim=yes child-not-system=yes VFS-SERVICE-SID-WITNESS
named-pipe 클라이언트를 임퍼소네이트 (ImpersonateNamedPipeClient / NamedPipeServerStream.RunAsClient). JSON OwnerSID를 무시; TryRegisterRepo를 클라이언트 SID에 바인딩. CreatePipeByName을 대화형 사용자와 LocalSystem으로 제한 (BuiltinUsersSid ReadWrite / CreateNewInstance 제거). GetActiveRepoList는 해당 클라이언트의 저장소만 반환해야 함. UnregisterRepo는 동일한 SID 일치를 요구해야 함.
ab95cf51d6ffd0ee0e2feae7180078fe9ecbbb3aWindowsPlatform.cs Users ACL 및 {serviceName}.pipeRegisterRepoHandler.csNamedPipeMessages.cs 클라이언트 제공 SID 필드RepoRegistry.cs 지속 및 AutoMountReposGVFSMountProcess.cs TryRunAs(..., "mount", repoRoot, ...)GNU Affero GPL v3.0. LICENSE 참조. 루프백 랩 전용. 보증 없음.