
DirtyPipe से प्रेरित लिनक्स कर्नेल में एक एक्सप्लॉइट प्रिमिटिव
लिनक्स कर्नेल में DirtyPipe (CVE-2022-0847) से प्रेरित एक exploit primitive।
कुछ दिन पहले, मैंने कई सुरक्षा विशेषज्ञों की तरह DirtyPipe (CVE-2022-0847) कमज़ोरी का अध्ययन और पुनरुत्पादन किया, और इस कमज़ोरी की उपयोगिता को गहराई से महसूस किया। यह कमज़ोरी मेमोरी के एक अनइनिशियलाइज़्ड (uninitialized) मुद्दे से शुरू होती है, और मनमानी फ़ाइलों में संशोधन पर समाप्त होती है; बीच में KASLR leak या ROP, JOP जैसे ऑपरेशन शामिल नहीं होते। इसलिए SMEP, SMAP जैसी सुरक्षाओं को बायपास करने की आवश्यकता नहीं होती।
पुनरुत्पादन के बाद, मैंने सोचना शुरू किया: DirtyPipe कमज़ोरी इतनी उपयोगी क्यों है? क्या DirtyPipe के ठीक होने के साथ, यह केवल एक क्षणभंगुर घटना की तरह होगी, जिसका भविष्य के vulnerability exploitation के लिए कोई सीखने का मूल्य नहीं होगा?
अचानक मुझे एहसास हुआ कि DirtyPipe जिस संरचना में स्थित है — struct pipe_buffer — बहुत परिचित लगती है। आह! क्या यह वही संरचना नहीं है जो GFP_KERNEL_ACCOUNT flag के साथ slab-1k में आवंटित होती है, और जिसमें एक ops फ़ील्ड होता है जिसे मैं अक्सर KASLR leak और RIP hijack के लिए उपयोग करता था?
फिर मुझे लगा कि मैं कितना बेवकूफ़ था, उस समय pipe_buffer के ops को ROP के लिए क्यों बदल रहा था? सीधे pipe_buffer के flags को बदलना और splice के साथ जोड़ना तो पहले ही मनमाना फ़ाइल लेखन कर देता! ऐसा करने पर KASLR leak करने की ज़रूरत नहीं होती, विभिन्न kernel संस्करणों के लिए exploit अनुकूलित करने की ज़रूरत नहीं होती, gadgets की चिंता नहीं होती, और SMEP, SMAP, KPTI जैसी सुरक्षाओं को बायपास करने की भी आवश्यकता नहीं होती।
मैंने तुरंत पहले से CVE-2021-22555 और pipe_buffer संरचना से जुड़े अन्य exploits निकाल लिए जिन्हें मैंने पुनरुत्पादित/सीखा था, थोड़ा संशोधित किया, और तुरंत विभिन्न बिना पैच वाले kernel संस्करणों पर सफलतापूर्वक उपयोग कर लिया। नीचे कुछ उदाहरण हैं:
चूंकि इससे पहले मैंने किसी को इसे Linux kernel exploit में एक primitive के रूप में उपयोग करते नहीं देखा था, इसलिए मैंने अपनी ओर से इसे “Pipe Primitive” नाम दे दिया है XD।
संक्षेप में, हमें Pipe संरचना को संशोधित करने की क्षमता प्राप्त करने की आवश्यकता है, जैसे कि slab-1k के अंतर्गत UAF, या slab-1k के अंतर्गत ऑफसेट के साथ आउट-ऑफ़-बाउंड लेखन (यानी, क्रम से सीधे overflow नहीं)।
इस प्रकार, kernel >= 5.8 में, हमें केवल pipe_buffer में splice पेज के flag |= PIPE_BUF_FLAG_CAN_MERGE को संशोधित करना होगा (यदि संभव हो तो offset और len को भी 0 कर सकते हैं, जिससे फ़ाइल की शुरुआत से लिखना शुरू हो सके); kernel < 5.8 में, पहले pipe_buffer में anon_pipe_ops को leak करना होगा, फिर splice पेज के ops को anon_pipe_ops में बदलना होगा (क्योंकि <5.8 संस्करणों में merge करने की क्षमता ops पर निर्भर करती है) (यदि संभव हो तो offset और len को भी 0 कर सकते हैं)।
और अगर आप पूछें कि कंटेनर एस्केप कैसे करें? मैं जो करना चाहता हूँ वह शायद CVE-2019-5736 के समान ही है XD।