2021년 11월에 발견된 CVE-2022-21999 취약점은 윈도우의 프린트 스풀러 권한 상승 취약점입니다. 프린트 스풀러는 인쇄 작업을 대기열에 전달하고 사용자 애플리케이션과 프린터 간 이벤트를 처리하는 윈도우 기본 구성요소로써, 대부분의 윈도우 시스템에 존재합니다. 공격자는 해킹을 통해 최소한의 접근 권한을 얻은 윈도우 피해 시스템에서 해당 취약점을 악용하여 권한 상승을 시도할 수 있습니다. 취약점 악용에 성공하면 공격자는 윈도우 시스템 최고 권한인 SYSTEM 권한으로 추가적인 악성행위를 수행할 수 있습니다.
해당 취약점은 지난 2월 9일 마이크로소프트 정기 패치에서 다른 프린트 스풀러 권한 상승 취약점과 함께 패치 되었으며, 패치가 이루어진 프린트 스풀러의 4가지 권한 상승 취약점 목록은 아래와 같습니다.
[표 1] 2월 9일 패치 된 프린트 스풀러 권한 상승 취약점 목록 (출처 : isc.sans.edu)
본 보고서에서는 이 중 악용 가능성이 높고 PoC가 공개되어 있는 CVE-2022-21999에 대해 살펴보도록 하겠습니다.
CVE-2022-21999 취약점 공격 과정에 대해 알아보기에 앞서 ‘스풀링’과 ‘스풀 디렉토리’에 대한 기본적인 개념 이해가 필요합니다.
프린트 스풀러는 프린터와 CPU간의 처리 속도 차이를 해소하기 위해 인쇄 데이터를 디스크의 임시 공간에 파일 (확장자: .SHD, .SPL)로 저장을 하게 되는데, 이러한 기능을 ‘스풀링’이라고 합니다. 그리고 인쇄 데이터가 저장되는 임시 공간이 바로 ‘스풀 디렉토리’입니다. ‘스풀 디렉토리’는 각 프린터마다 설정할 수 있으며, 모든 사용자에게 WriteData 권한이 허용된다는 특징이 있습니다.
이제 본론으로 들어가 Github에 공개되어 있는 PoC를 바탕으로 CVE-2022-21999 취약점 공격 과정에 대해 알아보도록 하겠습니다. 공격 흐름은 크게 8단계로 나누어 보았습니다.
먼저, %TEMP% 경로에 임시 디렉토리를 생성합니다. 이는 추후 레지스트리에서 스풀 디렉토리를 설정하는 과정에서 사용될 임시 디렉토리입니다.
[그림 1] 임시 디렉토리 생성 (PoC 소스코드)
AddPrinter 함수를 이용해 새 로컬 프린터를 생성하여 프린터 목록에 추가합니다. 프린터가 생성되면 PRINTER_ALL_ACCESS 권한의 프린터 핸들이 반환되며, 반환된 핸들은 추후 프린터 구성을 편집하기 위해 사용됩니다.
[그림 2] 새 로컬 프린터 생성 (PoC 소스코드)
※ 프린터를 생성하기 위해서는 기본적으로 인쇄 서버의 서버 관리 권한이 필요하지만, Windows 10에서 확인 결과, 기본적으로 INTERACTIVE 그룹에 대해 서버 관리 권한이 부여되어 있는 것을 확인할 수 있습니다. 따라서, 일반 사용자도 로컬 프린터 생성이 가능합니다.
단, 이 경우 로컬 프린터 생성 시 사전에 설치된 드라이버를 이용하여야 하며, [그림 2]와 같이 해당 PoC에서는 기본적으로 설치되어 있는 ‘Microsoft XPS Document Writer v4’ 드라이버를 이용한 것을 확인할 수 있습니다.
[그림 3] INTERACTIVE 그룹의 사용 권한
[3.2]에서 생성한 로컬 프린터에 대한 스풀 디렉토리를 설정합니다. 이를 위해 스풀러 구성데이터를 관리하기 위해 제공되는 API 중 하나인 SetPrinterDataEx 함수를 사용하며, 해당 함수를 통해 아래 경로의 레지스트리를 설정합니다.
Key : HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\[생성한 프린터]
Value : SpoolDirectory
[그림 4] 스풀 디렉토리 설정 (PoC 소스코드)
위 과정이 성공적으로 완료되면 레지스트리의 ‘SpoolDirectory’ 값에는 [3.1에서 생성한 임시 디렉토리]\[생성할 스풀 디렉토리 명]에 해당하는 UNC 경로가 등록됩니다.
[그림 5] 레지스트리에서 스풀 디렉토리 설정 확인
※ 스풀 디렉토리 설정과 관련하여 부가적으로 아래 내용을 이해할 필요가 있습니다.
• SetPrinterDataEx 함수를 이용하여 ‘SpoolDirectory’에 대한 레지스트리 설정을 시도하면 레지스트리를 설정하기에 앞서 해당 경로에 대한 현재 사용자의 쓰기권한 여부를 검증합니다. 이는 CVE-2020–1030에 대한 패치에서 구현된 것입니다. 따라서, ‘SpoolDirectory’에 설정할 경로는 현재 사용자 권한으로 디렉토리 생성이 가능한 경로여야 하며, 이러한 유효성 검증을 통과해야 비로소 성공적으로 레지스트리가 설정됩니다.
• 레지스트리를 통해 스풀 디렉토리 설정이 완료되면, 스풀 디렉토리는 스풀러 서비스가 재 시작
될 때 생성됩니다. 따라서, 현재는 레지스트리만 설정이 완료되고 스풀러 서비스는 재 시작되지 않았으므로 스풀 디렉토리는 생성되지 않은 상태입니다.
• 스풀 디렉토리를 %TEMP% 경로의 하위 디렉토리로 설정한 이유는 단지 앞서 언급한 유효성 검증(현재 사용자의 쓰기 권한 여부 검증)을 통과하기 위함 입니다. 취약점을 악용하기 위해 최종적으로 생성하고자 하는 스풀 디렉토리 경로는 프린터 드라이버 하위 경로이며, 다음 단계부터 이를 구현하는 과정에 대해 설명하도록 하겠습니다.
프린터 드라이버 경로(C:\Windows\System32\spool\drivers\x64)는 기본적으로 일반 사용자에게 쓰기 권한이 부여되지 않습니다. 따라서, 일반 사용자 권한으로는 SetPrinterDataEx 함수를 이용해 프린터 드라이버 경로를 스풀 디렉토리로 설정할 수 없습니다. 때문에 1차적으로 [3.3] 과정을 거쳐 임시 디렉토리를 스풀 디렉토리로 설정함으로써 유효성 검증만을 우회해둔 것입니다.
PoC에서는 다음 단계로 정션포인트를 이용합니다. 스풀 디렉토리로 설정해둔 임시 디렉토리 경로를 정션포인트를 이용하여 프린터 드라이버 경로와 연결하는 것입니다.
[그림 6] 정션포인트 설정 (PoC 소스코드)
이렇게 되면 레지스트리의 ‘SpoolDirectory’로 설정한 임시 디렉토리 경로가 정션포인트에 의해 프린터 드라이버 경로와 연결되며, 결론적으로 스풀 디렉토리는 프린터 드라이버 경로를 가리키게 됩니다.
스풀 디렉토리가 프린터 드라이버 경로를 가리키게 설정이 완료되었으므로, 이제 스풀 디렉토리 생성을 위해 스풀러 서비스를 재 시작하여야 합니다. (설정한 스풀 디렉토리는 스풀러 서비스 재시작시 생성됨)
하지만 일반 사용자 권한으로는 정상적인 방법으로 스풀러 서비스를 재 시작할 수 없습니다. 때문에 PoC에서는 이를 위해 Point and Print DLL 기능을 이용합니다.
※ Point and Print DLL은 사용자가 공유 프린터와 드라이버를 쉽게 설치할 수 있도록 하기 위해 고안된 기능 중 하나로써, 이 기능을 이용하면 레지스트리 설정을 통해 원하는 DLL을 스풀러 서비스에 로드 할 수 있습니다. 레지스트리 설정을 통해 Point and Print DLL 기능을 이용하는 경우 SetPrinterDataEx 함수를 사용할 수 있습니다. SetPrinterDataEx 함수는 인자로 전달받은 레지스트리 키를 검증하여 ‘CopyFiles\\’과 일치할 경우, 레지스트리 값(‘Module’)에 전달받은 dll을 스풀러 서비스에 로드 하게 됩니다.
[그림 7] SplSetPrinterDataEx 함수 내부 (localspl.dll)
단, ‘Module’ 값에 전달받은 dll 경로에 대해 유효성 검증을 수행하기 때문에 유효하지 않은 경로에 위치한 dll은 로드 할 수 없습니다. 64bit 윈도우 시스템 기준 유효한 경로는 아래와 같습니다.
• C:\Windows\System32\
• 프린터 드라이버 디렉토리(C:\Windows\System32\spool\drivers\x64\) 및 하위 모든 경로
따라서, 해당 경로 이외에 위치한 dll은 위와 같은 방식으로 로드 할 수 없습니다.
[그림 8]은 Point and Print DLL 기능을 이용해 시스템 내 정상 dll(AppVTerminator.dll)을 로드 하여 스풀러 서비스를 강제 종료 시키는 코드입니다.
[그림 8] Point and Print DLL 기능을 이용한 AppVTerminator.dll 로드 (PoC 소스코드)
해당 dll(AppVTerminator.dll)은 Windows 10 시스템에 존재하는 정상 dll이며, ‘C:\Windows\System32\’ 경로에 위치하였기 때문에 유효성 검증을 통과하여 Point and Print DLL 기능에 의해 스풀러 서비스에 성공적으로 로드 됩니다.
AppVTerminator.dll은 프로세스에 로드 될 경우 현재 프로세스를 종료하는 기능을 수행합니다.
결론적으로 스풀러 서비스는 강제 종료됩니다.
[그림 9] AppVTerminator.dll
하지만 윈도우 시스템에는 서비스 복구 기능이 존재합니다. 기본적으로 스풀러 서비스는 두번의 횟수에 한하여 서비스가 종료되어도 자동으로 다시 시작되게 설정되어 있습니다. 따라서, 강제 종료되었던 스풀러 서비스는 복구 기능에 의해 재시작 됩니다.
[그림 10] 스풀러 서비스 복구 설정
서비스 복구 기능에 의해 스풀러 서비스가 재 시작되면 프린터 드라이버 경로에 원하는 스풀 디렉토리(‘test’)가 생성되었음을 확인할 수 있습니다. 생성된 스풀 디렉토리의 권한을 확인해보면 일반 사용자에게 쓰기 권한이 할당되어 있음을 알 수 있습니다.
[그림 11] 생성된 스풀 디렉토리와 권한 정보
본래 프린터 드라이버 경로는 일반 사용자에게 쓰기 권한이 할당되어 있지 않지만, 위 과정을 통해 생성된 스풀 디렉토리(C:\Windows\System32\spool\drivers\x64\test)는 스풀 디렉토리 특성 상 일반 사용자도 쓰기 권한이 할당됩니다. 따라서, 해당 경로로 악성 DLL을 복사할 수 있습니다.
[그림 12] 스풀 디렉토리로 악성 DLL 복사 (PoC 소스코드)
※ 해당 경로로 악성 DLL을 복사하는 이유는 Point and Print DLL 기능을 이용하여 악성 DLL을 스풀러 서비스에 로드하기 위함 입니다. 앞서 언급하였듯이 Point and Print DLL 기능을 이용하여 DLL을 로드하기 위해서는 DLL 경로에 대한 유효성 검증을 통과해야 하며, 이를 충족할 수 있는 경로는 ‘C:\Windows\System32\’ 혹은 ‘프린터 드라이버 디렉토리 및 하위 모든 경로’ 입니다. 따라서, 이를 위해 프린터 드라이버 디렉토리 하위에 스풀 디렉토리를 생성한 것이며, 해당 경로로 악성 DLL을 복사하는 것이라 보시면 되겠습니다.
스풀 디렉토리로 악성 DLL 복사가 완료되면, [3.5]과정에서 사용한 방법과 마찬가지로 Point and Print DLL 기능을 이용하여 스풀러 서비스에 악성 DLL을 로드 합니다.
[그림 13] 스풀러 서비스에 악성 DLL 로드 (PoC 소스코드)
최종적으로 스풀러 서비스에 로드 된 악성 DLL은 자신이 로드 된 프로세스(spoolsv.exe)와 동일한 권한인 ‘SYSTEM’ 권한으로 악성행위를 수행할 수 있게 됩니다.
Github에 공개되어 있는 CVE-2022-21999 PoC를 활용하여 해당 취약점이 정상적으로 동작하는지 테스트를 진행해보겠습니다. 테스트 환경은 지난 2월 9일 발표된 보안 업데이트가 적용되지 않은 Windows 10 Pro 64bit 시스템이며, 일반 사용자 계정으로 진행을 하였습니다.
[그림 14] PoC 테스트 화면
[표 2] 테스트에 사용된 실행 인자 정보
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\ 경로에 ‘cyberone’ 프린터가 생성된 것을 확인할 수 있으며, 해당 프린터의 ‘SpoolDirectory’ 값이 임시 디렉토리 경로로 설정되어 있는 것을 알 수 있습니다.
[그림 15] 프린터 생성과 ‘SpoolDirectory’ 확인
또한, 프린터 드라이버 경로 내에 최종적으로 스풀 디렉토리가 생성된 것을 확인 가능하며, 해당 경로에는 스풀러 서비스에 로드 할 악성 DLL이 복사되었음을 확인하였습니다.
[그림 16] 스풀 디렉토리 생성과 악성 DLL 복사 확인
해당 악성 DLL은 프로세스에 로드 시 ‘admin’ 이름의 관리자 그룹 계정을 생성하도록 코딩 되어 있습니다.
[그림 17] AddUser.dll 소스코드
악성 DLL이 스풀러 서비스에 성공적으로 로드되어 동작했는지 확인해보면, ‘admin’ 이름의 관리자 그룹 계정이 생성된 것을 확인할 수 있습니다.
[그림 18] 관리자 그룹의 계정 생성 확인
CVE-2022-21999 취약점은 다수의 윈도우 운영체제가 취약한 것으로 보고되었으며, 영향 받는 시스템에 대한 자세한 사항은 아래 NIST 사이트에서 확인할 수 있습니다.
https://nvd.nist.gov/vuln/detail/CVE-2022-21999#match-7487867
해당 취약점은 지난 2월 9일 마이크로소프트 정기 패치에서 패치가 이루어진 사항이므로 윈도우 업데이트를 확인하여 최신 버전으로 업데이트할 것을 권고합니다.
윈도우 업데이트가 불가한 경우, Print Spooler 서비스의 필요 여부를 판단한 뒤, 필요하지 않을 경우 서비스를 중지하고 사용 안함으로 설정할 것을 권고합니다.
• https://github.com/ly4k/SpoolFool
• https://isc.sans.edu/diary/rss/28316
• https://nvd.nist.gov/vuln/detail/CVE-2022-21999#match-7487867
보안관제센터 MIR Team
Microsoft Exchange 0-DAY RCE 취약점(ProxyNotShell)을 이용한 공격 캠페인 발견 (0) | 2022.10.06 |
---|---|
Microsoft 지원 진단 도구(MSDT) 원격 코드 실행 취약점 (CVE-2022-30190) (0) | 2022.06.02 |
리눅스 커널 로컬 권한 상승 취약점 (CVE-2022-0847) (0) | 2022.03.17 |
GitLab 원격 코드 실행 취약점 (CVE-2021-22205) (0) | 2022.03.11 |
댓글 영역