
Android Binder UAF के लिए अवधारणा-प्रमाण LPE एक्सप्लॉइट जो मनमाना कर्नेल रीड/राइट प्राप्त करने के लिए iovec स्प्रेइंग और addr_limit ओवरराइट का उपयोग करता है।
CVE-2019-2215 को लक्षित करने वाला एक पुनर्लिखित Proof-of-Concept / स्थानीय विशेषाधिकार वृद्धि (LPE) एक्सप्लॉइट, जो Android Binder ड्राइवर में एक Use-After-Free भेद्यता है।
मैंने vulnerable_kernel_builds फ़ोल्डर में भेद्य कर्नेल बिल्ड प्रदान किया है। एक Android 10 AOSP एमुलेटर बनाएं और इसके साथ कर्नेल चलाएं
emulator -show-kernel -no-window -no-snapshot -wipe-data -avd research -kernel bzImage
बग के तकनीकी विवरण के लिए आप इस शानदार ब्लॉग से सीख सकते हैं: https://projectzero.google/2019/11/bad-binder-android-in-wild-exploit.html
task_struct संरचना में mm_segment_t प्रकार का एक महत्वपूर्ण सदस्य addr_limit होता है। addr_limit उच्चतम मान्य यूज़र स्पेस पता संग्रहीत करता है। addr_limit, लक्षित आर्किटेक्चर के आधार पर struct thread_info या struct thread_struct का हिस्सा होता है। चूँकि हम अब x86_64 बिट सिस्टम से निपट रहे हैं, addr_limit को struct thread_struct में परिभाषित किया गया है।

यदि हम इस addr_limit को 0xFFFFFFFFFFFFFFFF से क्लोबर कर सकते हैं, तो हम कर्नेल स्पेस मेमोरी के किसी भी हिस्से को पढ़ और लिख सकेंगे। एक्सप्लॉइट की x86_64 और arm64 पर बेहतर संगतता के लिए, addr_limit को 0xFFFFFFFFFFFFFFFE पर सेट करना बेहतर है।
struct iovec का उपयोग Vectored I/O के लिए किया जाता है, जिसे Scatter/Gather I/O भी कहा जाता है। struct iovec के साथ मुख्य समस्याओं में से एक यह है कि वे अल्पकालिक होते हैं। जब सिस्टम कॉल बफ़र्स के साथ काम कर रहे होते हैं तो उन्हें आवंटित किया जाता है, और यूज़र मोड में लौटते ही तुरंत मुक्त कर दिया जाता है।
हम चाहते हैं कि जब हम unlink ऑपरेशन को ट्रिगर करें और iov_base पॉइंटर को binder_thread->wait.head के पते के साथ ओवरराइट करें, तो iovec संरचना कर्नेल में बनी रहे, ताकि स्कोप्ड रीड और राइट प्राप्त हो सके। एक तरीका pipe फ़ाइल डिस्क्रिप्टर पर readv, writev जैसे सिस्टम कॉल का उपयोग करना है, क्योंकि यदि pipe भरा या खाली है तो यह ब्लॉक हो सकता है। pipe एक यूनिडायरेक्शनल डेटा चैनल है जिसका उपयोग इंटरप्रोसेस संचार के लिए किया जा सकता है। pipe की ब्लॉकिंग विशेषता हमें कर्नेल स्पेस में iovec संरचना को दूषित करने के लिए एक महत्वपूर्ण समय-खिड़की देती है।
इसी तरह, हम flag पैरामीटर के रूप में MSG_WAITALL पास करके recvmsg सिस्टम कॉल को ब्लॉक करने के लिए उपयोग कर सकते हैं।
चूँकि binder_thread संरचना का आकार 408 बाइट्स है, यह kmalloc-512 कैश में समाप्त होगी।

हमें डैंगलिंग चंक को पुनः आवंटित करने के लिए 25 iovec संरचनाओं को स्टैक करना होगा। 408 / 16 = 25.5

जैसा कि हम उपरोक्त छवि से देख सकते हैं, iovecStack[10].iov_len और iovecStack[11].iov_base क्लोबर हो जाएंगे।

इसलिए, हम iovecStack[10] को प्रोसेस करना चाहेंगे, writev सिस्टम कॉल को ब्लॉक करना चाहेंगे और फिर unlink ऑपरेशन को ट्रिगर करना चाहेंगे। यह सुनिश्चित करेगा कि जब iovecStack[11].iov_base क्लोबर हो जाए, तो हम writev सिस्टम कॉल को फिर से शुरू कर सकें। फिर अंत में, binder_thread चंक की सामग्री को वापस यूज़र स्पेस में लीक करें और उसमें से task_struct पॉइंटर पढ़ें।

स्कोप्ड write प्राप्त करने के लिए, हम flag पैरामीटर के रूप में MSG_WAITALL पास करके recvmsg सिस्टम कॉल को ब्लॉक करने के लिए उपयोग करने जा रहे हैं। recvmsg सिस्टम कॉल, writev सिस्टम कॉल की तरह ही ब्लॉक हो सकता है।

चूँकि mm_segment_t का आकार 0x8 बाइट्स है, हम इसे 0xFFFFFFFFFFFFFFFE से क्लोबर करना चाहेंगे, क्योंकि यह उच्चतम मान्य कर्नेल स्पेस पता है और arm64 सिस्टम में पेज फॉल्ट होने पर प्रोसेस क्रैश नहीं करेगा।

