윈도우에 어떤 프로그램을 설치했다가 지운 적이 있다면, 레지스트리에는 그 흔적이 남는다. 대개는 문제가 되지 않는다. 그런데 그 흔적이 시스템 권한으로 동작하는 서비스가 신뢰하는 COM 컴포넌트의 등록 정보라면 이야기가 달라진다. 구글 프로젝트 제로의 제임스 포쇼(James Forshaw)를 포함한 15명이 함께 신고한 는, 존재하지도 않는 DLL을 가리키는 "죽은" 등록 하나가 어떻게 관리자 권한 없이 SYSTEM 권한으로 이어지는지를 보여준다.
Why — COM 등록이 두 조각으로 나뉘는 이유
COM(Component Object Model)은 윈도우 안에서 서로 다른 프로그램이 언어에 상관없이 재사용 가능한 객체를 주고받기 위해 오래전부터 써온 표준이다. 어떤 프로그램이 CLSID(클래스를 식별하는 고유 번호)로 객체 생성을 요청하면, 운영체제는 그 번호에 해당하는 실행 파일을 찾아 실행하고 객체를 돌려준다.
이 구조가 작동하려면 두 조각이 모두 있어야 한다. 하나는 실제 코드가 담긴 서버 실행 파일(대개 DLL), 다른 하나는 HKEY_CLASSES_ROOT 레지스트리에 있는 CLSID 항목으로, 그 번호를 어떤 DLL에 연결할지 알려주는 지도 역할을 한다. 등록과 실행 파일을 분리해둔 덕분에 프로그램은 설치·삭제·업데이트가 자유로워졌다. 문제는 이 지도가 실제 파일과 동기화된다는 보장이 없다는 점이다. 실행 파일이 사라져도 지도는 남을 수 있다.
What — 죽은 COM 등록이란
이번 사건의 주인공은 CrossDevice라는 컴포넌트다. CLSID {E9F83CF2-E0C0-4CA7-AF01-E90C70BEF496}는 %ProgramData%\CrossDevice\CrossDevice.Streaming.Source.dll을 가리키도록 등록돼 있었는데, 실제로 이 경로에 파일이 없었다. 등록은 살아 있고 실행 파일만 죽은 상태, 이것이 "dangling registration"이다.
여기서 두 번째 사실이 결정적이다. %ProgramData%는 시스템 폴더처럼 보이지만, 기본 권한 구성상 일반 사용자도 하위 폴더를 만들고 파일을 쓸 수 있다. 즉 공격자는 이 죽은 등록이 가리키는 경로에 자기 DLL을 미리 가져다 놓을 수 있다. 이후 어떤 방식으로든 SYSTEM 권한 프로세스가 이 CLSID로 객체 생성을 시도하면, 시스템은 지도(레지스트리)를 그대로 믿고 공격자의 DLL을 SYSTEM 프로세스 안에서 로드한다.
How — 실제 작동 방식
1) 원본 취약점: Dark Elevator (CVE-2026-50343)
이 결함을 처음 찾아낸 것은 연구자 Calif였다. InstallService라는 SYSTEM 권한 서비스가 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\InstallService\State 아래 PlugInList·StaticPluginMap 값을 관리하는데, 이 레지스트리 키의 접근 권한(ACL)이 지나치게 느슨해 일반 사용자도 쓸 수 있었다. InstallService는 이 값에 적힌 CLSID를 그대로 신뢰해 CoCreateInstance로 로드한다.
공격 절차는 세 단계로 끝난다. 사용자 권한으로 StaticPluginMap에 CrossDevice의 CLSID를 추가하고, %ProgramData%\CrossDevice\에 악성 DLL을 심은 뒤, InstallService가 플러그인을 활성화하도록 트리거하면 SYSTEM 셸을 얻는다. 커널 메모리 손상이 전혀 없는 논리적 결함 체인이라 매번 결정론적으로 성공하고, 관리자 권한도 UAC도 재부팅도 필요 없다.
2) 패치의 절반짜리 수정
마이크로소프트는 2026년 7월 패치에서 InstallService 레지스트리 키의 ACL만 강화했다. 일반 사용자가 StaticPluginMap을 더 이상 쓸 수 없게 됐으니 이 경로로는 더는 공격이 통하지 않는다. 하지만 이 패치는 "CrossDevice CLSID가 존재하지 않는 DLL을 가리킨다"는 근본 원인은 건드리지 않았다. 죽은 등록은 패치 이후에도 그대로 레지스트리에 남아 있었다.
3) 우회: 커스텀 마샬링으로 다른 문을 두드리다
포쇼 등은 여기서 "죽은 CLSID가 여전히 존재한다"는 사실 자체를 새로운 공격면으로 봤다. InstallService를 거치지 않고도, COM의 커스텀 마샬링(custom marshaling) 기능을 이용해 이 CLSID를 다른 SYSTEM 서비스에 떠넘길 수 있다는 것이다.
COM 객체를 프로세스 사이로 전달할 때 쓰는 IMarshal 인터페이스는, 전달자가 임의의 CLSID를 지정한 커스텀 OBJREF(마샬된 객체 참조)를 만들 수 있게 허용한다. 이 OBJREF를 SYSTEM 권한 COM 서비스에 건네면, 그 서비스는 객체를 "역마샬(unmarshal)"하는 과정에서 지정된 CLSID의 DLL을 자동으로 로드한다. 이번에 쓰인 진입점은 일반 사용자도 트리거할 수 있는 예약 작업 \Microsoft\Windows\Shell\CreateObjectTask였다. 이 작업이 실행하는 "Shell Create Object Handler" COM 서비스(CLSID 135fd325-45b7-4c30-89f8-4386961669f0)는 SYSTEM 권한으로 동작하면서 커스텀 마샬링에 별다른 제한을 두지 않았다.
결과적으로 InstallService라는 문 하나를 잠갔더니, 같은 열쇠(dangling CLSID)로 열리는 다른 문(Shell Create Object Handler)이 여전히 남아 있었던 셈이다. 포쇼는 이런 죽은 등록을 미리 찾아내는 감사 로직도 함께 공개했다. 개념적으로는 레지스트리에 등록된 in-process COM 클래스를 모두 나열한 뒤, 그중 실제로 LoadLibrary가 실패하는(=DLL이 없는) 항목만 걸러내는 방식이다. 이는 방어자를 위한 사전 점검 스크립트일 뿐, 그 자체로 권한 상승을 수행하는 코드는 아니다. 이 밖에도 윈도우 카메라 프레임 서버 경로를 트리거로 쓰는 변형 PoC가 별도 연구자들 사이에서 공개돼 있으나, 이는 프로젝트 제로 원문이 직접 설명한 경로는 아니다.
Security — 왜 위험하고, 어떻게 잡아낼 것인가
이 취약점 계열이 특히 위험한 이유는 세 가지다. 커널 메모리 손상이 없어 크래시 위험 없이 매번 같은 결과를 내고, 관리자 권한이나 UAC 동의, 재부팅도 필요 없으며, 표준 사용자 계정만으로 시작할 수 있다. 다수 직원이 표준 사용자 권한으로 업무 PC를 쓰는 조직이라면, 초기 침투 이후 이런 결함이 SYSTEM 권한 상승의 발판이 될 수 있다.
COM 하이재킹 자체는 새로운 기법이 아니다. MITRE ATT&CK에는 이미 T1546.015(Component Object Model Hijacking)로 등재돼 있고, 보안 업체 Neodyme는 "The Key to COMpromise" 연구에서 다수의 백신·EDR 제품이 COM 인터페이스를 통해 SYSTEM 권한으로 상승당할 수 있음을 보여준 바 있다. 다만 기존 사례는 대개 정상적으로 존재하는 등록을 덮어쓰는 방식이었다. 이번 건은 마이크로소프트 자신이 남긴 레거시 dangling 등록을 그대로 재활용했고, 여기에 커스텀 마샬링이라는 우회 경로를 결합했다는 점에서 같은 기법군 안에서도 새로운 조합이다.
탐지 관점에서는 Sysmon 이벤트 ID 13(레지스트리 값 설정)으로 HKLM\SOFTWARE\Classes\CLSID\*\InprocServer32, LocalServer32, TreatAs 값의 생성·수정을 모니터링하는 것이 기본이다. 이는 MITRE의 데이터 컴포넌트 DC0063(레지스트리 키 수정)에 대응한다. 다만 이번 취약점 계열은 새로 값을 쓰는 게 아니라 "이미 등록돼 있지만 실행 파일이 없는" 상태를 노리기 때문에, 일반적인 파일 생성 탐지 규칙만으로는 잡히지 않는다. 포쇼가 공개한 감사 스크립트처럼, 등록된 CLSID 중 LoadLibrary가 실패하는 항목을 주기적으로 감사해 사전에 없애는 예방적 접근이 더 실효적이다. 개발자 쪽에서는 신뢰할 수 없는 마샬된 객체를 받지 않도록 CoInitializeSecurity에 EOAC_NO_CUSTOM_MARSHAL 플래그를 쓰거나, IGlobalOptions로 COMGLB_UNMARSHALING_POLICY_STRONG 정책을 적용하는 방법이 있다. 다만 이는 개별 COM 서비스 구현체가 직접 옵트인해야 하는 코드 수준 방어라, 운영체제 전역에 자동으로 적용되지는 않는다. 국내 기업 환경도 대부분 표준 사용자 권한 정책을 쓰는 윈도우 10·11 기반이라, 이런 유형의 결함은 초기 침투 후 내부 권한 상승 시나리오에서 특히 적용 가능성이 높다.
Summary
죽은 COM 등록은 삭제된 소프트웨어의 사소한 흔적이 아니라, SYSTEM 권한으로 가는 잠긴 문의 열쇠가 될 수 있다. 2026년 7월 패치는 그 열쇠로 열 수 있는 문 하나(InstallService)만 잠갔을 뿐, 열쇠 자체(dangling CLSID)는 그대로 뒀다. 방어의 핵심은 특정 진입점을 막는 데서 그치지 않고, 레지스트리에 남은 죽은 등록 자체를 찾아 없애는 데 있다.