
CVE-2024-38063 के लिए poc (tcpip.sys में RCE)
यह CVE-2024-38063 के लिए एक (थोड़ा अस्थिर) पीओसी है, जो tcpip.sys में एक RCE है जिसे 13 अगस्त 2024 को पैच किया गया था। मुझे यह भेद्यता नहीं मिली और न ही रिपोर्ट की, वह श्रेय Wei को जाता है।
pip3 install scapy
स्क्रिप्ट में फ़ील्ड्स को संशोधित करें:
iface <- यदि आपके पास एकाधिक एडेप्टर हैं, तो आपको चुनना होगा कि पैकेट भेजने के लिए किसका उपयोग करना है। उदाहरण के लिए लिनक्स पर "eth0" या विंडोज़ पर "Hyper-V Virtual Ethernet Adapter"। यदि आप अपने डिफ़ॉल्ट इंटरफ़ेस का उपयोग करने जा रहे हैं, तो इसे खाली छोड़ दें।ip_addr <- लक्ष्य प्रणाली का IP पता (IPv6)num_tries & num_batches <- भेजने के लिए कितने अलग-अलग पैकेट बैच। उनमें से अधिक = अधिक हीप भ्रष्टाचार का कारण + भेद्यता को ट्रिगर करने की अधिक संभावना।mac_addr <- खाली छोड़ें, जब तक कि scapy शिकायत न करे कि उसे मैक पता नहीं मिल रहा है। समस्या निवारण में नीचे देखें।स्क्रिप्ट चलाएँ:
python3 cve-2024-38063.py
भेद्यता को पुनः उत्पन्न करने का सबसे आसान तरीका लक्ष्य प्रणाली पर bcdedit /set debug on का उपयोग करना और मशीन/VM को पुनरारंभ करना है। यह डिफ़ॉल्ट नेटवर्क एडेप्टर ड्राइवर kdnic.sys बनाता है, जो पैकेट को सम्मिलित करने के लिए बहुत उत्सुक है। यदि आप किसी भिन्न सेटअप पर भेद्यता को पुनः उत्पन्न करने का प्रयास कर रहे हैं, तो आपको सिस्टम को ऐसी स्थिति में लाना होगा जहां वह आपके द्वारा भेजे गए पैकेट को सम्मिलित करेगा। अधिक विवरण के लिए आप नीचे समस्या निवारण अनुभाग पढ़ सकते हैं।
यदि आप तकनीकी विवरणों में रुचि रखते हैं, तो आप Marcus द्वारा भेद्यता का यह शानदार विश्लेषण पढ़ सकते हैं। नीचे मैंने जो विवरण लिखे हैं, वे गंभीर तकनीकी विश्लेषण के बजाय सारांश के रूप में काम करने के लिए हैं।
NET_BUFFER ऑब्जेक्ट होता है जिसमें बफ़र्ड पैकेट डेटा होता है। ऑफ़सेट 0x30 पर हमारे पास एक current-offset फ़ील्ड भी है जो इंगित करता है कि पैकेट को कितना पार्स किया गया है। इस चरण में, ऑफ़सेट मान आम तौर पर 0x28 होगा, यह दर्शाता है कि IPv6 हेडर पार्स किया गया है लेकिन कुछ और नहीं।tcpip!Ipv6pReceiveDestinationOptions में "destination options" एक्सटेंशन हेडर को संसाधित किया जाता है, तो एक पार्सिंग त्रुटि के परिणामस्वरूप tcpip!IppSendErrorList को कॉल किया जाएगा। यह फ़ंक्शन लिंक्ड लिस्ट में प्रत्येक पैकेट ऑब्जेक्ट (वर्तमान से शुरू) पर tcpip!IppSendError को कॉल करता है।tcpip!IppSendError के दुष्प्रभाव होते हैं। यह बफ़र्ड पैकेट डेटा को वापस शुरुआत में "वापस लाता है" और current-offset फ़ील्ड को शून्य पर रीसेट करता है।0x8C)। इसका मतलब है कि ड्राइवर लिंक्ड लिस्ट में अन्य पैकेटों के एक्सटेंशन हेडर को पार्स करना जारी रखेगा, भले ही उन्हें IppSendError में "वापस लाया" गया हो।0x28 के बजाय शून्य है।Ipv6pReceiveFragment का उपयोग करते हैं। फ़ंक्शन खंड विस्तार हेडर को पार्स करता है और मानता है कि पैकेट में गैर-हेडर डेटा की लंबाई की गणना करते समय पैकेट का ऑफ़सेट फ़ील्ड कम से कम 0x28 होगा, जो वर्तमान ऑफ़सेट मान से 0x30 घटाकर किया जाता है। यह मान तब पुनः जोड़ने वाली वस्तु में संग्रहीत किया जाता है जिसका उद्देश्य खंडित पैकेट को फिर से जोड़ना है।IppSendError द्वारा वापस लाया गया है। ऑफ़सेट मान शून्य होगा और Ipv6pReceiveFragment में पहले कहीं 8 तक बढ़ा दिया जाएगा। गैर-हेडर डेटा के आकार की गणना करते समय, मान अंडरफ़्लो होगा और 0xffd8 के बराबर होगा (घटाव 16 बिट में किया जाता है)।Ipv6pReassembleDatagram, जहां इसका उपयोग पुनः जुड़े पैकेट के आउटपुट बफर की लंबाई की गणना करने के लिए किया जाता है। हालाँकि, सभी गणनाएँ 32-बिट में की जाती हैं और एक सैनिटी चेक होता है कि कुल लंबाई 0xFFFF से अधिक नहीं है, जो इस मामले में होता है।Ipv6pReassemblyTimeout, जहां इसी तरह से इसका उपयोग किया जाता है। हालाँकि, यहाँ गणना 16 बिट में की जाती है और एक पूर्णांक ओवरफ़्लो होता है। इससे बाद में बफर में डेटा कॉपी करते समय बफर ओवरफ़्लो होता है।Ipv6pReassemblyTimeout को ट्रिगर करने के लिए, खंड के भेजने वाले को 1 मिनट तक निष्क्रिय रहना होगा। तब हमारी रणनीति है:
IppSendError को ट्रिगर करने के लिए दूषित गंतव्य विकल्प भेजें, उसके बाद एक खंड पैकेट भेजेंIpv6pReceiveFragment में अंडरफ़्लो का कारण बनें और उच्च 16-बिट मान के साथ एक नया पुनः जोड़ने वाला ऑब्जेक्ट बनाएं जिसमें खंड डेटा लंबाई होIpv6pReassemblyTimeout ट्रिगर हो।Ipv6pReassemblyTimeout में बफर आकार गणना में पूर्णांक ओवरफ़्लो का कारण बनें और हीप-आधारित बफर ओवरफ़्लो ट्रिगर करें।स्क्रिप्ट में पैकेटों को स्पैम किया जाता है ताकि उनके सम्मिलित होने की अधिक संभावना हो। मुख्य पेलोड काफी सरल है:
हम IPv6 हेडर में hop limit और flow label फ़ील्ड को मैन्युअल रूप से भी सेट करते हैं। याद रखें कि बफ़र्ड पैकेट डेटा भेद्यता के कारण रीसेट हो जाता है। इसका मतलब है कि, खंड पैकेट को संसाधित करते समय, IPv6 हेडर को खंड हेडर डेटा के रूप में व्याख्यायित किया जाएगा। IPv6 हेडर में hop limit फ़ील्ड को खंड हेडर में id फ़ील्ड के एक बिट के रूप में व्याख्यायित किया जाएगा। इसे बदलकर, हम सुनिश्चित करते हैं कि हम कई अलग-अलग खंडों के लिए भेद्यता को ट्रिगर करते हैं और कई अलग-अलग भ्रष्टाचार का कारण बनते हैं, जिससे क्रैश की संभावना बढ़ जाती है (आखिरकार यह एक PoC ही है)। ip हेडर का flow limit फ़ील्ड खंड हेडर के ऑफ़सेट और "more indicator" फ़ील्ड के रूप में व्याख्यायित किया जाएगा। इसे 1 पर सेट करके, हम संकेत देते हैं कि आने वाले और हेडर हैं (इसलिए बाद में Ipv6pReassemblyTimeout को ट्रिगर करने में सक्षम) और ऑफ़सेट शून्य है (क्योंकि यह ऐसी id वाला पहला पैकेट है जो आ रहा है)।
Ipv6pReassemblyTimeout में हम जिस कोड पथ का उपयोग कर रहे हैं, उसके लिए आवश्यक है कि मूल खंड पैकेट को यूनिकास्ट के रूप में भेजा जाए।यदि यह काम नहीं कर रहा है, तो इसका कारण हो सकता है:
Ether(raw(sr1(IPv6(dst={your_dest_ip})/ICMPv6EchoRequest()))).src, लेकिन यह कभी-कभी काम नहीं करताtcpip!Ipv6pReceiveDestinationOptions -> tcpip!Ipv6pProcessOptions -> tcpip!IppSendErrorList हिट हो रहा है?tcpip!Ipv6pProcessOptions पर ब्रेक लगाएं और जांचें कि क्या [rcx] हर समय शून्य है। यदि हाँ, तो पैकेट किसी कारण से सम्मिलित नहीं हो रहे हैं।tcpip!Ipv6pReceiveFragment पर ब्रेक लगाएं और जांचें कि क्या [rcx+0x30] शून्य के बराबर है। यदि नहीं, तो भेद्यता किसी कारण से ट्रिगर होने में विफल रही।