
Windows 64-bit Firefox용 CVE-2019-9810 익스플로잇.
CVE-2019-9810은 Richard Zhu와 Amat Cama가 Pwn2Own 2019에서 발견하여 악용한 취약점입니다. Mozilla의 JavaScript 엔진인 Spidermonkey에 영향을 미치며, 렌더러 손상(renderer compromise)을 달성하는 데 사용되었습니다.
이 문제는 약 두 달 전에 mfsa2019-09에서 수정되었습니다.
간단히 말해, 이 버그는 범위 검사(bounds check)가 중복(redundant)으로 간주되어 최적화되어 사라지게 하여 코드가 경계를 벗어난 메모리에 접근할 수 있도록 합니다. 문제 자체는 Ion 파이프라인의 Alias Analysis 패스(Alias Analysis pass)에 있습니다. 아래 그림은 GVN 최적화 패스(GVN optimization pass)에서 버그의 결과(범위 검사가 최적화되어 사라짐)를 강조하며, 이것이 원하는 내용이라면 좋은 요약이 됩니다:

하지만 더 자세히 알고 싶다면, A journey into IonMonkey: root-causing CVE-2019-9810을 살펴보시길 권장합니다.
저장소에는 익스플로잇 코드뿐만 아니라 이전에 blazefox 익스플로잇을 위해 개발했던 여러 도구가 포함되어 있습니다. 방금 그것들을 다듬고 BigInt와 호환되도록 만들었습니다. 결과적으로, 이 익스플로잇은 Firefox에서 BigInt 지원이 켜져 있다고 가정하며, about:config에서 javascript.options.bigint를 전환하여 활성화할 수 있습니다.

