12 minute read

Executive Summary

본 문서는 CVE-2021-40449 취약점의 원인 분석 과정 및 활용(exploit) 코드 개발과정에 대한 내용을 담고 있습니다. 저자는 취약점 원인 분석 및 활용(exploit) 코드 개발 초심자로서 타 보안 연구원대비 활용(exploit, 이하 ‘익스’) 코드 개발까지 많은 시간이 걸려서 기술적으로 우위에 있거나 자랑할 것은 없지만, 저자와 유사한 수준의 경험을 가지고 있는 보안 연구자들이 동일한 실수를 회피하고 교훈을 얻을 수 있도록 익스개발 과정에서의 겪은 실수를 글로 작성하였습니다.

Introduction

소프트웨어 취약점은 그 공개여부를 기준으로 제로데이(Zeroday)/원데이(Oneday)로 구분합니다. 제로데이는 아직 미공개된 취약점으로써 해외에서 매우 비싼 가격에 매매가 이뤄지고 있으며, 간혹 Kaspersky와 같은 보안회사에 의해 ITW(In The Wild)라는 태그로 제조사에 의한 패치와 함께 원데이로 공개됩니다. 원데이(Oneday) 취약점의 경우 대부분 시스템에 패치가 출시된 취약점으로 보안 연구가의 제보 또는 앞에서 언급한 보안회사의 악성코드 분석을 통하여 그 정보가 공개됩니다. 현재는 취약점에 대한 공개 절차가 잘 이뤄져서 제조사에 제보가 이뤄지고 난 뒤 일정 시일(60, 90일)뒤 또는 패치 이후에 공개가 되고 있습니다. 과거 원데이 취약점의 경우 그 취약점을 이해하고 분석할 수 있도록 취약점을 유발(Trigger)할 수 있는 코드, 일명 PoC(Proof of Concept) 코드도 공개하고 계산기(calc.exe) 또는 시스템 권한 상승된 쉘(cmd.exe)를 실행하는 방법이 포함된 익스 코드까지 공개되었지만, 현재 제로데이 취약점이 높은 가격에 거래되면서 원데이 취약점까지 높은 가치의 상품화되어 원데이 취약점 유발/익스 코드 또한 거의 공개되지 않습니다. 특히 크롬(chrome) 샌드박스 탈출(SBX: SandBox Escape)이 가능한 원데이 취약점의 경우 2021년 현재 분석 문서가 공개된 경우는 있어도 그 코드가 공개된 경우가 없습니다. 살펴본 봐로는 작년에도 SBX가 되는 취약점에 대해 코드가 공개된 사례가 없는 것 같습니다.

Image Alt 텍스트
그림1. Vulndb에서 공개하는 CVE-2021-40449 취약점 익스 가격 원화로 2천6백만원에서 1억2천 사이임을 알 수 있다.

Three ways to study the oneday vulnerability

