
macOS SSH क्लाइंट में एक तर्क दोष का विश्लेषण जो स्थानीय हमलावर को क्लाइंट पासफ्रेज़ के संपर्क में लाता है
यह दस्तावेज़ macOS पर ssh बाइनरी में पहचाने गए एक लॉजिक भेद्यता का विश्लेषण (मेरी पहली सॉफ़्टवेयर भेद्यता!) और यह प्रदर्शित करने वाला पैच विश्लेषण प्रस्तुत करता है कि Apple ने भेद्यता को कैसे ठीक किया। मैंने यह मुद्दा 2022 के अंत में Apple Security Bounty कार्यक्रम के माध्यम से Apple को सूचित किया, जिसे बाद में macOS Ventura 13.5 में ठीक किया गया और CVE-2023-42829 (🎉) जारी किया गया। यह मुद्दा macOS उपयोगकर्ता-स्थानीय 'लॉगिन' कीचेन ( com.apple.ssh.passphrases एक्सेस समूह में) में सहेजे गए SSH पासफ़्रेज़ को एक स्थानीय हमलावर को सादे-पाठ में उजागर करने का कारण बनता है।
अस्वीकरण:
यह रिपोर्ट केवल शैक्षिक उद्देश्यों के लिए प्रदान की गई है, जिसमें जिम्मेदार प्रकटीकरण प्रक्रियाओं का पालन किया गया है। विश्लेषण यथास्थिति प्रदान किया गया है, और इस जानकारी के किसी भी आगे के प्रकाशन या उपयोग को जिम्मेदार प्रकटीकरण दिशानिर्देशों का पालन करना चाहिए।
पैच के बाद उच्च-स्तरीय प्रवाह
पैच से पहले उच्च-स्तरीय प्रवाह
com.apple.private.security.clear-library-validation विशेषाधिकार| हार्डवेयर | OS सॉफ्टवेयर |
|---|---|
| MacBook Pro M1 2021 | /usr/bin/ssh @ macOS Ventura बिल्ड 13.0.1 (22A400) |
निम्नलिखित प्रूफ-ऑफ-कॉन्सेप्ट भेद्यता की अपेक्षाकृत सरल शोषणीयता को दर्शाता है, जो ssh बाइनरी के -I फ्लैग में एक डायनामिक लाइब्रेरी पास करता है:
jamesd@local build % ssh -I /Users/jamesd/rome.dylib [email protected]
SSH Private Key Passphrase -> 'SuperSecret!!@@$'
आइए बात करते हैं कि यह कैसे खोजा गया और ऐसा क्यों हुआ!
एक समय की बात है, मैं ssh बाइनरी का उपयोग किसी सामान्य काम के लिए कर रहा था और -i फ्लैग (SSH पहचान फ़ाइल पास करने के लिए) को -I फ्लैग से टाइप किया और निम्नलिखित stdout देखा:
jamesd@local build % ssh -I /Users/jamesd/.ssh/id_rsa something@somewhere
dlopen /Users/jamesd/.ssh/id_rsa failed: dlopen(/Users/jamesd/.ssh/id_rsa, 0x0002): tried: '/Users/jamesd/.ssh/id_rsa' (not a mach-o file), ...
...
ssh बाइनरी के विशेषाधिकारों की जाँच करने के बाद...
jamesd@local build % ldid -e /usr/bin/ssh # /usr/bin/ssh बाइनरी के विशेषाधिकार डंप करें
<key>com.apple.private.security.clear-library-validation</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>com.apple.ssh.passphrases</string>
</array>
...मेरी रुचि बढ़ गई - बाइनरी के पास एक संरक्षित कीचेन एक्सेस समूह (com.apple.ssh.passphrases) से पढ़ने के विशेषाधिकार हैं, com.apple.private.security.clear-library-validation विशेषाधिकार रखता है, और ssh मेरी निजी कुंजी को dlopen() करने का प्रयास कर रहा है?
जैसा कि पता चला, ssh pkcs11 नामक एक चीज़ के माध्यम से रिमोट सिस्टम पर प्रमाणीकरण का समर्थन करता है, जो हार्डवेयर सुरक्षा मॉड्यूल (HSMs) पर क्रिप्टोग्राफ़िक संचालन के लिए एक मानक है (https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-library.html).
हमें इस लेख के प्रयोजनों के लिए pkcs11 की विशिष्टताओं के बारे में चिंता करने की आवश्यकता नहीं है, सिवाय इस तथ्य के कि क्लाइंट ssh -I को एक pkcs11 (डायनामिक लाइब्रेरी) लाइब्रेरी प्रदान करता है।
com.apple.private.security.clear-library-validation विशेषाधिकारहालांकि अवधारणात्मक रूप से समतुल्य, com.apple.private.security.clear-library-validation पिछले समतुल्य विशेषाधिकार (com.apple.security.cs.disable-library-validation) से भिन्न है क्योंकि com.apple.private.security.clear-library-validation के लिए आपको csops() सिस्कॉल को CS_OPS_CLEAR_LV पास करके कॉल करना होता है ताकि लाइब्रेरी सत्यापन को सक्षम/अक्षम करने पर नियंत्रण रखा जा सके और रनटाइम पर प्रक्रिया अखंडता पर अधिक नियंत्रण बनाए रखा जा सके ( com.apple.private.security.clear-library-validation की तुलना में जो संभवतः आपको बिना किसी नियंत्रण के कोई भी लाइब्रेरी लोड करने की अनुमति देगा)। (https://github.com/apple-oss-distributions/xnu/blob/main/bsd/kern/kern_proc.c) (https://theevilbit.github.io/posts/com.apple.private.security.clear-library-validation/)
चूंकि हमारी लाइब्रेरी को dlopen() करने से पहले csops(CS_OPS_CLEAR_LV) कॉल किया जाता है, हमारी लाइब्रेरी बस लोड हो जाती है और कंस्ट्रक्टर निष्पादित हो जाता है, जिससे हम एक दुर्भावनापूर्ण डायनामिक लाइब्रेरी को pkcs11 लाइब्रेरी के रूप में प्रस्तुत कर सकते हैं और /usr/bin/ssh के संदर्भ से कोड निष्पादित कर सकते हैं और keychain-access-groups विशेषाधिकार का उपयोग कर सकते हैं।
शायद पैच में csops() को कॉल करने से पहले बाइनरी पर विशिष्ट विश्वसनीय हस्ताक्षर पहचानों की जाँच करने के लिए की गई जाँचें शामिल थीं?
नहीं!
पैच रिलीज़ (22G74) के बाद, मैंने pkcs11_add_provider() (वह विधि जिसमें dlopen() कॉल किया जाता है) के असुरक्षित कार्यान्वयन की तुलना की और यह पैच रिलीज़ के समान दिखाई दिया - लेकिन /usr/bin/ssh में एक विशेषाधिकार गायब है?
<?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>keychain-access-groups</key>
<array>
<string>com.apple.ssh.passphrases</string>
</array>
</dict>
</plist>
लेकिन निश्चित रूप से Apple ने SSH से pkcs11 समर्थन नहीं हटाया है? मैंने अपने PoC का उपयोग करके भेद्यता का फिर से शोषण करने का प्रयास किया और पाया कि हालांकि मेरी लाइब्रेरी लोड हो गई थी, यह अब कीचेन एक्सेस समूह से नहीं पढ़ सकती थी और /usr/libexec/ssh-apple-pkcs11 (एक बाइनरी जो मैंने पहले नहीं देखी थी) के संदर्भ में निष्पादित हो रही थी, जिसके पास निम्नलिखित विशेषाधिकार हैं:
<?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.private.security.clear-library-validation</key>
<true/>
</dict>
</plist>
CS_OPS_CLEAR_LV के लिए csops() सिस्कॉल में एक टिप्पणी (https://github.com/apple-oss-distributions/xnu/blob/main/bsd/kern/kern_proc.c) में CS_OPS_CLEAR_LV के संयोजन में उपयोग करने के बजाय, लाइब्रेरी सत्यापन के बिना एक बाइनरी में पुनः-निष्पादित (re-exec) करने का उल्लेख किया गया है। तो यदि अब एक अतिरिक्त सहायक बाइनरी है, तो /usr/bin/ssh में pkcs11_add_provider() में तार्किक रूप से दोषपूर्ण रूटीन अभी भी क्यों मौजूद है? और पैच में कार्यान्वयन अपरिवर्तित क्यों दिखाई देता है?
खैर, जैसा कि पता चला, पैच में एक सहायक बाइनरी जोड़ना शामिल नहीं था, और इसमें macOS में दो ssh बाइनरी वितरित करना शामिल था: /usr/bin/ssh और /usr/libexec/ssh-apple-pkcs11 - दोनों अपने विशेषाधिकारों के अलावा समान हैं (मैंने इसे सत्यापित करने के लिए Diaphora का उपयोग किया):
पैच किए गए ssh बाइनरी पर कुछ डायनामिक विश्लेषण करने के बाद, ssh के (बल्कि बड़े) start() रूटीन में एक अतिरिक्त जाँच जोड़ी गई थी, जिसका उपयोग pkcs11 सुविधाओं के उपयोग पर यह निर्धारित करने के लिए किया जाता है कि बाइनरी /usr/bin/ssh या /usr/libexec/ssh-apple-pkcs11 के संदर्भ में निष्पादित हो रही है या नहीं:
हरे ब्लॉक में, हम SecTaskCopyValueForEntitlement() (पास किया गया मान "com.apple.private.security.clear-library-validation" है) पर एक कॉल देख सकते हैं, जिसका मूल्यांकन (नारंगी ब्लॉक में) किया जाता है और यदि वर्तमान कार्य/प्रक्रिया के लिए "com.apple.private.security.clear-library-validation" विशेषाधिकार मौजूद नहीं है (लाल ब्लॉक) तो यह पुनः-निष्पादन रूटीन के लिए एक सशर्त कॉल का कारण बनता है।
इसके परिणामस्वरूप उपयोगकर्ता-आपूर्ति की गई pkcs11 लाइब्रेरी लोड करते समय कम विशेषाधिकार वाली ssh-apple-pkcs11 बाइनरी का उपयोग किया जाता है (प्रभावी रूप से ssh की कीचेन-संबंधित सुविधाओं को अक्षम करता है), और ssh का उपयोग वहाँ किया जाता है जहाँ अविश्वसनीय लाइब्रेरी लोड नहीं की जानी हैं ( ssh की कीचेन-संबंधित सुविधाओं को सक्षम करता है)।
हम पैच किए गए ssh बाइनरी को डीबग करके भी इसे सत्यापित कर सकते हैं।
यदि हम पैच किए गए ssh बाइनरी (macOS 22G74 में वितरित) को डीबग करते हैं और execv() पर ब्रेकपॉइंट सेट करते हैं, तो हम वास्तव में -I फ्लैग प्रदान करने पर execv() के लिए एक कॉल देख सकते हैं, जो ssh को pkcs11 सुविधाओं के उपयोग के बिना लॉन्च करने पर नहीं होती है:
मैंने यह मुद्दा 2022 के अंत में Apple Security Bounty कार्यक्रम के माध्यम से Apple को सूचित किया और बाद में macOS Ventura 13.5 में इसे ठीक किया गया और CVE-2023-42829 (🎉) जारी किया गया।
यह लेख एक स्वतंत्र प्रकाशन है और इसका Apple Inc. द्वारा अधिकृत, प्रायोजित या अन्यथा अनुमोदित नहीं किया गया है। macOS, iOS और iWork Apple Inc. के ट्रेडमार्क हैं।