
SnatchBox (CVE-2020-27935) macOS के 10.15.x तक के संस्करणों को प्रभावित करने वाला एक सैंडबॉक्स एस्केप भेद्यता और एक्सप्लॉइट है।
SnatchBox (CVE-2020-27935) एक सैंडबॉक्स एस्केप भेद्यता है जो macOS के संस्करण 10.15 तक, साथ ही macOS 11.0 के प्रारंभिक बीटा संस्करणों को प्रभावित करती है। SnatchBox का सबसे महत्वपूर्ण प्रभाव यह है कि यह एक दुर्भावनापूर्ण प्रकाशक को गैर-वैकल्पिक macOS ऐप स्टोर सैंडबॉक्स से बचने और उपयोगकर्ता की सभी फ़ाइलों तक पूर्ण पहुँच प्राप्त करने की अनुमति देता है, जिससे macOS पर ऐप स्टोर की सुरक्षा मॉडल टूट जाता है।
तथ्य यह है कि macOS में, उदाहरण के लिए iOS के विपरीत, एक userspace कार्य स्वेच्छा से स्वयं को एक सैंडबॉक्स में रखता है, डिज़ाइन के अनुसार कमजोर है। चूंकि यह एक ऐसा कार्य है जिस पर एक संभावित दुर्भावनापूर्ण लेखक का अपनी मेमोरी मैपिंग और सामग्री पर लगभग पूर्ण नियंत्रण होता है, और सैंडबॉक्स प्रारंभिकरण से पहले चलने वाला कोड (जैसे dyld स्वयं, या Objective-C रनटाइम) इस संभावित दुर्भावनापूर्ण बाइनरी की सामग्री को पार्स करता है, ध्यानपूर्वक तैयार किए गए डेटा का उपयोग सैंडबॉक्स प्रारंभिकरण से पहले कोड निष्पादन प्राप्त करने के लिए किया जा सकता है। यदि प्रक्रिया सैंडबॉक्स में लागू होने से पहले कभी भी कोई कोड, जिसमें dyld कोड भी शामिल है, निष्पादित नहीं करेगी, तो यह कोई समस्या नहीं होती, क्योंकि उस मामले में प्रारंभिक कोड निष्पादन से हमले को कुछ हासिल नहीं होगा। यह अवधारणात्मक रूप से Saagar Jha के सैंडबॉक्स बाईपास के समान है, सिवाय इसके कि यह नव-प्रस्तुत शमन और ऐप स्टोर सत्यापनों को बायपास करता है।
macOS 10.15 से पहले इस बग का शोषण काफी सरल है। कोई एक बाइनरी बनाएगा जिसमें एक ऐसी क्लास के लिए Objective-C श्रेणी होती है जिसका उपयोग सैंडबॉक्स प्रारंभिकरण से पहले किया जाता है (जैसे OS_xpc_object) और एक विधि को ओवरराइड करेगा (अधिमानतः एक विरासत में मिली विधि ताकि रनटाइम चेतावनियों से बचा जा सके) जिसका उपयोग सैंडबॉक्स प्रारंभिकरण से पहले किया जाता है (जैसे +initialize, जिसे क्लास तक पहली पहुँच पर अंतर्निहित रूप से कॉल किया जाता है)। क्योंकि श्रेणियाँ सैंडबॉक्स प्रारंभिकरण से पहले लोड की जाती हैं, और OS_xpc_object (या अन्य उपयुक्त पीड़ित क्लास) तक पहली पहुँच श्रेणियाँ लोड करने के बाद और सैंडबॉक्स प्रारंभिकरण से पहले की जाती है, हमलावर द्वारा प्रदान की गई +initialize विधि (या अन्य उपयुक्त पीड़ित विधि) को सैंडबॉक्स प्रारंभिकरण से पहले कॉल किया जाएगा, जिससे उदाहरण के लिए, कंटेनर के बाहर डेटा तक पहुँचा जा सकता है। वैकल्पिक रूप से, हमलावर _libsecinit_initializer (जो सैंडबॉक्स को प्रारंभ करता है) के संदर्भ को nop-जैसे फंक्शन से बदल सकता है ताकि (संभावित रूप से सशर्त रूप से) निष्पादन फिर से शुरू होने के बाद भी सैंडबॉक्स को अक्षम किया जा सके।
macOS 10.15 में उपयोग किया जाने वाला Objective-C रनटाइम पहले विस्तृत की गई शोषण तकनीक के प्रति संवेदनशील नहीं है, क्योंकि didCallDyldNotifyRegister सेट होने से पहले श्रेणियाँ लोड नहीं की जाती हैं, जिससे हमारी +initialize विधि सैंडबॉक्स प्रारंभिकरण होने के बाद ही कॉल की जाती है।
हालाँकि, map_images अभी भी हमारी बाइनरी पर कॉल किया जाता है, जिससे रनटाइम डेटा को अनपेक्षित तरीकों से बदलना संभव हो जाता है जो हमें सैंडबॉक्स प्रारंभिकरण से पहले कोड निष्पादित करने की अनुमति देगा। पूर्ण, टिप्पणी-युक्त शोषण main.c में है, लेकिन मैं यहाँ मूल विवरणों के माध्यम से जाऊंगा। हम एक Objective-C क्लास संरचना बनाते हैं जिसका data पॉइंटर libxbc.dylib में एक स्थान की ओर इंगित करता है। उस स्थान को इस प्रकार चुना जाना चाहिए कि flags में बिट 31 (RW_REALIZED) सेट हो, ताकि रनटाइम इस अमान्य क्लास को realize करने का प्रयास न करे और क्रैश न हो, और firstSubclass को उस क्लास के isa के साथ अपना पता साझा करना होगा जिसे हम ओवरराइड करना चाहते हैं। एक और (मेटा) क्लास इस अमान्य क्लास से इनहेरिट करेगी, और अपनी स्वयं की +initialize विधि प्रदान करेगी। हम उपवर्ग को __objc_nlclslist में जोड़ते हैं ताकि रनटाइम इस क्लास को realize करे।
जब रनटाइम हमारे उपवर्ग को realize करता है, जो सैंडबॉक्स प्रारंभिकरण से पहले होता है, यह हमारे अमान्य सुपरक्लास और उपवर्ग पर addSubclass को कॉल करेगा, जो पीड़ित के isa को हमारे उपवर्ग के पॉइंटर से बदल देगा, प्रभावी रूप से इसकी सभी विधियों को हमारे +initialize से बदल देगा। जब हमारी +initialize विधि को कॉल किया जाता है, जो सैंडबॉक्स प्रारंभिकरण से पहले होगा यदि हमने एक उपयुक्त पीड़ित क्लास चुनी है, तो हम फिर से _libsecinit_initializer संदर्भों को nops से बदल सकते हैं (सशर्त रूप से या नहीं), और बाद में बिना क्रैश हुए निष्पादन को फिर से शुरू करने के लिए किए गए रनटाइम परिवर्तनों को ठीक कर सकते हैं।
प्रदान किया गया डेमो make चलाकर, ~/Documents/SecretDocument.txt पर एक फ़ाइल बनाकर, और टर्मिनल से SnatchBox.app/Contents/MacOS/SnatchBox चलाकर बनाया जा सकता है (एक बंडल बनाया जाता है क्योंकि यह com.apple.security.app-sandbox द्वारा आवश्यक है, लेकिन यह अभी भी एक कमांड लाइन प्रोग्राम है)। निर्मित बाइनरी पर com.apple.security.app-sandbox के साथ हस्ताक्षर किए गए हैं जो सामान्यतः ~/Documents/SecretDocument.txt तक पहुँच को रोक देगा (क्योंकि यह हमारे कंटेनर में नहीं है), लेकिन फिर भी इसके डेटा को पढ़ने में सक्षम होगा। रनटाइम संरचना परिवर्तनों के कारण यह डेमो macOS 10.14 और पहले के असंशोधित संस्करणों पर काम नहीं करेगा, लेकिन 10.15 और 11.0 पर काम करेगा (परीक्षण किया गया: 10.15.4, 10.15.7 और 11.0 बीटा (20A5354i))। दोनों शोषण तकनीकों को दोनों रनटाइम संस्करणों को लक्षित करने के लिए जोड़ा जा सकता है, लेकिन ऐसा प्रदर्शन प्रदान नहीं किया गया है।
उदाहरण रन:
CatalinaVM:SnatchBox lior$ make
mkdir -p SnatchBox.app/Contents/MacOS/
clang -O3 -Wall -framework Foundation main.m -o SnatchBox.app/Contents/MacOS/SnatchBox
cp Info.plist SnatchBox.app/Contents/
codesign --force --sign - SnatchBox.app --entitlements ent.xml
CatalinaVM:SnatchBox lior$ echo "Quack"> ~/Documents/SecretDocument.txt
CatalinaVM:SnatchBox lior$ codesign -d --entitlements :- SnatchBox.app/Contents/MacOS/SnatchBox
Executable=/Volumes/SharedFolders/Home/Projects/SnatchBox/SnatchBox.app/Contents/MacOS/SnatchBox
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>
CatalinaVM:SnatchBox lior$ SnatchBox.app/Contents/MacOS/SnatchBox
Found libsecinit_initializer at 0x7fff72309124
Found libSystem.B.dylib at 0x7fff6f0de000
Found __DATA at 0x7fff984eeca0
Replacing libsecinit_initializer reference at 0x7fff984eed48 with a nop
2020-12-18 16:31:48.196 SnatchBox[804:8043] Attempting to read protected file: /Users/lior/Documents/SecretDocument.txt
2020-12-18 16:31:48.197 SnatchBox[804:8043] Escaped sandbox! The contents are: <51756163 6b0a>
जैसा कि पहले उल्लेख किया गया है, यह एक macOS ऐप स्टोर एप्लिकेशन बनाने की अनुमति देता है जो ऐप स्टोर नीति द्वारा आवश्यक होने के बावजूद सैंडबॉक्स में नहीं चलता है। भेद्यता का उपयोग एक फ्रेमवर्क में भी किया जा सकता है, जिसका उपयोग अन्यथा वैध ऐप स्टोर एप्लिकेशन कर सकते हैं। अंत में, इसे "Xcode Ghost" के समान किसी चीज़ के साथ जोड़कर ऐप स्टोर एप्लिकेशन में बड़े पैमाने पर दुर्भावनापूर्ण कोड इंजेक्ट किया जा सकता है जो सैंडबॉक्स के बाहर चलता है।
Apple ने macOS 11.0 के बीटा परीक्षण चरण के दौरान realizeClassWithoutSwift में malloc_size के कॉल को जोड़कर शोषण को ठीक किया। यह पुष्टि करता है कि यदि कोई क्लास realize के रूप में चिह्नित है (RW_REALIZED, हमारी नकली क्लास की तरह), तो उसके पास वास्तव में एक वैध, malloc'ed डेटा पॉइंटर है, जिसका सही आकार (0x20 बाइट्स) है। यदि ऐसा नहीं है, तो रनटाइम realized class 0x100002078 has corrupt data pointer 0x7fff88c00948 जैसे संदेश के साथ बंद हो जाएगा। फिक्स को iOS, iPadOS, tvOS और watchOS पर भी लागू किया गया था; भले ही वे सीधे प्रभावित न हों।