최근의 원데이 취약점 공개 경향을 고려할 시, 윈도우 권한상승 취약점(LPE:Local Privilege Escalation)을 분석하여 본인의 실력을 키우는 방법은 3가지로 생각할 수 있습니다. 첫 번째는 취약점 유발 코드가 존재할 때입니다. 이 경우에는 윈도우 BSOD(BlueScreen Of Death)를 확인할 수 있고, 취약점이 발생하는 지점을 Windbg를 통해 바로 확인할 수 있기때문에 다른 경우보다 신속하게 취약점이 발생하게된 근본 원인(RCA: Root Cause of Vulnerability)을 분석할 수 있습니다. 또한 취약점 유발 코드가 확보된 상태이기때문에 익스 작업에만 초점을 두고 진행할 수 있어 비교적 빠른 시일 내에 시스템권한 cmd를 실행할 수 있습니다. 두 번째에는 취약점에 대한 분석 결과 및 활용코드 개발에 대한 기술 문서를 활용하는 경우입니다. 첫 번째 경우보다는 어려운 과정입니다. 그래도 취약점이 발생하는 함수를 명시적으로 기술해주고, 취약점의 원인을 상세히 기술하는 문서를 만날 수 있는 아주 운이 좋은 경우도 있습니다. 이 경우처럼 Windbg로 취약한 함수에 중단점(BreakPoint)을 설정 후 중단점에서 멈추는 경우를 확인할 수 있으면 비교적 빠른 시일내에 익스에 착수할 수 있습니다. 문서기반으로 원데이 취약점 익스에서 가장 큰 문제는 어떻게하면 취약한 함수까지 도달 할 수 있는지를 자세히 기술해 놓은 문서가 잘 없다는 것입니다. 따라서 취약한 함수까지 도달하는 입력을 만들어 내기위해 상당한 부분을 역공학(Reverse Engineering/Reversing)을 해서 입력을 생성해야합니다. 또한 분석가들이 취약점을 유발하기 위해 꼭 필요한 정보를 기술하지 않는 경우도 있습니다. 따라서 분석 문서가 존재한다고 해서 반드시 쉽게 해당 취약점을 익스할 수 있다는 뜻은 아닙니다. 세번째에는 이 세상 어디에서도 익스를 개발하고 싶은 취약점에 대한 정보가 없는 경우입니다. 이런 원데이 취약점일 때에는 우리는 먼저 취약한 함수가 무엇인가?를 알아내는 일 부터 시작해야 합니다. 이 작업을 할 수 있는 유일한 방법은 패치 디핑(Patch Diffing)입니다. 과거와 달리 꽤 좋은 성능을 지닌 바이너리 디핑도구들이 존재하고 본인은 Diaphora를 즐겨 사용하고 있습니다. 이 경우 상당히 많은 함수들이 패치 디핑의 결과로 나올 수 있고, MS사에서 공개하는 간단한 취약점 유형을 근거로 적절한 함수를 찾아내야 합니다. 때로는 해당 취약점과 관련 없는 함수를 취약한 함수로 생각하여 많은 시간을 허비할 수 도 있고, 취약한 함수를 찾지 못 할 수도 있습니다. 취약점을 패치한 것으로 추정하는 함수가 식별되면, 해당 함수까지 도달할 수 있는 방법을 찾아내야 합니다. 이 단계가 취약한 함수를 찾아내는 것 보다 더 어려운 작업일 수 도 있고, 여기까지 완료해야 내가 찾은 함수가 진짜 내가 찾고자 한 취약한 함수인지도 알 수 있습니다. 여기까지 오면 패치디핑 기반 익스는 70~80 퍼센트 정도 한 것입니다. 본인은 처음에는 CVE-2021-40449의 경우 세번째 패치디핑으로 접근하였고, 나중에 MS Patch Tuesday에 Kaspersky 분석 보고서가 공개되었다는 사실을 확인하였습니다. 정말 아쉬운 점은 본인은 Kaspersky securelist를 메일 구독상태였고 실제로 게시된 글에 대한 메일이 왔음에도 확인을 하지 않았으며, 그로 인해 보다 빠르게 작업할 수 있는 길을 돌아서 갔고, 더욱이 Kasperysky 보고서에서 기본중에 기본인 내용들을 꼼꼼히 확인하지 않아서 너무 의미없이 많은 시간을 흘러보냈다는 점입니다. 이 점이 너무나 아쉽고 다시는 같은 실수를 반복하지 않기 위해서 글로 남기기로 결심했습니다. CVE-2021-40449의 경우 ITW LPE(Local Privilege Escalation) 임에도 취약점 유발 및 익스 코드가 공개된 몇 안되는 경우이며, 윈도우 LPE 취약점을 공부하는 연구자 입장에서 가뭄에 단비와 같은 경우라 할 수 있습니다.

Make a Crash PoC

CVE-2021-40449의 경우 취약점 원인 분석 첫단계부터 잘못 진행되었습니다. 10월12일에 Kasperksy에서 해당 취약점을 활용한 공격에 대한 분석 보고서를 공개했음에도 해당 보고서를 확인하지 않고, 머릿속으로 계속 패치 디핑만 생각하고 있었습니다. 따라서 MS Patch Tuesday가 공개되자마자 해당 다른 정보는 살펴보지도 않고 10월 MS 보안 패치중 윈도우 권한 상승 취약점 목록만 확인하였고, CVE-2021-40449, CVE-2021-41335 이 두개 취약점이 패치된 것을 확인하였습니다. 이 두개중 CVE-2021-40449를 먼저 분석하기로 결정하였는데 그 이유는 트위터에서 CVE-2021-40449는 ITW 취약점이라는 트윗을 확인했기 때문입니다.

