
CVE-2022-3602 के लिए तकनीकी गहन अध्ययन और एंटी-पीओसी, जो OpenSSL 3.0.x में एक पुनिकोड बफर ओवरफ्लो है, प्रतिकृति स्क्रिप्ट, स्टैक विश्लेषण और कंपाइलर शमन मूल्यांकन के साथ।
यह दस्तावेज़ और रिपॉजिटरी CVE−2022-3602 का एक राइट-अप है, जो OpenSSL में एक punycode बफर ओवरफ्लो समस्या है। यह एक "एंटी-पीओसी" है (समस्या शोषण योग्य प्रतीत नहीं होती) जो उन लोगों के लिए है जो अपने स्वयं के OpenSSL बिल्ड का रखरखाव करते हैं और कंपाइलर रखरखावकर्ताओं के लिए।
उसी रिलीज़ में एक अलग CVE, CVE-2022-3786 भी है, जो बफर ओवरफ्लो की ओर ले जाता है, लेकिन उस स्थिति में हमलावर सामग्री को नियंत्रित नहीं कर सकता। यहाँ उस समस्या के लिए कोई प्रतिकृति नहीं है, लेकिन वह समस्या क्रैश के कारण सेवा अस्वीकृति (DoS) का कारण बन सकती है।
क्रैश और बफर ओवरफ्लो कभी भी अच्छे नहीं होते हैं और यदि आप OpenSSL 3.0.x का उपयोग कर रहे हैं, तो जल्द से जल्द अपडेट करना उचित है।
कृपया GitHub issues या pull-requests के माध्यम से किसी भी त्रुटि या चूक की रिपोर्ट करने में संकोच न करें।
ossl_punycode_decode में punycode डिकोडिंग को संभालने के तरीके में एक ऑफ-बाय-वन समस्या है जिसके परिणामस्वरूप 4-बाइट का ओवरफ्लो होता है। यह समस्या केवल तभी उचित है जब OpenSSL एक प्रमाणपत्र श्रृंखला को संसाधित करता है और इसके लिए दो शर्तों की आवश्यकता होती है। पहली, श्रृंखला में एक CA या इंटरमीडियरी प्रमाणपत्र में एक name-constraint फ़ील्ड होना चाहिए जो punycode का उपयोग करता है।
nameConstraints = permitted;email:xn-maccrthaigh-n7a.com
दूसरी, लीफ प्रमाणपत्र में एक SubjectAlternateName (SAN) otherName फ़ील्ड होना चाहिए जो एक SmtpUTF8Mailbox स्ट्रिंग निर्दिष्ट करता है।
otherName = 1.3.6.1.5.5.7.8.9;UTF8:[email protected]
ट्रिगर होने पर, nameConstraints फ़ील्ड में punycode, लेकिन otherName फ़ील्ड में punycode नहीं, कमजोर OpenSSL punycode पार्सिंग द्वारा संसाधित किया जाएगा।
David Benjamin और Matt Caswell ने निर्धारित किया कि nameConstraint जाँच सामान्य प्रमाणपत्र श्रृंखला सत्यापन और हस्ताक्षर सत्यापन के बाद होती है। अधिकांश अनुप्रयोगों के लिए इसका मतलब है कि समस्या को स्व-हस्ताक्षरित प्रमाणपत्र या अमान्य श्रृंखला के साथ ट्रिगर नहीं किया जा सकता है।
ध्यान दें कि openssl के s_client और s_server एप्लिकेशन डिबगिंग के लिए हैं और श्रृंखला के अमान्य होने पर प्रसंस्करण बंद नहीं करते हैं।
एक विश्वसनीय CA या इंटरमीडिएट में दुर्भावनापूर्ण पेलोड होना चाहिए, और उसे लीफ प्रमाणपत्र पर हस्ताक्षर भी करना होगा जो समस्या को ट्रिगर करता है।
कुछ वातावरण ऐसे हो सकते हैं जहाँ अविश्वसनीय पक्ष CA या इंटरमीडिएरी हैं, उदाहरण के लिए एक होस्टिंग सेवा जो ग्राहक-प्रदत्त प्राइवेट CA का समर्थन करती है, लेकिन यह सामान्य नहीं है।
कई अनुप्रयोगों के लिए उत्तर "नहीं" होगा क्योंकि कंपाइलर ने स्टैक को कैसे व्यवस्थित किया है और स्टैक कैनरी / स्टैक कुकीज़, पैडिंग, PIE, FORTIFY_SOURCE जैसी अन्य सुरक्षाओं की उपस्थिति के कारण।
समस्या वास्तव में स्टैक पर 32-बिट के ओवरफ्लो की ओर ले जाती है। यह सीधे शेल कोड निष्पादित करने के लिए पर्याप्त नहीं है, लेकिन यह किसी एप्लिकेशन के नियंत्रण प्रवाह को बदलने के लिए पर्याप्त हो सकता है। उदाहरण के लिए, यदि यह डेटा (या इस डेटा की कॉपी किए गए टुकड़े) एक निष्पादन योग्य स्थान पर स्टैक पर कॉपी किया जाता है, तो X509 प्रमाणपत्र श्रृंखला में एम्बेडेड शेल-कोड पर कूदना संभव हो सकता है।
हर Linux प्लेटफ़ॉर्म पर जिसका मैंने परीक्षण किया, ओवरफ्लो पैडिंग में होता है और हानिरहित है। सिद्धांत रूप में, एक कंपाइलर चर को इस तरह व्यवस्थित कर सकता है कि ओवरफ्लो ossl_a2ulabel फ़ंक्शन के अन्य चरों में से एक में हो।
इनलाइनिंग के आधार पर मौजूद चरों की पूरी सूची है:
outptr, inptr, size, result, tmpptr, delta, seed, utfsize
और मुझे ऐसा लगता है कि उनमें से कोई भी विशेषाधिकार वृद्धि या दिलचस्प नियंत्रण के लिए स्पष्ट मार्ग प्रदान नहीं करता है।
मैंने एक टारबॉल संलग्न किया है जिसमें ऐसे उपकरण हैं जिनका उपयोग सभी चार बाइट्स पर जितना संभव हो उतना नियंत्रण के साथ प्रतिकृतियां और ओवरफ्लो बनाने के लिए किया जा सकता है। संदर्भ प्रतिकृति स्ट्रिंग (xn--ww90271...aaaa) चार बाइट्स को मानों 0xFF 0x0F 0x0F 0x0F के साथ ओवरफ्लो करती है। यदि वह किसी एप्लिकेशन को क्रैश नहीं करता है, तो संभव है (संभावित?) कि वह एप्लिकेशन असुरक्षित नहीं है।
शेल स्क्रिप्ट run-poc का उपयोग एक दुर्भावनापूर्ण प्रमाणपत्र श्रृंखला उत्पन्न करने के लिए किया जा सकता है। ca.cnf से एक दुर्भावनापूर्ण CA प्रमाणपत्र और leaf.cnf से एक ट्रिगरिंग लीफ प्रमाणपत्र उत्पन्न होता है।
CA प्रमाणपत्र निम्नलिखित संदर्भ पेलोड का उपयोग करता है:
xn--ww902716aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
एक python स्क्रिप्ट का उपयोग विभिन्न पेलोड के लिए अन्य punycode स्ट्रिंग उत्पन्न करने के लिए किया जा सकता है।
जब निष्पादित किया जाता है, run-poc एक openssl क्लाइंट और सर्वर चलाएगा और दस बार समस्या का शोषण करने का प्रयास करेगा।
एक कमजोर OpenSSL संभवतः क्रैश हो जाएगा। इसका मतलब यह नहीं है कि OpenSSL का संस्करण RCE के लिए कमजोर है, क्योंकि स्टैक कैनरी और स्टैक कुकी सुरक्षा भी आमतौर पर एक (सुरक्षित) एप्लिकेशन क्रैश का कारण बनती हैं। यह भी ध्यान दें कि यह किसी भी तरह से उसी रिलीज़ में दूसरे CVE की गंभीरता को नहीं बदलता है।
सभी चार ओवरफ्लो बाइट्स पर लगभग पूर्ण नियंत्रण प्राप्त करना आश्चर्यजनक रूप से सूक्ष्म है और इसके लिए OpenSSL के punycode डिकोडर का गैर-मानक / अमान्य punycode के साथ शोषण करना आवश्यक है। संलग्न टारबॉल में एक स्क्रिप्ट है जो सूक्ष्मता को संभालने वाली एक स्ट्रिंग का निर्माण कर सकती है। नीचे बताया गया है कि यह कैसे काम करता है।
सुरक्षा समस्या ossl_punycode_decode() में है
int ossl_punycode_decode(const char *pEncoded, const size_t enc_len,
unsigned int *pDecoded, unsigned int *pout_length)
ossl_punycode_decode को ossl_a2ulabel से बुलाया जाता है। pEncoded बफर अधिक या कम मनमाने आकार का बफर है जो X509 प्रमाणपत्र श्रृंखला से आता है। यह nameConstraint फ़ील्ड में किसी भी "xn--" के बाद आने वाला भाग है। ऐसी प्रमाणपत्र श्रृंखला को पुन: उत्पन्न करने के तरीके के लिए [reproduction] देखें।
pDecoded unsigned int की LABEL_BUF_SIZE आकार की एक सरणी है। LABEL_BUF_SIZE 512 है, और अधिकांश प्लेटफार्मों पर एक unsigned int 4 बाइट चौड़ा होगा। तो अधिकांश प्लेटफार्मों पर pDecoded 2048 बाइट लंबा है।
ossl_punycode_decode() के अंदर समस्या का मूल यह गलत लंबाई जाँच है:
if (written_out > max_out)
max_out *pout_length से मेल खाता है जो हमेशा 512 होता है। और written_out ट्रैक रखता है कि pDecoded में कितने unsigned int लिखे गए हैं। क्योंकि written_out बाद में केवल लिखने के बाद बढ़ाया जाता है, यह दोषपूर्ण जाँच 513 unsigned int को pDecoded में लिखने की अनुमति देती है। अंतिम परिणाम कुछ इस प्रकार दिखता है ...
pDecoded = [ ... , 'X , 'Y' , 'Z' ] 'P'
// Indices 509 510 511
यहाँ, C के सम्मेलन के अनुसार, सूचकांक शून्य-आधारित हैं, इसलिए स्लॉट नंबर 511 सरणी का 512वाँ तत्व है। 'P' एक चार-बाइट पेलोड है जिसे सीमा से बाहर रखा गया है, ossl_a2ulabel() में buf बफर के लिए स्टैक पर आवंटित स्थान से परे, जो कि pDecoded इंगित करता है।
चार बाइट एक छोटा ओवरफ्लो है, और एक nop-sled ले जाने या सीधे शेल कोड निष्पादित करने के लिए पर्याप्त नहीं है, लेकिन किसी एप्लिकेशन के नियंत्रण प्रवाह को बदलने के लिए पर्याप्त है। उदाहरण के लिए, x509 प्रमाणपत्र श्रृंखला में एम्बेडेड शेल-कोड पर कूदना संभव हो सकता है, यह इस बात पर निर्भर करता है कि यह डेटा (या इस डेटा की कॉपी किए गए टुकड़े) कैसे संग्रहीत किया जाता है और क्या वह मेमोरी निष्पादन योग्य है। हालांकि, एक संभावित हमलावर के लिए अभी भी अधिक कठिनाई है।
पहला, कंपाइलर का पैडिंग और स्टैक का संरेखण, या स्टैक कैनरी जैसी सुरक्षा, किसी भी शोषण को पूरी तरह से असंभव बना सकती है।
दूसरा, ossl_punycode_decode() के लिए केवल एक ही रास्ता है और यह रास्ता स्टैक पर एक बफर का उपयोग करता है। यह संभावना नहीं बनाता है कि समस्या का उपयोग अलग-अलग मेमोरी स्थानों में एक साथ 4 बाइट ओवरफ्लो के लिए किया जा सकता है।