이 익스플로잇은 Windows RS5 64비트에서 테스트되었으며, Firefox의 커스텀 빌드를 대상으로 합니다. 따라서 다른 환경에서 작동하게 하려면 약간의 작업이 필요해도 놀라지 마십시오. 하지만 컴파일하지 않고 익스플로잇을 실행해보고 싶다면, release/firefox-68.0a1.en-US.win64.7z에 업로드한 패키지 브라우저를 준비했습니다. 여기에는 js.exe 셸과 js.exe, firefox.exe, xul.dll에 대한 프라이빗 심볼 정보도 포함되어 있습니다.
익스플로잇 과정은 이전의 kaizen.js 익스플로잇과 매우 유사하게 작동합니다. 리플렉티브 DLL의 ReflectiveLoader로 실행을 전달하며, 이 DLL은 페이로드를 구현합니다:
js.exe에 의해 호출되었음을 감지하면, 단순히 stdout에 PWN을 스팸하고 계산기를 띄운 후 종료합니다.Firefox.exe 프로세스에 자신을 주입하는 것으로 시작합니다. 이를 위해 JavaScript 익스플로잇은 리플렉티브 DLL 복사본에 대한 포인터를 전달하고, 리플렉티브 DLL은 이를 다른 프로세스에 매핑합니다. 이것이 완료되면 리플렉티브 로더에 원격 스레드를 생성하고 잠시 대기합니다. 그 이유는 현재 상태의 익스플로잇이 상당히 지저분하고 프로세스 연속(process continuation)을 구현하지 않기 때문입니다. 하지만 이 시점에서는 그리 많은 작업이 필요하지 않을 것 같습니다. 언젠가 시간을 내서 해볼지도 모르겠네요 :-).Firefox.exe에서 실행될 때, xul!nsJSUtils::ExecutionContext::Compile 함수를 인라인 후킹(inline-hook)합니다. 이 함수는 JavaScript 엔진에서 스크립트를 평가해야 할 때 실행됩니다. 따라서 제가 원하는 작업에 충분히 적합한 후보로 보였습니다. 후킹된 버전은 단순히 우리가 선택한 임의의 JavaScript 페이로드를 앞에 추가합니다.실제로는 위에서 설명하지 않은 더 미묘한 세부 사항들이 많이 있으므로, 관심이 있다면 진실을 찾아 소스를 읽어보시기 바랍니다.
페이로드를 빌드하려면 VS 2017 x64 프롬프트에서 nmake를 실행하기만 하면 됩니다.
CVE-2019-9810\payload>nmake
Microsoft (R) Program Maintenance Utility Version 14.16.27027.1
Copyright (C) Microsoft Corporation. All rights reserved.
ml64 /c src\trampoline.asm
Microsoft (R) Macro Assembler (x64) Version 14.16.27027.1
Copyright (C) Microsoft Corporation. All rights reserved.
Assembling: src\trampoline.asm
if not exist .\bin mkdir bin
type injected-script.js > src\injected-script.h
cl /O1 /nologo /W3 /D_AMD64_ /DWIN_X64 /DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN /Febin\payload.dll src\ReflectiveLoader.c src\ReflectiveDll.cc trampoline.obj /link /DLL /nologo /debug:full /PDBALTPATH:%_PDB%
ReflectiveLoader.c
Generating Code...
Compiling...
ReflectiveDll.cc
Generating Code...
Creating library bin\payload.lib and object bin\payload.exp
python jsify_payload.py bin\payload.dll
move payload.js ..
1 file(s) moved.
del *.obj
del src\injected-script.h
if exist .\bin del bin\*.exp bin\*.ilk bin\*.lib
이렇게 하면 payload\bin 디렉토리 안에 payload.dll / payload.pdb 파일이 생성됩니다. 또한 payload.js라는 JavaScript 파일이 생성되는데, 이 파일은 DLL을 Uint8Array 안에 로더에 대한 오프셋과 함께 포함합니다.
다음 리비전 ID와 동기화된 로컬 Windows 빌드를 대상으로 이 익스플로잇을 작성했습니다: 2abb636ad481768b7c88619080cf224b2c266b2d (직접 빌드하고 싶지 않다면 제 빌드를 여기에 업로드했습니다: release/firefox-68.0a1.en-US.win64.7z):
$ hg --debug id -i
2abb636ad481768b7c88619080cf224b2c266b2d
그리고 다음 mozconfig 파일을 사용했습니다:
. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
ac_add_options --disable-crashreporter
ac_add_options --enable-debug-symbols
. "$topsrcdir/build/mozconfig.clang-cl"
. "$topsrcdir/build/mozconfig.lld-link"
# Use the clang version in .mozbuild
CLANG_LIB_DIR="$(cd ~/.mozbuild/clang/lib/clang/*/lib/windows && pwd)"
export LIB=$LIB:$CLANG_LIB_DIR
ac_add_options --enable-js-shell
ac_add_options --enable-jitspew
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-ff64
제 목적에는 괜찮았지만, xul!nsJSUtils::ExecutionContext::Compile이 임의의 스크립트를 삽입하기에 완벽한 함수인지는 확실하지 않습니다. xul 프론트엔드가 어떻게 작동하는지 이해하는 데 더 많은 시간을 투자하면 더 나은 후킹 지점을 찾을 수 있을 것이라고 확신합니다.
익스플로잇을 작성한 후 발견한 또 다른 몇 가지 접근 방식은 다음 버그질라 항목에서 논의됩니다: 982974 (JavaScript 인터프리터를 위한 시스템 프린시펄(System principal)과 security.turn_off_all_security_so_that_viruses_can_take_over_this_computer). 이것이 오늘날 Firefox에 얼마나 관련이 있는지 확인하는 것도 흥미로울 것입니다.
아마도 누군가가 이 주제를 이미 연구했고 제가 완전히 놓친 것일 수도 있습니다. 어쨌든, 피드백이 있으면 언제든지 연락 주세요!
또 다른 흥미로운 점은 브라우저 내에서 지속성(persistence) 메커니즘을 가질 수 있는 방법이 있는지 탐구하는 것입니다. 이 영역은 전혀 연구하지 않았지만 꽤 멋질 것입니다. :-)