시간이라는 자원은 항상 부족하기 때문에 분석을 할 때 우선순위를 결정하는 것은 매우 중요한 작업입니다. 일단 ITW(In The Wild) 취약점의 경우 가장 높은 우선순위를 두고 분석을 합니다. 그 이유는 실제로 활용된 취약점이기 때문에 반드시 익스방법이 존재한다는 확신을 가지고 분석에 착수 할 수 있습니다. 그 다음으로 고려 할 수 있는 것이 취약점이 발생한 모듈입니다. nt, win32k가 있다면 nt에서 발생한 취약점을 먼저 보는 것이 좋습니다. 왜냐하면 크롬때문인데요, 크롬의 경우 win32k 락다운(lockdown) 방어 기법을 적용하고 있기 때문입니다. 따라서 락다운 적용을 받지 않는 nt 모듈에서 발생하는 취약점이 보다 가치가 있고 중요한 취약점이므로 이왕이면 보다 가치있는 취약점을 연구하는 것이 좋습니다.

10월 패치된 윈도우 권한 상승 CVE-2021-40449는 win32k 취약점이고 CVE-2021-41335는 nt 취약점입니다. 하지만 CVE-2021-40449는 제가 정한 규칙에 따라 ITW 취약점이기 때문에 CVE-2021-40449를 먼저 착수하였습니다. 12일에 분석용 VM의 보안 업데이트를 하고 win32kfull.sys, win32kbase.sys 두 개의 파일을 각각 9월/10월 VM 스냅 삿에서 추출했습니다. 그 후 IDA Pro와 Diaphora를 활용해 패치 디핑을 시도하였지만 여기서 문제가 발생했습니다. 12일 당일에 보안 패치는 배포되었지만, 아직 10월에 패치된 바이너리에 대한 디버거 심볼을 업데이트 되지 않았습니다. Diaphora와 같은 패치 디핑 도구들이 가장 기본적으로 패치 함수를 식별하는 방법은 디버거 심볼을 활용하여 함수명은 같은데, 바이너리 구조가 바뀐 것을 찾는 것입니다. 그런데 10월 패치된 바이너리에 대한 심볼이 아직 없으므로 디핑 결과에 대한 신뢰도도 낮고, 너무 많은 함수들이 패치된 함수로 탐지되기 때문에 패치 디핑을 기반한 분석을 착수조차 할 수 없었습니다. CVE-2021-41339 취약점을 대상으로도 패치 디핑을 하였지만 역시 결과는 심볼이 없어서 그 결과를 신뢰할 수 없었습니다. 이 때라도 Kaspersky 보고서를 읽었으면 바로 취약점 유발 PoC 개발을 착수 할 수 있었을 건데, 본인은 디버거 심볼의 서버 업로드를 기다라며, 다른 일을 하며 하루를 기다리기로 결정합니다.

13일 Patch Tuesday 다음날 트위터를 통한 공개정보를 살펴보던 중 벌써 누군가 BSOD PoC를 만든 것을 확인하였습니다. 심볼도 없는 상태에서 패치디핑을 통해 PoC를 하루만에 만들었다는 생각에 속으로 많이 놀랐습니다. 정말 세상에는 고수가 많구나 라는 생각도 하면서 부랴 부랴 정신을 차리고 최대한 빠르게 exploit을 하기 위해 정보를 긁어 모으기로 하고 CVE-2021-40449에 대한 검색을 실시하였습니다. 또한 디버거 심볼 서버도 업데이트 되어서 심볼을 다운로드 할 수 있다는 것을 확인하고 패치디핑 실시, 그 결과 또한 확인하였습니다. 패치디핑 결과는 아래 그림과 같이 win32full!GreResetDCInternal 함수가 상당히 많이 바뀐 것을 확인할 수 있습니다.

Image Alt 텍스트
그림.2 win32kfull.sys 파일를 Diaphora로 패칭 디핑했을 때 결과

