
Sleirsgoevy के CVE-2018-4386 के एक्सप्लॉइट कार्यान्वयन के संस्करण का एक लेख, जिसे Fire30 द्वारा Bad_Hoist कहा जाता है।
[!Note] PS4 के बारे में पृष्ठभूमि जानकारी:
PlayStation 4 कंसोल में एक कस्टम AMD x86-64 CPU (8 कोर) है, इसका Orbis OS FreeBSD (v9.0) पर आधारित है जिसमें NetBSD के कुछ हिस्से भी शामिल हैं। इसमें कई अतिरिक्त ओपन सोर्स सॉफ्टवेयर भी शामिल हैं, जैसे Mono VM और WebKit।
PS4 द्वारा उपयोग किया जाने वाला इंटरनेट ब्राउज़र वास्तव में ओपन सोर्स WebKit प्रोजेक्ट से बनाया गया है। यह ओपन सोर्स लेआउट इंजन है जो iOS, Wii U, 3DS, PS Vita और PS4 के ब्राउज़रों में वेब पेजों को रेंडर करता है।
PS4 इंटरनेट ब्राउज़र वास्तव में 2 अलग-अलग प्रक्रियाओं से बना है। जिसे हम कोड निष्पादन के लिए हाईजैक करते हैं, वह WebKit कोर प्रक्रिया है (जो उदाहरण के लिए HTML और CSS को पार्स करना, इमेज को डिकोड करना और जावास्क्रिप्ट को निष्पादित करना संभालती है)। दूसरी प्रक्रिया बाकी सब कुछ संभालती है: ग्राफिक्स प्रदर्शित करना, कंट्रोलर इनपुट प्राप्त करना, हिस्ट्री और बुकमार्क प्रबंधित करना, आदि।
PS4 WebKit ब्राउज़र कई हीप आवंटकों का उपयोग करता है, प्रत्येक विभिन्न घटकों की सेवा करता है। ये निम्नलिखित हैं:
CVE-2018-4386 का मूल WebKit (v605.1.15) के JavaScriptCore (JSC) इंजन में एक तर्क दोष है, जो PS4 फर्मवेयर 6.XX में उपयोग किया जाने वाला संस्करण है।
यह दोष BytecodeGenerator::hoistSloppyModeFunctionIfNecessary फंक्शन में मौजूद है और इसमें स्लॉपी मोड JavaScript में वेरिएबल होइस्टिंग का अनुचित प्रबंधन शामिल है, विशेष रूप से for-in लूप्स के अंदर।
भेद्य घटक (ForInContext):
हम जिस चीज को मुख्य रूप से लक्षित करते हैं, वह ForInContext है। यह JavaScriptCore द्वारा for-in लूप की स्थिति को प्रबंधित करने के लिए उपयोग की जाने वाली एक आंतरिक संरचना है, जो वर्तमान पुनरावृत्ति चर और गणना की जा रही गुणों के सेट को ट्रैक करती है।
जब for-in लूप के अंदर एक फंक्शन घोषणा होइस्ट की जाती है, तो यदि पुनरावृत्ति चर ओवरराइट किया जाता है तो इंजन को संबंधित ForInContext ऑब्जेक्ट को अमान्य कर देना चाहिए। हालांकि, बग के कारण, यह अमान्यकरण नहीं होता है।
यह पुनरावृत्ति चर को एक मनमानी वस्तु से बदलने की अनुमति देता है। इसके बावजूद, इंजन वेरिएबल को एक स्ट्रिंग गुण नाम के रूप में मानता रहता है।
जब बाद में op_get_direct_pname बाइटकोड हैंडलर को आमंत्रित किया जाता है, तो यह प्रकार जांच के बिना पुनरावृत्ति चर को सीधे एक स्ट्रिंग ऑब्जेक्ट के रूप में उपयोग करता है।
एक स्ट्रिंग के बजाय एक गढ़ी हुई वस्तु पारित करके, जिससे प्रकार-भ्रम होता है, हम इसका शोषण इस तरह से करने में सक्षम होते हैं जो मेमोरी भ्रष्टाचार प्राप्त करता है, और यहां तक कि addrof, fakeobj, और मनमाना पढ़ना/लिखना जैसी उपयोगी शोषण प्रारंभिकाएं भी प्राप्त करते हैं।
स्ट्रक्चर आईडी: JavaScriptCore में प्रत्येक ऑब्जेक्ट, जिसमें WTF::StringImpl जैसी आंतरिक प्रस्तुतियां शामिल हैं, के पास एक स्ट्रक्चर आईडी (या प्रकार टैग) होता है जो इंजन को बताता है कि वस्तु किस प्रकार की है और इसके क्षेत्रों की व्याख्या कैसे करनी है।
प्रकार-भ्रम: हमारा शोषण CVE-2018-4386 बग का दुरुपयोग करके JavaScript ऑब्जेक्ट को StringImpl के रूप में व्याख्या करवाता है। यह create_impl() फंक्शन का उद्देश्य है, जो एक WTF::StringImpl प्रकार-भ्रमित वस्तु लौटाता है, जिसे बाद में trigger() फंक्शन को उस मनमानी वस्तु के रूप में पारित किया जा सकता है जिसके बारे में हमने इस लेख के भेद्यता तंत्र भाग में पहले बात की थी।
हालांकि, इसके काम करने के लिए, मेमोरी लेआउट और स्ट्रक्चर आईडी को इंजन की एक वास्तविक स्ट्रिंग ऑब्जेक्ट के लिए अपेक्षा के "काफी करीब" होना चाहिए।
JSString::toIdentifier() आंतरिक रूप से क्या करता है?PS4 इंटरनेट ब्राउज़र के WebKit JavaScriptCore इंजन में एक विधि है जिसका नाम JSString::toIdentifier() है। यह विधि एक JavaScript स्ट्रिंग ऑब्जेक्ट (JSString) को एक आंतरिक पहचानकर्ता प्रतिनिधित्व में परिवर्तित करती है।
इस पहचानकर्ता का उपयोग पूरे इंजन में संपत्ति नामों, चर नामों और अन्य स्ट्रिंग्स की कुशलता से तुलना, भंडारण और खोज करने के लिए किया जाता है जिन्हें JavaScript इंजन द्वारा जल्दी और बार-बार संदर्भित किया जाना चाहिए।
यह जांचता है कि वस्तु एक मान्य स्ट्रिंग है और इसकी स्ट्रक्चर आईडी इंजन की स्ट्रिंग ऑब्जेक्ट के लिए अपेक्षा से मेल खाती है। यदि स्ट्रिंग एक रोप (स्ट्रिंग्स का संयोजन) है, तो यह रूपांतरण से पहले इसे चपटा कर सकता है। फिर यह या तो स्ट्रिंग के लिए मौजूदा पहचानकर्ता को पुनः प्राप्त करता है या यदि यह मौजूद नहीं है तो एक नया बनाता है।
यह पहचानकर्ता फिर तेज संपत्ति और चर खोजों के लिए आंतरिक रूप से उपयोग किया जाता है।
JSString::toIdentifier() जांचों के लिए काम का तरीकाजब शोषण 1024 बार पुनरावृत्ति करने वाले for-लूप में प्रवेश करता है, तो प्रत्येक पुनरावृत्ति create_impl() फंक्शन द्वारा लौटाए गए 32 नई स्ट्रक्चर आईडी के साथ एक नया प्रकार-भ्रमित WTF::StringImpl ऑब्जेक्ट बनाती है।
जब इस प्रकार-भ्रमित वस्तु का उपयोग किया जाता है और इसे मनमानी वस्तु के रूप में trigger() को पारित किया जाता है, तो JSC उस पर JSString::toIdentifier() को कॉल करता है।
JSString::toIdentifier() स्ट्रक्चर आईडी में कुछ बिट्स की जांच करता है ताकि यह पुष्टि की जा सके कि वस्तु एक मान्य स्ट्रिंग है या इसे एक के रूप में माना जा सकता है। विभिन्न लेआउट और स्ट्रक्चर आईडी के साथ कई वस्तुएं उत्पन्न करके, शोषण संभावनाओं को बढ़ाता है कि कम से कम एक के पास एक स्ट्रक्चर आईडी होगा जो JSString::toIdentifier() में आंतरिक जांचों को पास करता है।