
CVE-2019-5736 के लिए PoC
CVE-2019-5736 के लिए PoC
की सहायता से बनाया गया @singe, @_cablethief, और @feexd
Ubuntu 18.04, Debian 9, और Arch Linux पर परीक्षण किया गया। Docker संस्करण 18.09.1-ce और 18.03.1-ce। यह PoC वर्तमान में Ubuntu 16.04 और CentOS के साथ काम नहीं करता है।
Dragon Sector (जिन्होंने कमजोरी की खोज की) से एक्सप्लॉइट कोड देखें यहाँ।
यह CVE-2019-5736 का Go कार्यान्वयन है, जो Docker के लिए एक कंटेनर एस्केप है। एक्सप्लॉइट कंटेनर के अंदर से होस्ट सिस्टम के runc बाइनरी को ओवरराइट और निष्पादित करके काम करता है।
एक्सप्लॉइट के 2 उपयोग मामले हैं। पहला (जो इस रिपॉजिटरी में है), मूलतः एक जाल है। हमलावर को कंटेनर के अंदर कमांड निष्पादन प्राप्त करना होगा और एक दुर्भावनापूर्ण बाइनरी शुरू करनी होगी जो सुनेगी। जब कोई (हमलावर या पीड़ित) कंटेनर में प्रवेश करने के लिए docker exec का उपयोग करता है, तो यह एक्सप्लॉइट को ट्रिगर करेगा जो रूट के रूप में कोड निष्पादन की अनुमति देगा।

दूसरा (जो नहीं है यह रिपॉजिटरी), एक दुर्भावनापूर्ण Docker इमेज बनाता है। जब वह इमेज चलाई जाती है, एक्सप्लॉइट सक्रिय हो जाता है। कंटेनर में exec करने की आवश्यकता नहीं है। gif उदाहरण के लिए इस रीडमी के नीचे देखें।
इस कमजोरी का शोषण करने के लिए आपको कंटेनर के अंदर रूट (uid 0) होना आवश्यक है।
हाँ, आप अपने runc के कार्यान्वयन को ओवरराइट कर देंगे जिससे आपका सिस्टम Docker कंटेनर चलाने में असमर्थ हो जाएगा। कृपया /usr/bin/docker-runc या /usr/bin/runc (इस पर निर्भर करता है कि आपके पास कौन सा है; /usr/sbin भी जांचें) का बैकअप लें।
कोड को अपनी इच्छानुसार संशोधित करें और go build main.go से संकलित करें। उस बाइनरी को उस कंटेनर में ले जाएं जिससे आप बचना चाहते हैं। बाइनरी निष्पादित करें, और फिर अगली बार जब कोई इससे जुड़ता है और /bin/sh कॉल करता है, तो आपका पेलोड सक्रिय हो जाएगा।
यह PoC lxc प्रोजेक्ट की इस कमिट (और दूसरों से कुछ सहायक सलाह) के उत्कृष्ट स्पष्टीकरण का उपयोग करके बनाया गया था।
उदाहरण के तौर पर, यदि लक्ष्य बाइनरी /bin/bash था, तो इसे एक निष्पादन योग्य स्क्रिप्ट से बदला जा सकता है जो इंटरप्रेटर पथ #!/proc/self/exe निर्दिष्ट करती है (/proc/self/exec कर्नेल द्वारा प्रत्येक प्रक्रिया के लिए बनाया गया एक प्रतीकात्मक लिंक है जो उस प्रक्रिया के लिए निष्पादित बाइनरी की ओर इशारा करता है)। इस प्रकार जब /bin/bash कंटेनर के अंदर निष्पादित होता है, तो इसके बजाय /proc/self/exe का लक्ष्य निष्पादित होगा - जो होस्ट पर runc बाइनरी की ओर इशारा करेगा।
हम इसे कंटेनर में /bin/sh को #!/proc/self/exe से ओवरराइट करके लागू करते हैं जो इस प्रक्रिया को शुरू करने वाली बाइनरी (Docker exec) की ओर इशारा करेगा।

हमलावर तब /proc/self/exe के लक्ष्य पर लिखने का प्रयास कर सकता है ताकि होस्ट पर runc बाइनरी को ओवरराइट कर सके। हालांकि, सामान्यतः यह सफल नहीं होगा क्योंकि कर्नेल इसे तब ओवरराइट होने की अनुमति नहीं देगा जब runC निष्पादित हो रहा है। इसे दूर करने के लिए, हमलावर इसके बजाय O_PATH फ्लैग का उपयोग करके /proc/self/exe के लिए फ़ाइल डिस्क्रिप्टर खोल सकता है और फिर /proc/self/fd/ के माध्यम से बाइनरी को O_WRONLY के रूप में फिर से खोल सकता है और एक अलग प्रक्रिया से बिजी लूप में उस पर लिखने का प्रयास कर सकता है।
नोट: पिछले अनुभाग के कुछ भाग पूरी तरह से सटीक नहीं हैं। runcinit के लिए फ़ाइल डिस्क्रिप्टर प्राप्त करते समय आपको O_PATH फ्लैग का उपयोग करने की आवश्यकता नहीं है। इसके अतिरिक्त आपको दूसरी प्रक्रिया में राइट लूप बनाने की आवश्यकता नहीं है। हम /proc/PID/exe के लिए फ़ाइल हैंडल प्राप्त करके runcinit के लिए फ़ाइल डिस्क्रिप्टर प्राप्त करते हैं। वहां से, हम फिर उस हैंडल का उपयोग करके /proc/self/fd/FILEDESCRIPTOR के लिए फ़ाइल हैंडल प्राप्त करते हैं। यह फ़ाइल हैंडल है जिसका उपयोग हम लिखने के लिए करेंगे।

अंततः यह तब सफल होगा जब runC बाइनरी बाहर निकलती है। इसके बाद runC बाइनरी से समझौता हो जाता है और इसका उपयोग अन्य कंटेनरों या होस्ट पर हमला करने के लिए किया जा सकता है।
यदि हम उस फ़ाइल हैंडल पर लिखने में सक्षम हैं तो हमने होस्ट पर runc बाइनरी को ओवरराइट कर दिया है। हम रूट के रूप में मनमाने कमांड निष्पादित करने में सक्षम हैं।
इस रिपॉजिटरी में यह उदाहरण शामिल नहीं है लेकिन आप इसे यहाँ पा सकते हैं। मेरी राय में, यह कहीं अधिक खतरनाक परिदृश्य है। बस दुर्भावनापूर्ण कंटेनर इमेज चलाएं और आपको रूट के रूप में कोड निष्पादन मिलता है। विस्तृत स्पष्टीकरण के लिए कृपया यह देखें।