패치 디핑은 시간이 많이 걸리는 작업이므로, 디핑을 걸어놓고 공개 정보를 검색하였고, 그 결과로 Kasperksy 분석 보고서를 확인할 수 있었습니다. CVE-2021-40449는 Kasperksy 보안 서비스에 의해 탐지가 되어 MS에 제보된 것으로 판단할 수 있습니다. Kasperksy 보고서 앞쪽에 해당 ITW 취약점이 동작하는 환경을 기술하고 있는데, 이 부분을 일단 지나쳤습니다. 그런데 이 부분을 그냥 지나친 것은 오히려 이 후 엄청난 시간적 손실을 가져오게 됩니다. 취약점 원인 분석 부분을 읽어 보니 패치디핑으로 확인한 win32kfull!GreResetDCInternal 함수가 문제가 되는 것을 확인할 수 있었고, 이 취약 함수를 호출할 수 있는 Ring3 함수는 ResetDC인 것도 확인할 수 있었습니다. 그리고 분석 내용을 읽어보니, 예전부터 취약점을 유발하는 구조인 UserMode Callback 형태라는 것 또한 확인 할 수 있었습니다.

ResetDC 함수의 첫번째 인자로 DC 핸들 값이 들어가야 하는데, 예제 코드로 쉽게 입수할 수 있는 스크린관련 DC 핸들을 인자로 주니, win32kfull!GreResetDCInternal이 호출 되지 않았습니다. 여기가 또 문제의 지점인데, 빨리 만들겠다는 마음이 앞서서 눈에 정보의 필터를 단 것 처럼 파라미터 정보만 확인하고, 해당 함수에 대한 정보를 꼼꼼히 확인할 생각을 하지 않았다는 것입니다. 왜 안되지 왜 안되지 이런 생각만 하고 계속 DC관련된 함수의 파라미터만 조작하면서 계속 엉뚱한 곳에 시간을 써버린 것입니다. 상당한 시간이 흘러가고 다시 ReseDC함수의 MSDN을 다시 읽어보니 이 번에는 그림에서 빨간색으로 밑줄을 그은 “The ResetDC function updates the specified printer or plotter device context (DC) using the specified information.” 문장이 눈에 들어왔습니다. 또 엉뚱한 데서 시간을 써버린 것 때문에 마음만 더 급해졌습니다.

Image Alt 텍스트
그림.3 ResetDC MSDN 설명(빨간색 밑줄 문장이 나중에서야 눈에 들어왔다.)

프린터 DC관련 예제 코드에서 프린터 DC얻는 코드만 추출한 후 이미 작성된 코드에 삽입하니 win32kfull!GreResetDCInternal함수에 BP가 걸렸습니다. 이후 Ring3의 UserMode Callback 함수를 알아 내기 위해 KeUserModeCallback 함수에 BP를 걸고 Callback 함수 인덱스를 확인하니, USER32!__ClientPrinterThunk 함수인 것을 확인할 수 있었습니다. USER32!__ClientPrinterThunk를 우리가 임의로 조작가능한 함수로 설정하고 해당 함수내에서 ResetDC를 한 번 더 호출하는 구조로 PoC를 작성하였습니다. 분명히 Kasperksy 보고서에서 기술하고 있는 구조로 PoC를 작성하였고, 이제 BSOD가 발생하면 그때 해제된 메모리 영역을 !pool 명령으로 확인 후 우리가 조작가능한 객체로 해당 영역을 채우자 이런 생각에 부풀어 있었는데, 아무리 PoC를 돌려도 BSOD가 뜨지 않았습니다. PoC 테스트 VM 이미지 경우 Windows10 1909였고, MSRC CVE-2021-40449 설명 페이지에서도 아래 그림과 같이 Windows10 1909 또한 영향 받는 것으로 되어 있었습니다.

Image Alt 텍스트
그림.4 CVE-2021-40449에 대한 MSRC 웹페이지, Windows10 1909도 취약한 것으로 기술하고있다.

