
CVE-2017-13868: XNU में अप्रारंभिक कर्नेल हीप डेटा का सूचना रिसाव।
macOS High Sierra 10.13 में ctl_ctloutput फ़ंक्शन sooptcopyin कॉल के रिटर्न वैल्यू को अनदेखा करता है, जो अनइनिशियलाइज़्ड कर्नेल हीप डेटा को यूज़र स्पेस में लीक करने के लिए एक रेस विंडो खोलता है। ctl_ctloutput-leak एक प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट है जो इस सूचना लीक को ट्रिगर करने का प्रयास करता है। इस एक्सप्लॉइटेशन के लिए रूट विशेषाधिकार आवश्यक हैं।
यह एक्सप्लॉइट macOS High Sierra 10.13.1 Beta 17B25c और iOS 10.1.1 14B100 (mach_portal के अंतर्गत) पर काम करता हुआ पुष्ट किया गया है।
यहाँ macOS High Sierra 10.13 पर ctl_ctloutput का प्रासंगिक भाग है:
if (sopt->sopt_valsize && sopt->sopt_val) {
MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, // (a) data is allocated
M_WAITOK); // without M_ZERO.
if (data == NULL)
return (ENOMEM);
/*
* 4108337 - copy user data in case the
* kernel control needs it
*/
error = sooptcopyin(sopt, data, // (b) sooptcopyin() is
sopt->sopt_valsize, sopt->sopt_valsize); // called to fill the
} // buffer; the return
len = sopt->sopt_valsize; // value is ignored.
socket_unlock(so, 0);
error = (*kctl->getopt)(kctl->kctlref, kcb->unit, // (c) The getsockopt()
kcb->userdata, sopt->sopt_name, // implementation is
data, &len); // called to process
if (data != NULL && len > sopt->sopt_valsize) // the buffer.
panic_plain("ctl_ctloutput: ctl %s returned "
"len (%lu) > sopt_valsize (%lu)\n",
kcb->kctl->name, len,
sopt->sopt_valsize);
socket_lock(so, 0);
if (error == 0) {
if (data != NULL)
error = sooptcopyout(sopt, data, len); // (d) If (c) succeeded,
else // then the data buffer
sopt->sopt_valsize = len; // is copied out to
} // userspace.
यह कोड निम्नलिखित कार्य करता है:
getsockopt के डेटा पैरामीटर के लिए एक कर्नेल हीप बफर आवंटित करता है, बिना M_ZERO फ़्लैग निर्दिष्ट किए जो आवंटित बाइट्स को शून्य कर देता है।sooptcopyin का उपयोग करके यूज़रस्पेस से getsockopt डेटा को कॉपी करता है, जिससे अभी-अभी आवंटित डेटा बफर भर जाता है। यह copyin आवंटित डेटा को पूरी तरह से अधिलेखित करने वाला होता है, यही कारण है कि M_ZERO फ़्लैग की आवश्यकता नहीं थी। हालाँकि, sooptcopyin का रिटर्न वैल्यू जाँचा नहीं जाता, जिसका अर्थ है कि copyin विफल हो सकता है, जिससे बफर में अनइनिशियलाइज़्ड डेटा रह जाता है। copyin विफल हो सकता है, उदाहरण के लिए, यदि प्रोग्राम ने getsockopt को एक अनमैप्ड पता पास किया।getsockopt कार्यान्वयन को कॉल करता है। इस कार्यान्वयन को इनपुट बफर को संसाधित करना चाहिए, संभवतः इसे संशोधित और छोटा करना चाहिए, और एक परिणाम कोड लौटाना चाहिए। हालाँकि, कार्यान्वयन यह मानने के लिए स्वतंत्र है कि आपूर्ति किया गया बफर पहले से ही आरंभीकृत है (क्योंकि सैद्धांतिक रूप से यह यूज़र स्पेस से आता है), और इसलिए कई कार्यान्वयन बफर को बिल्कुल भी संशोधित नहीं करते हैं। उदाहरण के लिए, NECP फ़ंक्शन necp_ctl_getopt डेटा बफर को बिल्कुल भी संसाधित किए बिना केवल 0 लौटाता है।getsockopt कार्यान्वयन कोई त्रुटि नहीं लौटाता है, तो डेटा बफर को वापस यूज़र स्पेस में कॉपी करने के लिए को कॉल करता है।इस प्रकार, getsockopt को एक अनमैप्ड डेटा पता निर्दिष्ट करके, हम नियंत्रित आकार के हीप बफर को आवंटित कर सकते हैं, उस बफर की सामग्री को आरंभीकृत होने से रोक सकते हैं, और फिर sooptcopyout के कॉल तक पहुँच सकते हैं जो उस बफर को वापस अनमैप्ड पते पर लिखने का प्रयास करता है। copyout को सफल बनाने के लिए हमें बस इतना करना है कि sooptcopyin और sooptcopyout के कॉल के बीच उस पते को रीमैप करें। यदि हम ऐसा कर सकते हैं, तो हम अनइनिशियलाइज़्ड कर्नेल हीप डेटा को यूज़रस्पेस में लीक कर देंगे।
यह पता चला है कि यह एक काफी आसान रेस है जिसे जीता जा सकता है। अपने 2015 Macbook Pro पर परीक्षण करते समय, रेस जीतने के प्रयासों की औसत संख्या कभी भी 600 से अधिक नहीं थी, और माध्यिका कभी भी 5 से अधिक नहीं थी। iPhone 7 पर iOS 10.1.1 पर रेस जीतना और भी आसान था, आमतौर पर 2 से अधिक प्रयास नहीं लगते थे। (यह परीक्षण DEBUG बंद करके किया गया था, क्योंकि printfs एक्सप्लॉइट को काफी धीमा कर देते हैं।)
बनाने के लिए, make चलाएँ। विभिन्न बिल्ड विकल्पों के लिए Makefile के शीर्ष देखें।
कमांड लाइन पर लक्ष्य लीक आकार निर्दिष्ट करके एक्सप्लॉइट चलाएँ:
$ sudo ./ctl_ctloutput-leak 128
000000: ef be ad de ef be ad de 00 00 00 00 00 00 00 00
000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000020: 00 00 00 00 00 00 00 00 01 00 00 00 40 80 00 00
000030: de 28 45 00 04 00 00 00 a0 ff 4a 26 80 ff ff ff
000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000050: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000070: 00 00 00 00 00 00 00 00 ef be ad de ef be ad de
मैंने इस मुद्दे की सूचना 7 अक्टूबर, 2017 को Apple को दी थी। इसे CVE-2017-13868 निर्दिष्ट किया गया था। Apple ने macOS 10.13.2 और iOS 11.2 में मुद्दों को ठीक किया।
ctl_ctloutput-leak कोड को सार्वजनिक डोमेन में जारी किया गया है। एक शिष्टाचार के रूप में मैं अनुरोध करता हूँ कि यदि आप इस कोड का कोई संदर्भ या उपयोग करते हैं तो आप इसका श्रेय मुझे दें।
ctl_ctloutputsooptcopyout