
CVE-2022-37969 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, एक Windows कॉमन लॉग फ़ाइल सिस्टम ड्राइवर स्थानीय विशेषाधिकार वृद्धि। यह हीप स्प्रे, टोकन स्टीलिंग और आर्बिट्ररी कर्नेल राइट का प्रदर्शन करके SYSTEM विशेषाधिकार प्राप्त करता है।
authors: Ricardo Narvaja & Daniel Kazimirow (Solid)
केवल प्रदर्शन उद्देश्यों के लिए। पूर्ण एक्सप्लॉइट कमजोर Windows 11 21H2 सिस्टम पर काम करता है।
पहले Zscaler द्वारा प्रकाशित जानकारी पर आधारित कार्यात्मक PoC
व्याख्या लेख देखें Understanding the CVE-2022-37969 Windows Common Log File System Driver Local Privilege Escalation।
एक्सप्लॉइटेशन वॉकथ्रू:
यहाँ उपयोग किया गया परिदृश्य Windows 11 21H2 (OS Build 22000.918) clfs.sys v10.0.22000.918 था
पहला चरण MyLog.blf नामक एक फ़ाइल को पब्लिक फ़ोल्डर (%public%) में बनाना है, CreateLogFile() फ़ंक्शन का उपयोग करके:



फिर यह एक Loop का उपयोग करके रैंडम नामों के साथ कई लॉग फ़ाइलें बनाता है।
और लूप के भीतर, यह हमारे getBigPoolInfo() फ़ंक्शन को कॉल करता है:

यह NtQuerySystemInformation() को कॉल करता है, पहले तर्क के रूप में 0x42 (66 दशमलव) के साथ, यह v5 में बिगपूल में किए गए raids के बारे में जानकारी लौटाएगा, जिसकी संरचना SYSTEM_BIGPOOL_INFORMATION प्रकार की होती है।

हमें इस फ़ंक्शन को दो बार कॉल करना होता है। पहली बार यह एक त्रुटि लौटाएगा, लेकिन यह हमें दूसरी बार कॉल करने के लिए बफर का सही आकार देगा ताकि वांछित जानकारी प्राप्त हो सके।

v5 को SYSTEM_BIG_POOL_INFORMATION संरचना की जानकारी प्राप्त होगी।

बिगपूल में आवंटनों की संख्या, Count नामक पहले फ़ील्ड में संग्रहीत होती है, दूसरे फ़ील्ड में SYSTEM_BIGPOOL_ENTRY संरचनाओं की एक सरणी होती है।

फिर हम सभी संरचनाओं में "Clfs" टैग और आकार 0x7a00 के लिए खोज करेंगे।

यह kernelAddrArray नामक एक सरणी में VirtualAddress संग्रहीत करता है जो प्रत्येक संरचना का पहला फ़ील्ड है जिसमें CLFS टैग और आकार 0x7a00 होता है। अब से, जो पूल दोनों शर्तों को पूरा करते हैं उन्हें "right pools" कहा जाएगा।

प्रत्येक right pool को सरणी में संग्रहीत करने के अलावा, यह अंतिम पाए गए right pool को a2 चर की सामग्री में संग्रहीत करता है, जिसका उपयोग फ़ंक्शन के तर्क के रूप में किया जाता है।

इस प्रकार a2 हमेशा CLFS टैग और आकार 0x7a00 वाले अंतिम बनाए गए right pool की ओर इंगित करता है।
चर v26 हमेशा पिछला पाया गया right pool संग्रहीत करता है क्योंकि getBigPoolinfo() को कॉल करने से पहले यह v24 के बराबर होता है (v26=v24), लेकिन इस कॉल से बाहर निकलते समय v24 को अंतिम पाए गए right pool के साथ अद्यतन किया जाता है, और v26 पिछले पाए गए right pool के साथ रहता है।

फिर यह दोनों पतों को घटाता है, और यदि परिणाम नकारात्मक है, तो संकार्यों को उलट देता है ताकि यह हमेशा सकारात्मक रहे।

इस प्रकार v32 में अंतिम दो पाए गए right pool के VirtualAddress के बीच का अंतर संग्रहीत होगा।
फिर यह कुछ ऐसा ही करता है, इस मामले में v23 शुरू में शून्य होता है इसलिए पहली बार v23=v32 होता है।

अगली बार लूप में v23 का मान अभी भी समान होता है और शून्य नहीं होता, इसलिए यह टूट जाता है और यहाँ आता है।

V32 में अंतिम अंतर होता है और v23 में पिछला अंतर होता है, यदि वे बराबर हैं, तो यह बाहर आता है और एक बढ़ाता है, लेकिन काउंटर को शून्य पर रीसेट कर देता है।
विचार यह है कि CLFS टैग और आकार 0x7a00 के 6 लगातार तुलनाओं को खोजा जाए जिनके अंतर समान हों, और वह अंतर 0x11000 होगा। निष्पादित करते समय हम देखेंगे कि जब यह 6 (क्योंकि यह शुरू से शुरू होता है) समान दूरियों वाले लगातार पाता है तो यह उनके बीच का अंतर मान देगा।


वहाँ हम देखते हैं कि उसे 6 लगातार मिले और वह लॉग फ़ाइलें बनाने के लूप से बाहर निकल गया।
"public" फ़ोल्डर में हम बनाई गई फ़ाइलें देख सकते हैं

हमारा craftFile() फ़ंक्शन मूल फ़ाइल (MyLog.blf) खोलता है और बग को ट्रिगर करने के लिए उसे संशोधित करता है।

फ़ाइल को संशोधित करने के बाद, CRC32 बदलना आवश्यक है, अन्यथा हमें एक दूषित फ़ाइल त्रुटि मिलेगी
यह मान फ़ाइल के ऑफसेट 0x80C पर स्थित है।