이럴 경우 Windows10 1909에서 왜 PoC가 동작하지 않는지에 대한 정확한 이유를 상세 분석을 통해서 알아내던지, 아니면 Kaspersky 보고서내 동작 환경에 대한 부분을 다시 읽어 봤으면, PoC가 동작하지 않는 이유를 빨리 알아내어 다음 단계로 넘어 갈 수 있었을 텐데, 트위터에 Oliver Lyak(as Ly4k)이 CallbackHell이라는 이름으로 PoC를 공개할 때까지 계속 PoC내에서 API 파라미터 조작 및 두 번째 ResetDC 호출 지점 변경과 같이 계속 PoC 조작만 하였습니다. 한 3일을 그렇게 보내고, CallbackHell PoC를 돌려봤는데 Windows10 1909에서 BSOD가 발생하지 않았습니다. 이제서야 PoC의 문제가 아니구나를 인식하고 다른 원인을 찾기 시작했습니다.

주변 보안 연구자들에게 코드 검수도 받고 문의 끝에 제가 작성한 PoC 코드는 문제 없다는 답변을 받았고 PoC 시험 환경얘기를 하던 중에 Kasperksy 보고서에서는 1809(build no 17763)까지 언급이 되어 있다는 것을 전해 듣고 실제로 보고서를 확인해보니 Windows10의 경우 1809까지 임을 확인할 수 있었습니다.

Image Alt 텍스트
그림.5 CVE-2021-40449에 대한 Kaspersky 웹페이지, Windows10 1809까지 취약한 것으로 기술하고있다.

Windows10 1809 ISO 파일을 다운로드하여 급하게 VM 이미지를 제작하여 CallbackHell PoC를 먼저 실행해보니 BSOD가 발생하는 것을 확인 후 제가 만든 PoC를 실행, 드디어 BSOD를 확인 할 수 있었습니다. 크래쉬 유발이 가능한 PoC를 Kasperksy 보고서 확인한 날 개발했음에도 한 4일을 엉뚱한 곳에서 허비한 것이 너무나 뼈아픈 경험이였습니다. 그림 6.은 제가 작성한 CVE-2021-40449 PoC의 동작 흐름도이며, UserCallback 내에서 호출된 ResetDC에 의해 Callback처리 이후 유효해야할 DC 객체가 강제 해제됨으로써, 해제된 메모리 영역의 유효하지 않는 값을 활용하는 것이 BSOD 유발 원인이였습니다.

Image Alt 텍스트
그림.6 BSOD 유발 PoC의 흐름도
  1. PoC내에서 첫번째 ResetDC을 호출하게 되면 Ring3 가장 종단에서 NtGdiResetDC를 호출하게 되며, 이후 Ring0에서는 NtGdiResetDC함수에서 시작하여 win32kfull!GreResetDCInternal에 다다르게 됩니다.
  2. GreResetDCInternal에서 hdcOpenDCW 호출
  3. hdcOpenDCW에서 KeUserModeCallback 호출, KeUserModeCallback 함수에 의해 USER32!__ClientPrinterThunk(FakeClientPrinterThunk로 후킹된 상태) 호출
  4. FakeClientPrinterThunk에서 두번째 ResetDC 호출
  5. Ring3 ResetDC 호출에 대응하여 SystemCall에 의해 커널영역으로 진입
  6. 2번에서 3번과정 진행 및 첫번째와 달리 정상적인 USER32!__ClientPrinterThunk호출하며 두번째 ResetDC호출 완료, 이 때 PDEV 객체가 해제됨
  7. 두번째 ResetDC 커널영역 코드 실행 종료 후 두 번째 ResetDC 호출 지점으로 복귀
  8. 유저 영역 Callback 종료후 KeUserModeCallback 함수 종료
  9. PDEV 객체가 해제된 상태로 hdcOpenDCW 호출 종료 후, GreResetDCInternal내 남은 로직 수행, BSOD 발생, 만약에 해제된 객체와 유사한 크기의 객체를 할당 시켜서 첫 번째 ResetDC도 BSOD없이 함수 호출 종료가 가능

그림 7.에서는 실제 우리가 익스(exploit)에서 활용할 수 있는 지점을 확인 할 수 있으며, 해제된 객체와 동일한 크기의 Paged Pool을 할당함으로써 우리가 원하는 함수로 실행 흐름을 변경할 수 있음을 확인할 수 있습니다. 비교적 취약점 유발만 할 수 있으면 익스(exploit)는 쉽게 할 수 있는 취약점임을 그림 7.을 보면 확인할 수 있습니다.

