
CVE-2026-29923 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, pstrip64.sys में BYOVD विशेषाधिकार वृद्धि। IOCTL के माध्यम से भौतिक मेमोरी रीड/राइट का प्रदर्शन करता है ताकि SYSTEM टोकन चुराया जा सके और उन्नत शेल लॉन्च किया जा सके।
अस्वीकरण: यह कोड केवल शैक्षिक और रक्षात्मक अनुसंधान उद्देश्यों के लिए प्रदान किया गया है। इसे कर्नेल शोषण की समझ को बढ़ाने और रक्षकों को समान कमजोरियों से बचाने में मदद करने के लिए लिखा गया था। इस परियोजना का कोई भी अनधिकृत, अवैध या दुर्भावनापूर्ण उपयोग सख्त वर्जित है।
हैश: ab01485bb7c8bc1a9c86096eeea6d31d8fad557bf4d44072b46373d2203faa6e
ड्राइवर नाम: pstrip64.sys
CVE: CVE-2026-29923
"अपना स्वयं का कमजोर ड्राइवर लाएं" (BYOVD) हमला एक पुराना लेकिन बेहद प्रभावी तरीका है जिसके द्वारा हमलावर एक विरासत ड्राइवर का उपयोग करके आधुनिक विंडोज सुरक्षा सुरक्षा को बायपास कर सकते हैं जिसे ऑपरेटिंग सिस्टम अभी भी आधिकारिक रूप से विश्वसनीय मानता है। एक बार ड्राइवर लोड हो जाने के बाद, हमलावर इसकी खामियों का उपयोग करके एक मानक, अनप्रिविलेज्ड प्रक्रिया और पूर्ण सिस्टम-स्तरीय नियंत्रण के बीच की खाई को पाटता है।
इस सप्ताह की शुरुआत में, pstrip64.sys ड्राइवर में एक नई कमजोरी का खुलासा हुआ, जिसे CVE-2026-29923 के रूप में ट्रैक किया गया है। यह ब्लॉग पोस्ट एक्सप्लॉइट के पूरे जीवनचक्र को विस्तार से बताता है: मेरे प्रारंभिक कमजोरी अनुसंधान और प्रूफ ऑफ कॉन्सेप्ट (PoC) के विकास से लेकर अपने वातावरण को सुरक्षित करने वाले रक्षकों के लिए कार्रवाई योग्य शमन रणनीतियों तक।
pstrip64.sys ड्राइवर EnTech Taiwan PowerStrip (संस्करण 3.90.736 तक) से जुड़ा एक विरासत कर्नेल-मोड घटक है। जबकि इसका वैध उद्देश्य उन्नत ग्राफिक्स कार्ड डिस्प्ले ट्वीकिंग को सक्षम करना है, इसके गहरे सिस्टम विशेषाधिकार इसे हमलावरों के लिए एक अत्यधिक आकर्षक लक्ष्य बनाते हैं।
जब कमजोरी का पहली बार खुलासा हुआ, तो मैंने इसके DriverEntry फ़ंक्शन का विश्लेषण करके शुरू किया। यह कर्नेल ड्राइवर के लिए मुख्य प्रारंभिक रूटीन के रूप में कार्य करता है, \Device\PSTRIP64 डिवाइस ऑब्जेक्ट बनाता है और इसे \DosDevices\PSTRIP64 सिम्बोलिक लिंक के माध्यम से उपयोगकर्ता-मोड अनुप्रयोगों के लिए एक्सपोज़ करता है। इससे भी महत्वपूर्ण बात, यह ड्राइवर की डिस्पैच टेबल को कॉन्फ़िगर करता है। वह प्रविष्टि जिसने तुरंत मेरा ध्यान खींचा, वह इंडेक्स 14 (IRP_MJ_DEVICE_CONTROL) पर थी, जो उपयोगकर्ता द्वारा प्रदान किए गए सभी IOCTL अनुरोधों को सीधे sub_11340 हैंडलर फ़ंक्शन में रूट करती है, जो हमारा प्राथमिक रुचि क्षेत्र है।
sub_11340 फ़ंक्शन प्राथमिक IOCTL डिस्पैचर के रूप में कार्य करता है, जो उपयोगकर्ता-मोड से अनुरोधों की व्याख्या करता है।
सभी एक्सपोज़्ड IOCTL में से, 0x80002008 निस्संदेह सबसे दिलचस्प है। जबकि डिफ़ॉल्ट मामले छोटे I/O पोर्ट इंटरैक्शन को संभालते हैं, 0x80002008 sub_11000 के लिए एक गेटवे के रूप में कार्य करता है, SystemBuffer को सीधे इस फ़ंक्शन में पास करके।
यह sub_11000 रूटीन सबूत का मुख्य टुकड़ा है। पहले, यह हमारे उपयोगकर्ता द्वारा प्रदान किए गए पते को लेने और इसे एक वैध सिस्टम भौतिक पते में अनुवाद करने के लिए HalTranslateBusAddress का उपयोग करता है। फिर, यह \Device\PhysicalMemory खोलता है और ZwMapViewOfSection का उपयोग करके इसे मैप करता है। लक्ष्य प्रक्रिया हैंडल को (HANDLE)0xFFFFFFFFFFFFFFFFLL (जो ZwCurrentProcess() का प्रतिनिधित्व करता है) पर हार्डकोड करके, ड्राइवर इस भौतिक मेमोरी को सीधे हमारी कॉलिंग प्रक्रिया के वर्चुअल एड्रेस स्पेस में मैप करता है। महत्वपूर्ण रूप से, यह फिर इस नए मैप किए गए वर्चुअल पते को SystemBuffer में वापस लिखता है ताकि उपयोगकर्ता को वापस किया जा सके, और आधिकारिक तौर पर हमारे एप्लिकेशन को भौतिक मेमोरी को पढ़ने और लिखने के लिए एक सीधा पॉइंटर सौंपता है।
कमजोरी को पूरी तरह से समझ लेने और एक भौतिक रीड/राइट प्रिमिटिव स्थापित करने के बाद, मेरे पास सभी आवश्यक पहेली के टुकड़े हैं। अब, प्रूफ ऑफ कॉन्सेप्ट लिखना शुरू करने का समय है।
नोट: यह PoC विशेष रूप से Windows 10 22H2 वातावरण पर विकसित और परीक्षण किया गया था। चूंकि एक्सप्लॉइट कच्चे भौतिक मेमोरी हेरफेर पर निर्भर करता है, कर्नेल संरचना ऑफसेट और भौतिक मेमोरी सीमाएं वर्तमान में मेरे सेटअप के लिए हार्डकोडेड हैं। इसे अपनी मशीन पर परीक्षण करने के लिए, आपको विंडोज कर्नेल ऑफसेट को अपडेट करना होगा और भौतिक पता स्कैनिंग रेंज को अपने विशिष्ट OS बिल्ड और RAM कॉन्फ़िगरेशन से मिलाने के लिए समायोजित करना होगा।
मेरे एक्सप्लॉइट में पहला कदम ड्राइवर के साथ संचार स्थापित करना है। मैंने ड्राइवर के सिम्बोलिक लिंक (\\.\PSTRIP64) पर CreateFileA को कॉल करके ऐसा किया। एक बार जब मेरे पास एक वैध हैंडल था, तो मुझे पहले विश्लेषित 0x80002008 IOCTL का दुरुपयोग करने का एक साफ तरीका चाहिए था। मैंने MapPhysicalMemory() नामक एक रैपर फ़ंक्शन बनाया। यह फ़ंक्शन मेरे कस्टम PSTRIP_MAP_REQUEST स्ट्रक्ट को लक्ष्य भौतिक पते और मैं जिस मेमोरी चंक को पढ़ना चाहता हूं उसकी लंबाई से भरता है।
फिर मैं इस स्ट्रक्ट को सीधे DeviceIoControl के माध्यम से ड्राइवर को भेजता हूं। यदि सफल होता है, तो ड्राइवर उस भौतिक मेमोरी को सीधे मेरे उपयोगकर्ता-मोड एप्लिकेशन में मैप करता है और OutputResult फ़ील्ड में वर्चुअल बेस पता लौटाता है। अब मैं इस लौटाए गए पते को एक मानक C++ पॉइंटर में बदल सकता हूं, जिससे मुझे सिस्टम की भौतिक RAM तक कच्ची, अनप्रिविलेज्ड पहुंच मिलती है।
मेरे भौतिक रीड/राइट प्रिमिटिव के पूरी तरह से संचालन में आने के बाद, मेरा लक्ष्य कर्नेल डेटा संरचनाओं को ढूंढना था जिनमें प्रक्रिया विशेषाधिकार होते हैं। विंडोज में, प्रत्येक चल रही प्रक्रिया को एक EPROCESS संरचना द्वारा दर्शाया जाता है।
विंडोज कर्नेल पूल में EPROCESS संरचनाओं को पूल टैग नामक एक विशिष्ट 4-बाइट पहचानकर्ता का उपयोग करके आवंटित करता है। प्रक्रियाओं के लिए, यह टैग स्ट्रिंग Proc है (जो हेक्स में 0x636F7250 में अनुवादित होता है)। सिस्टम की भौतिक RAM को स्कैन करके, मैं इस सटीक स्ट्रिंग की खोज कर सकता था।
मेरा एक्सप्लॉइट 0x10000000 से 0x140000000 तक भौतिक मेमोरी स्पेस के माध्यम से लूप करता है, मेमोरी को 2MB चंक (STEP_SIZE = 0x200000) में मैप करता है। मैं प्रत्येक मैप किए गए चंक को एक कच्चे बाइट सरणी में कास्ट करता हूं और इसे 16-बाइट चंक (sizeof(_POOL_HEADER)) में स्कैन करता हूं।
हालांकि, भौतिक मेमोरी में केवल Proc टैग ढूंढना पर्याप्त नहीं है। मेमोरी गड़बड़ है, वह टैग समाप्त प्रक्रिया का अवशेष हो सकता है, या केवल यादृच्छिक डेटा जो हेक्स मान से मेल खाता है। यदि मैं आंख मूंदकर मान लेता कि प्रत्येक Proc टैग एक वैध EPROCESS संरचना है और मेमोरी को संशोधित करना शुरू कर देता, तो मैं तुरंत BSOD का कारण बनता।
स्थिरता सुनिश्चित करने के लिए, मुझे ह्यूरिस्टिक्स का उपयोग करके संरचना को मान्य करना पड़ा। पहले, मैं EPROCESS संरचना की शुरुआत की गणना करता हूं (जो पूल टैग से थोड़ा ऑफसेट बैठता है)। वहां से, मैं एक चल रही प्रक्रिया के लिए कुछ ज्ञात स्थिरांकों की जांच करता हूं:
0x2 (सामान्य प्राथमिकता) है।0x0 है।यदि ये सभी ह्यूरिस्टिक्स पास हो जाते हैं, तो मैं काफी आश्वस्त हो सकता हूं कि मैं एक वैध, सक्रिय प्रक्रिया देख रहा हूं। फिर मैं इसका अद्वितीय प्रक्रिया आईडी (PID) पढ़ता हूं। यदि PID मेरी अपनी एक्सप्लॉइट प्रक्रिया से मेल खाता है, तो मैं इसके टोकन पॉइंटर का भौतिक पता सहेजता हूं। यदि PID 4 है (विंडोज System प्रक्रिया), तो मैं इसके अत्यधिक विशेषाधिकार प्राप्त टोकन का वास्तविक मान निकालता और सहेजता हूं।
अंत में, मैं अपनी प्रक्रिया के टोकन पॉइंटर के सहेजे गए भौतिक पते को निकटतम 4KB सीमा पर संरेखित करता हूं और केवल उस विशिष्ट पेज को मैप करने के लिए आखिरी बार MapPhysicalMemory() का उपयोग करता हूं।
इसके बाद, मैं सटीक ऑफसेट पर नेविगेट करता हूं और अपने टोकन को सिस्टम टोकन मान से ओवरराइट करता हूं। तुरंत, विंडोज कर्नेल मेरी एक्सप्लॉइट प्रक्रिया को NT AUTHORITY\SYSTEM के रूप में मानता है।