
CVE-2021-3156 के लिए तकनीकी विश्लेषण और एक्सप्लॉइट विकास, जो Sudo में एक हीप-आधारित बफर ओवरफ्लो है, जिसमें प्रमुख Linux वितरणों पर स्थानीय विशेषाधिकार वृद्धि के लिए तीन कार्यशील एक्सप्लॉइट शामिल हैं।
Qualys Security Advisory
Baron Samedit: Sudo में हीप-आधारित बफर ओवरफ्लो (CVE-2021-3156)
सारांश विश्लेषण शोषण आभार समयरेखा
हमने Sudo (https://www.sudo.ws/) में एक हीप-आधारित बफर ओवरफ्लो खोजा। यह भेद्यता:
बिना प्रमाणीकरण के किसी भी स्थानीय उपयोक्ता (सामान्य उपयोक्ता और सिस्टम उपयोक्ता, sudoers और non-sudoers) द्वारा शोषण योग्य है (अर्थात, आक्रमणकारी को उपयोक्ता का पासवर्ड जानने की आवश्यकता नहीं है);
जुलाई 2011 (कमिट 8255ed69) में पेश की गई थी, और अपनी डिफ़ॉल्ट कॉन्फ़िगरेशन में सभी विरासत संस्करणों 1.8.2 से 1.8.31p2 तक और सभी स्थिर संस्करणों 1.9.0 से 1.9.5p1 तक को प्रभावित करती है।
हमने इस भेद्यता के लिए तीन अलग-अलग शोषण विकसित किए, और Ubuntu 20.04 (Sudo 1.8.31), Debian 10 (Sudo 1.8.27), और Fedora 33 (Sudo 1.9.2) पर पूर्ण रूट विशेषाधिकार प्राप्त किए। अन्य ऑपरेटिंग सिस्टम और वितरण भी संभवतः शोषण योग्य हैं।
यदि Sudo को "shell" मोड (shell -c command) में एक कमांड चलाने के लिए निष्पादित किया जाता है:
या तो -s विकल्प के माध्यम से, जो Sudo का MODE_SHELL फ़्लैग सेट करता है;
या -i विकल्प के माध्यम से, जो Sudo के MODE_SHELL और MODE_LOGIN_SHELL फ़्लैग सेट करता है;
तो, Sudo के main() की शुरुआत में, parse_args() सभी कमांड-लाइन तर्कों को जोड़कर (पंक्तियाँ 587-595) और सभी मेटा-वर्णों को बैकस्लैश से एस्केप करके (पंक्तियाँ 590-591) argv को फिर से लिखता है (पंक्तियाँ 609-617):
बाद में, sudoers_policy_main() में, set_cmnd() कमांड-लाइन तर्कों को हीप-आधारित बफर "user_args" में जोड़ता है (पंक्तियाँ 864-871) और मेटा-वर्णों को अन-एस्केप करता है (पंक्तियाँ 866-867), "sudoers मिलान और लॉगिंग प्रयोजनों के लिए":
दुर्भाग्य से, यदि कोई कमांड-लाइन तर्क एक एकल बैकस्लैश वर्ण के साथ समाप्त होता है, तो:
पंक्ति 866 पर, "from[0]" बैकस्लैश वर्ण है, और "from[1]" तर्क का null टर्मिनेटर है (अर्थात, स्पेस वर्ण नहीं);
पंक्ति 867 पर, "from" को बढ़ाया जाता है और यह null टर्मिनेटर की ओर इंगित करता है;
पंक्ति 868 पर, null टर्मिनेटर को "user_args" बफर में कॉपी किया जाता है, और "from" को फिर से बढ़ाया जाता है और यह null टर्मिनेटर के बाद के पहले वर्ण की ओर इंगित करता है (अर्थात, तर्क की सीमा से बाहर);
पंक्तियों 865-869 पर "while" लूप सीमा से बाहर के वर्णों को पढ़ता है और "user_args" बफर में कॉपी करता है।
दूसरे शब्दों में, set_cmnd() हीप-आधारित बफर ओवरफ्लो के प्रति संवेदनशील है, क्योंकि "user_args" बफर में कॉपी किए गए सीमा से बाहर के वर्ण इसके आकार (पंक्तियों 852-853 में गणना) में शामिल नहीं थे।
हालाँकि, सिद्धांत रूप में, कोई भी कमांड-लाइन तर्क एक एकल बैकस्लैश वर्ण के साथ समाप्त नहीं हो सकता है: यदि MODE_SHELL या MODE_LOGIN_SHELL सेट है (पंक्ति 858, संवेदनशील कोड तक पहुँचने के लिए एक आवश्यक शर्त), तो MODE_SHELL सेट है (पंक्ति 571) और parse_args() ने पहले ही सभी मेटा-वर्णों को एस्केप कर दिया है, जिसमें बैकस्लैश भी शामिल हैं (अर्थात, इसने प्रत्येक एकल बैकस्लैश को दूसरे बैकस्लैश के साथ एस्केप किया)।
व्यवहार में, हालाँकि, set_cmnd() में संवेदनशील कोड और parse_args() में एस्केप कोड थोड़ी भिन्न स्थितियों से घिरे हैं:
बनाम:
तो हमारा प्रश्न यह है: क्या हम MODE_SHELL और या तो MODE_EDIT या MODE_CHECK सेट कर सकते हैं (संवेदनशील कोड तक पहुँचने के लिए) लेकिन डिफ़ॉल्ट MODE_RUN नहीं (एस्केप कोड से बचने के लिए)?
उत्तर, ऐसा प्रतीत होता है, नहीं है: यदि हम MODE_EDIT (-e विकल्प, पंक्ति 361) या MODE_CHECK (-l विकल्प, पंक्तियाँ 423 और 519) सेट करते हैं, तो parse_args() "valid_flags" से MODE_SHELL को हटा देता है (पंक्तियाँ 363 और 424) और यदि हम MODE_SHELL जैसा अमान्य फ़्लैग निर्दिष्ट करते हैं तो त्रुटि के साथ बाहर निकलता है (पंक्तियाँ 532-533):
लेकिन हमें एक खामी मिली: यदि हम "sudo" के बजाय "sudoedit" के रूप में Sudo निष्पादित करते हैं, तो parse_args() स्वचालित रूप से MODE_EDIT सेट करता है (पंक्ति 270) लेकिन "valid_flags" को रीसेट नहीं करता है, और "valid_flags" में डिफ़ॉल्ट रूप से MODE_SHELL शामिल होता है (पंक्तियाँ 127 और 249):