Image Alt 텍스트
그림.7 BSOD 유발 지점 및 UAF Paged Pool 정보

Exploitation

CVE-2021-40449의 경우 취약점을 트리거하는 방법을 확보하면 익스(exploit)하는 것은 많이 어렵지 않습니다. 해제된(freed) Pool을 win32kfull!GreResetDCInternal의 hdcOpenDCW 호출이후 활용되기 전 조작된 Pool로 채울 수 만 있으면 그림 7. 에서 확인할 수 있는 것과 같이 조작된 객체에서 함수포인터와 함수 파리미터를 얻기 때문에, 우리가 원하는 함수를 우리가 원하는 인자로 호출 할 수 있습니다. 두 번째 ResetDC 호출로 Pool이 해제되고, UserModeCallback이 완료되기 전에는 hdcOpenDCW 함수 호출이 완료되지 않기 때문에 우리가 후킹한 UserModeCallback 핸들러에서 두 번째 ResetDC호출 이후 해제된 Pool과 동일한 크기의 Pool을 스프레이 함으로써 해제된 Pool 영역을 우리가 원하는 객체로 채울 수 있습니다. 그림 7.에서 !pool 명령 결과를 보면 해제될 메모리 영역 앞에 이미 해제된 Pool이 존재하는데, 이 상태에서 대상 Pool이 해제가 되면, 병합 로직이 동작해 해제 Pool의 크기가 커지게 됩니다. 따라서 이런 경우를 사전에 방지하기 위해서는 목표하는 Pool크기로 익스 성공률 향상을 위한 Pool 조작(Grooming)을 하는 것이 좋습니다. 그렇게 하여 해제 대상 객체 주면에 사전에 해제된 공간이 없게 하는 것입니다. 익스 대상 객체의 크기가 0xE10으로 상당히 큰 Pool공간이므로 팔렛트(Palette) 객체를 활용하여 진행하였으며, Palette를 활용한 익스방법은 많이 공개되어 검색을 통해 쉽게 확인할 수 있습니다.

다음 단계로 우리가 찾아야 하는 것은 적절한 커널 모듈 함수, 그리고 함수 파라미터 선정입니다. 함수, 함수파라미터 선정전에 윈도우내에서 권한 상승이라는 효과를 달성하기 위해 우리가 목표로 설정해야하는 것이 무엇인지를 아는 것이 먼저일 것 같습니다. 최근 보안 연구자들이 주로 얘기하는 방법은 첫 번째는 PreviousMode를 0으로 설정하는 것 두 번째는 SEP_TOKEN_PRIVILEGE 구조체내 플래그 정보를 다 1로 셋하여 모든 권한을 가지게 하는 것 이 두가지 방법을 많이 사용합니다. CVE-2021-40449의 경우 SEP_TOKEN_PRIVILEGE를 이용해서 익스(exploit) 하는 것이 공개되어 있으므로, PreviousMode를 0으로 설정하는 것을 목표로 설명하겠습니다.

PreviousMode을 0으로 설정하기 위해서는 함수의 인자로 KTHREAD 구조의 PreviousMode의 주소를 함수의 인자로 설정할 수 있어야하고, 이 주소 영역을 0으로 덮어쓰는 동작을 코드로 가지고 있으면서, 원치않는 결과를 최소화 할 수 있도록, 함수내 코드가 짧으면 짧을 수 록 좋습니다. IDA Pro에서 ntoskrnl.exe 모듈을 열어서 해당 모듈내 모든 함수를 클릭해 가며, 위와 같은 조건에 해당하는 함수를 찾아보면 여러 함수를 찾을 수 있지만, 저는 nt!xHalQueryProcessorRestartEntryPoint 함수를 선택하였습니다. nt!xHalQueryProcessRestartEntryPoint함수의 경우 아래 그림에서와 같이 rcx 즉 첫번째 인자를 주소로 활용하여 8바이트를 0으로 채우는 효과를 가지며, 코드가 워낙 짧아 예측 불가능한 동작을 최소화 할 수 있습니다. 단 nt!xHalQueryProcessRestartEntryPoint 함수의 경우 nt모듈에서 export하는 함수가 아니므로, OS Build 정보별 해당 함수의 오프셋 정보를 가지고 있어야하며, nt모듈의 Base주소에 해당 오프셋을 더하여 함수 주소로 사용하여야 합니다. 다른 함수대비 조금 더 노력이 필요하다는 것이 단점입니다. 그럼 우리는 첫번째 인자로 사용해야할 값과 이 때 사용해야할 커널내 함수 주소 이 두가지를 다 확보하였습니다. 이제 다시 그림 7.로 돌아가서 RBX가 가리키는 Pool에서 0xAB0 오프셋 주소에 함수 주소를 설정하고, 0x700 오프셋에 파라미터 값을 설정하면 된다는 것을 확인 후 Palette 객체내에서도 앞에서 언급한 오프셋 위치에 값을 셋팅하면 됩니다. 단 우리가 임의로 셋팅 가능한 부분이 PaletteEntry 영역이므로 Palette 헤더 정보 오프셋(0x24)만큼을 각각 더해줘야 합니다. 이 것은 실제로 값을 설정해서 Windbg상으로 확인해보면 간단히 확인할 수 있습니다.

Image Alt 텍스트
그림.8 IDA Pro에서 리버싱된 xHalQueryProcessRestartEntryPoint 함수

위와 같은 구조로 익스(exploit) 코드를 구성하여 실행하면, 아래 그림과 같은 결과를 얻을 수 있습니다. 이후 현재 프로세스가 PreviousMode 값이 0이기 때문에, winlogon.exe 프로세스같은 높은 권한의 프로세스에 쓰레드 인젝션이 가능함으로, 임의의 높은 권한의 프로세스를 실행할 수 있습니다. 단 풀 익스코드를 만드셨다면, 윈도우 디펜더와 같은 Anti-Virus 소프트웨어는 비활성화 하시는 것을 추천드립니다. 여러분들의 코드를 악성으로 간주해 다 검역소로 보내거나 삭제할 것입니다.

Image Alt 텍스트
그림.9 익스(exploit) 전/후 PreviousMode값

Epilogue

CVE-2021-40449의 경우 비교적 짧은 시간내 익스까지 완료할 수 있었던 취약점이였음에도 1주일 이상 긴 시간이 소요되었는데, 그 근본 이유를 한 마디로 정리하면 공개되어 있는 정보에 대해 세밀한 분석이 없었으며, 너무 많은 것들을 눈보다 머리속에서 가정하고 진행했다라는 점입니다. 그리고 의욕이 너무 앞서, 시야가 좁아져 눈앞에 있는 정보를 인지하지 못 했습니다. 이 글을 읽는 분들은 제가한 실수가 다소 유치해 보일 수도 있습니다. 저 또한 이렇게 적고나니 다소 허무한 실수라 생각이 듭니다. 하지만 그 당시에는 당연히 확인해야하는 것 들이 정말 눈에 보이지 않았고, 한 번 스텝이 꼬이고 나니 시간을 허비했다는 생각에 점점더 스텝이 꼬이는 … 정말 악순환의 연속이였습니다. 앞으로 공개취약점 분석을 할 때에는 CVE-2021-40449에서의 경험을 살려 효과적인 분석을 실시하도록 할 계획이며, 앞으로도 분석을 하다가 공유하고 싶은 경험이나 지식이 있으면 블로그를 계속 작성하도록 하겠습니다. 그리고 이 글을 읽고 잘 이해가 되지 않는 분들은 synam[AT]mtf.re.kr로 질문사항을 주시면 제가 알고있는 범위내에서 답변해드리도록 하겠습니다.

마지막으로 이 글을 읽고 윈도우 권한상승 공개취약점 분석 및 PoC 개발에 관심 있으신 분들은 synam[AT]mtf.re.kr로 연락을 주시면 같이 공부하면서 함께 실력을 높이는 기회를 만들었으면 좋겠습니다. 초기 학습 멤버로 3~4명 정도 모시고 싶으며, 초과하는 인원에 대해서는 스터디 그룹이 어느정도 안정화되면 추가적으로 모시겠습니다. 감사합니다.

References

  • https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40449
  • https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-resetdca
  • https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/
  • https://vuldb.com/?id.184265
  • https://github.com/ly4k/CallbackHell
  • https://github.com/KaLendsi/CVE-2021-40449-Exploit
  • https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation