Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2023-28252 | Kitploit
उपकरण/GitHubGitHub/fortra/cve-2023-28252
विशेषाधिकार वृद्धिमेमोरी फोरेंसिकभेद्यता विश्लेषणशोषणरिवर्स इंजीनियरिंगडीबगर्सबाइनरी शोषण
GitHubfortra/cve-2023-28252

CVE-2023-28252

रिपॉजिटरी देखें
184443 साल पहलेKitploit द्वारा समीक्षित

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

फरवरी 2022 से एक नए रैंसमवेयर की सूचना मिली थी जो Windows 0-day भेद्यता का उपयोग करता प्रतीत होता है, Trend Micro द्वारा किए गए शोध के अनुसार।
इस रैंसमवेयर के बारे में अधिक जानकारी इस लिंक पर मिल सकती है।
Kaspersky के विश्लेषण के अनुसार, Nokoyawa रैंसमवेयर समूह ने जून 2022 से Common Log File System (CLFS) ड्राइवर को लक्षित करने वाले अन्य exploits का उपयोग किया है, जिनमें समान लेकिन भिन्न विशेषताएँ हैं, और ये सभी एक ही exploit डेवलपर से जुड़े हैं।
अप्रैल 2023 में जब Microsoft ने पैच जारी किया, तो CVE-2023-28252 को निर्दिष्ट किया गया।
इससे पहले, 2022 में उसी घटक में एक समान बग पर हमने शोध किया था, और इस ब्लॉगपोस्ट में प्रलेखित किया था।

Common Log File System (CLFS) फ़ाइल प्रारूप:

विश्लेषण का सामना करने के लिए, .blf फ़ाइल प्रारूप को जानना आवश्यक है, जिसे CLFS.sys नामक भेद्य Common Log File System ड्राइवर द्वारा संभाला जाता है और जो system32 के भीतर ड्राइवर फ़ोल्डर में होता है।

इस फ़ाइल प्रकार के बारे में अधिक जानकारी नीचे दिए गए लिंक में मिल सकती है:

https://www.zscaler.com/blogs/security-research/technical-analysis-windows-clfs-zero-day-vulnerability-cve-2022-37969-part

https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-the-common-log-file-system

https://github.com/ionescu007/clfs-docs/blob/main/README.md

https://www.coresecurity.com/core-labs/articles/understanding-cve-2022-37969-windows-clfs-lpe

भेद्यता:

यह विश्लेषण Windows 11 21H2, clfs.sys version 10.0.22000.1574 के लिए किया गया है, हालाँकि यह Windows 10 21H2, Windows 10 22H2, Windows 11 22H2 और Windows server 2022 पर भी काम करता है।

पिछले Windows संस्करणों में, कुछ मानों को समायोजित करना आवश्यक है, अन्यथा हम BSOD उत्पन्न कर देंगे।

Microsoft Patch Tuesday अप्रैल 2023.

कंप्यूटर का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरणआप ड्राइवर संस्करण को दिखाए अनुसार जाँच सकते हैं

जब भेद्यता प्रकाशित हुई, अप्रैल 2023 में, मैंने Esteban Kazimirow के साथ CLFS.sys ड्राइवर का रिवर्सिंग करना शुरू किया, हालाँकि इस मामले में केवल पैच का विश्लेषण करना यह अनुमान लगाना बहुत कठिन था कि बग कहाँ था और उसे कैसे ट्रिगर किया जाए, क्योंकि शोषण बहुत जटिल है।

बाद में, एक ब्लॉगपोस्ट प्रकाशित हुआ जिसके लेखक ने एक मैलवेयर नमूने से, HexRays द्वारा डीकंपाइल किए गए कोड के कुछ हिस्से और कुछ जानकारी दिखाई, जिसने मार्गदर्शन किया कि शोषण को कहाँ सामना करना था।

स्पष्ट रूप से प्रदान की गई जानकारी पूरी नहीं थी, लेकिन इस सहायता के बिना PoC और बाद में एक कार्यात्मक exploit बनाना संभव नहीं होता।

समझने में आसानी के लिए, हम पहले समझाएंगे कि PoC कैसे बनाया जाए और फिर हम भेद्यता विश्लेषण करेंगे।

इस ब्लॉगपोस्ट में दो खंड हैं:

PoC बनाना:

1-शोषण के लिए आवश्यक कर्नेल पते प्राप्त करें

2-.blf फ़ाइलें बनाने के लिए पथ तैयार करना:

3-CreateLogFile() फ़ंक्शन का उपयोग करके "trigger blf" फ़ाइल बनाना

4-"trigger blf" फ़ाइल तैयार करना

5-trigger blf के BASE BLOCK का कर्नेल पता प्राप्त करना

6-trigger blf के हैंडल के साथ AddLogContainer को कॉल करना

7-spray blf फ़ाइलें तैयार करना

8-spray करने के लिए मेमोरी तैयार करना

9-बग को ट्रिगर करना

डीबगिंग:

1-मेमोरी स्प्रे की जाँच करना

2-trigger blf के RecordOffset[12] को देखना

3-spray blf फ़ाइल में iFlushBlock मान को देखना

4-यह BLOCK 0 CONTROL के बजाय BLOCK 1 SHADOW से क्यों पढ़ता है ?

5-blf spray फ़ाइलों में checksum शून्य के बराबर क्यों होता है ?

6-शोषण समाप्त करना।

7-वास्तविक पैच

PoC बनाना:

1-शोषण के लिए आवश्यक कर्नेल पते प्राप्त करें

मैं कुछ आवश्यक कर्नेल पते प्राप्त करने के लिए InitEnvironment नामक एक फ़ंक्शन बनाऊँगा।

अपनी प्रक्रिया का EPROCESS पता प्राप्त करें और उसे g_EProcessAddress वेरिएबल में संग्रहीत करें, फिर SYSTEM प्रक्रिया का EPROCESS पता प्राप्त करें और उसे system_EPROCESS में संग्रहीत करें, फिर अपनी प्रक्रिया के मुख्य थ्रेड का EHTREAD पता प्राप्त करें और उसे g_EThreadAddress में संग्रहीत करें और अंत में PREVIOUS MODE का पता, जो PoC के इस संस्करण में उपयोग नहीं किया जाएगा।

कंप्यूटर कोड का एक स्क्रीनशॉट, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

यह विधि सर्वविदित है, GetObjectKernelAddress फ़ंक्शन पहले तर्क SystemExtendedHandleInformation के साथ NtQuerySystemInformation को दो बार कॉल करता है, पहला कॉल गलत आकार के साथ किया जाता है और त्रुटि लौटाता है, लेकिन सही आकार भी लौटाता है जो दूसरे कॉल में उपयोग होता है और सभी हैंडल की जानकारी प्राप्त करता है, फिर लूप में प्रत्येक हैंडल की जानकारी से गुजरता है और सही handleinfo के Object फ़ील्ड में कर्नेल में खोजा गया पता प्राप्त करता है।

पाठ, स्क्रीनशॉट, फ़ॉन्ट, रेखा युक्त चित्र, स्वचालित रूप से निर्मित विवरण

मुझे CLFS.sys द्वारा निर्यात किए गए निम्नलिखित फ़ंक्शनों के कर्नेल पते भी चाहिए:

• ClfsEarlierLsn

• ClfsMgmtDeregisterManagedClient

और NTOSKRNL.exe से निर्यात किए गए फ़ंक्शन

• RtlClearBit/PoFxProcessorNotification

• SeSetAccessStateGenericMapping

इन पतों को प्राप्त करने के लिए वही समान विधि उपयोग की जाती है जो दोनों मॉड्यूलों का कर्नेल आधार प्राप्त करने के लिए प्रयोग होती है, NtQuerySystemInformation को दो बार कॉल करके, लेकिन इस मामले में पहला तर्क SYSTEM_INFORMATION_CLASS होगा (PoC में हम इस उद्देश्य के लिए FindKernelModulesBase फ़ंक्शन का उपयोग करते हैं)।

पाठ, फ़ॉन्ट, स्क्रीनशॉट, रेखा युक्त चित्र, स्वचालित रूप से निर्मित विवरणफिर यह LoadLibrary को कॉल करके CLFS.sys और NTOSKRNL.exe को यूज़र मोड में सामान्य मॉड्यूल के रूप में लोड करता है, GetProcAddress के साथ यूज़र मोड में पते प्राप्त करता है और फिर प्रत्येक से imagebase घटाता है, जिससे फ़ंक्शन का ऑफ़सेट प्राप्त होता है और अंत में प्रत्येक ऑफ़सेट को संबंधित कर्नेल आधारों में जोड़ता है और इस प्रकार सभी आवश्यक फ़ंक्शनों के कर्नेल पते प्राप्त करता है।

पाठ, फ़ॉन्ट, रेखा, स्क्रीनशॉट युक्त चित्र, स्वचालित रूप से निर्मित विवरण

2-.blf फ़ाइलें बनाने के लिए पथ तैयार करना:

मैं createInitialTriggerBlfFile नामक एक फ़ंक्शन बनाता हूँ जो एक .blf फ़ाइल उत्पन्न और लिखेगा।

CreateLogFile में तर्क के रूप में उपयोग किया जाने वाला पथ सामान्य पथ से भिन्न होता है, उदाहरण के लिए C:\Users\Public फ़ोल्डर में स्थित 1280.blf फ़ाइल को खोलने के लिए, हमें पथ LOG:C:\Users\Public\1280. सेट करना होगा। यह stored_name_CreateLog वेरिएबल में सहेजा जाएगा।

मैं यह wsprintfW() का उपयोग करके करता हूँ क्योंकि stored_env पहले पर्यावरण चरों से प्राप्त पथ C:\Users\Public संग्रहीत करता है। इस स्ट्रिंग में मैं LOG: स्ट्रिंग जोड़ूँगा और अंत में एक यादृच्छिक नाम जोड़ूँगा, बिना .blf एक्सटेंशन के।

कंप्यूटर का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

यह मेरी प्रारंभिक फ़ाइल का पथ होगा जिसे मैं "trigger blf" कहूँगा। बेशक, मुझे उसी फ़ाइल का सामान्य पथ भी सहेजना होगा, बिना LOG: के सामने और BLF एक्सटेंशन के साथ, ताकि इसे CreateFile(), WriteFIle() के साथ किसी भी अन्य फ़ाइल की तरह खोलकर संशोधित किया जा सके, यह पथ उदाहरण के लिए होगा: C:\Users\Public\1280.blf, और इसे stored_name_fopen वेरिएबल में संग्रहीत किया जाएगा।

पाठ, फ़ॉन्ट, रेखा, स्क्रीनशॉट युक्त चित्र, स्वचालित रूप से निर्मित विवरण

बेशक, दोनों पथ एक ही फ़ाइल के अनुरूप हैं, और मुझे आवश्यकतानुसार एक या दूसरे का उपयोग करना होगा।

3-CreateLogFile() फ़ंक्शन का उपयोग करके "trigger blf" फ़ाइल बनाना।

CreateLogFile फ़ंक्शन CreateFile() के समान कार्य पूरा करता है (नई फ़ाइलें बनाता है या मौजूदा फ़ाइलें खोलता है और उनका हैंडल प्राप्त करता है), यहाँ तक कि कुछ तर्क समान हैं, लेकिन CreateLogFile() केवल blf फ़ाइलों के साथ काम करता है।

इसके अलावा, जब यह किसी मौजूदा फ़ाइल को खोलता है, तो यह सत्यापित करता है कि प्रारूप ठीक है, यहाँ तक कि प्रत्येक ब्लॉक में checksum होता है और यदि यह सही नहीं है तो यह एक त्रुटि लौटाएगा।

मैं 2 प्रकार की BLF फ़ाइलें बनाऊँगा:

  1. ट्रिगर blf

  2. स्प्रे blf

दोनों blf फ़ाइलें हैं लेकिन अलग तरीके से संशोधित की जाती हैं।

कंप्यूटर कोड का एक क्लोज़-अप, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरणइस प्रकार PoC पहले "trigger blf" फ़ाइल बनाता है, CreateLogFile का उपयोग करके, उदाहरण के लिए पथ: LOG:C:\Users\Public\1280 जो मैंने पहले सेट किया था, और stored_name_CreateLog वेरिएबल में संग्रहीत किया गया था।

पाँचवाँ तर्क fCreateDisposition, CreateFileA() की तरह, निम्नलिखित मान ले सकता है:

पाठ, फ़ॉन्ट, रेखा, रसीद युक्त चित्र, स्वचालित रूप से निर्मित विवरण

इस मामले में मैं OPEN_ALWAYS तर्क का उपयोग करूँगा, इसलिए फ़ाइल बनाई जाएगी यदि यह मौजूद नहीं है और यदि यह मौजूद है तो इसे खोला जाएगा। चूँकि फ़ाइल अभी तक मौजूद नहीं है, इसे एक यादृच्छिक नाम के साथ बनाया जाएगा।

logFile = CreateLogFile(stored_name_CreateLog, GENERIC_READ | GENERIC_WRITE, 1, 0, 4, 0);

CreateLogFile() हमारी "trigger blf" फ़ाइल को उसके 6 ब्लॉकों और उनके संबंधित checksums के साथ बनाएगा और वह हैंडल लौटाएगा जो logFile वेरिएबल में संग्रहीत किया जाएगा।

पाठ, स्क्रीनशॉट, फ़ॉन्ट, संख्या युक्त चित्र, स्वचालित रूप से निर्मित विवरण

प्रत्येक ब्लॉक में बाएँ कॉलम में दिखाए गए ऑफ़सेट से एक हेडर होगा, जिसका आकार 0x70 बाइट्स है।

इसलिए, उदाहरण के लिए, CONTROL BLOCK का हेडर ऑफ़सेट 0x0 से 0x70 तक जाता है।

कंप्यूटर का एक स्क्रीनशॉट, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

सभी ब्लॉकों के सभी हेडरों की संरचना समान होती है जिसे _CLFS_LOG_BLOCK_HEADER कहा जाता है।

यह हेडर संरचना है:

कंप्यूटर का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

हेडर के ऑफ़सेट 0xC पर मुझे checksum मिलता है, इसलिए जैसे CONTROL BLOCK ऑफ़सेट 0 से शुरू होता है, checksum फ़ाइल के ऑफ़सेट 0xC पर होगा और इस प्रकार प्रत्येक ब्लॉक के अपने ब्लॉक की शुरुआत से 0xC पर checksum होगा।

कंप्यूटर का एक स्क्रीनशॉट, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

4-"trigger blf" फ़ाइल तैयार करना:

trigger blf फ़ाइल को संशोधित करने के लिए, मुझे इसे एक सामान्य फ़ाइल के रूप में CreateFileA या fopen के साथ खोलना होगा और फिर क्रमशः WriteFile या fwrite के साथ संशोधित करना होगा, मैं इसे PoC के fun_prepare फ़ंक्शन की शुरुआत में करता हूँ।

याद रखें कि सामान्य पथ stored_name_fopen वेरिएबल में संग्रहीत है, इसलिए मैं इसे wfopen_s के साथ फ़ाइल खोलने के लिए उपयोग करता हूँ (जो fopen का एक प्रकार है जो यूनिकोड स्ट्रिंग्स का समर्थन करता है)।

फ़ाइल को craftTriggerBlfFile फ़ंक्शन में संशोधित किया जाता है जो fun_prepare से कॉल किया जाता है।

पाठ, रेखा, फ़ॉन्ट, स्क्रीनशॉट युक्त चित्र, स्वचालित रूप से निर्मित विवरण

फिर मैं बदले जाने वाले ऑफ़सेट को इंगित करने के लिए fseek कॉल करता हूँ और फिर fwrite के साथ फ़ाइल संशोधित की जाती है।

कंप्यूटर का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण"trigger blf" फ़ाइल में किए जाने वाले परिवर्तन इस प्रकार हैं:

ये परिवर्तन करने के बाद, FixCRCFile को नया checksum गणना करने और पहले 4 ब्लॉकों के checksums को ठीक करने के लिए कॉल किया जाता है। अगले दो ब्लॉकों में कोई परिवर्तन नहीं होता है, इसलिए उनके checksums की पुनर्गणना करना आवश्यक नहीं है।

पाठ, फ़ॉन्ट, स्क्रीनशॉट, संख्या युक्त चित्र, स्वचालित रूप से निर्मित विवरण

5-trigger blf के BASE BLOCK का कर्नेल पता प्राप्त करना:

CLFS.sys ड्राइवर फ़ाइल के छह ब्लॉकों को पढ़ता है, और उनकी सामग्री को संग्रहीत करने के लिए कर्नेल पूल में एक आवंटन करता है।

पाठ, स्क्रीनशॉट, फ़ॉन्ट, संख्या युक्त चित्र, स्वचालित रूप से निर्मित विवरण

आकार 0x90 की एक बहुत महत्वपूर्ण संरचना है, जिसे पिछले CVE-2022-37969 के ब्लॉगपोस्ट में, रिवर्सिंग के माध्यम से मैंने कुछ फ़ील्ड पाए और इसे pool_0x90 कहा। बहुत अधिक रिवर्सिंग के बाद, अब मुझे पता है कि इसका वास्तविक नाम m_rgBlocks है और जैसे ही कंट्रोलर फ़ाइल से प्रत्येक ब्लॉक की सामग्री की प्रतिलिपि बनाने के लिए मेमोरी आवंटित करता है, वहाँ यह प्रत्येक ब्लॉक का आकार, प्रारंभ ऑफ़सेट और कर्नेल पता सहेजता है जहाँ इसे संग्रहीत किया गया था।

पाठ, स्क्रीनशॉट, फ़ॉन्ट युक्त चित्र, स्वचालित रूप से निर्मित विवरण

इसमें छह CLFS_METADATA_BLOCK हैं जो प्रत्येक ब्लॉक के अनुरूप उसकी संख्या से मेल खाते हैं।

प्रत्येक CLFS_METADATA_BLOCK संरचना 0x18 बाइट्स लंबी है। (0x18*6=0x90)

पाठ, फ़ॉन्ट, रेखा, संख्या युक्त चित्र, स्वचालित रूप से निर्मित विवरणऑफ़सेट 0 में एक union है, लेकिन कम से कम इस exploit में केवल pbImage फ़ील्ड का उपयोग किया जाता है, इसलिए इसे सरल बनाने पर यह होगा:

उस संरचना का आवंटन CLFS.sys ड्राइवर के दो अलग-अलग स्थानों से किया जा सकता है, नई फ़ाइल के निर्माण के अनुसार या यदि कोई मौजूदा फ़ाइल खोली जाती है। नई फ़ाइल बनाने के मामले में, ड्राइवर CClfsBaseFilePersisted::CreateImage+28A से 0x90 बाइट्स आवंटित करता है, जबकि मौजूदा फ़ाइल के मामले में यह CClfsBaseFilePersisted: ReadImage+6E से आवंटित करता है।

उसके बाद, मैं ब्लॉक 2 का प्रारंभ पता प्राप्त करूँगा जो trigger blf फ़ाइल से मेल खाता है, जिसे BASE BLOCK कहा जाता है, जो ऑफ़सेट 0x800 से शुरू होता है और इसकी लंबाई 0x7a00 है।

पाठ, स्क्रीनशॉट, फ़ॉन्ट, संख्या युक्त चित्र, स्वचालित रूप से निर्मित विवरण

नीचे fun_prepare फ़ंक्शन के अंदर यह पता कर्नेल में कोड के इस टुकड़े का उपयोग करके पाया जाएगा।

कंप्यूटर कोड का एक स्क्रीनशॉट, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

सबसे पहले, getBigPoolInfo फ़ंक्शन पूल में उन सभी आवंटनों को ढूँढता है जिनमें "Clfs" टैग और आकार 0x7a00 है, फिर उन्हें एक सरणी में संग्रहीत करता है।

उसके बाद यह पहले से संशोधित trigger blf फ़ाइल को CreateLogFile का उपयोग करके OPEN_EXISTING तर्क के साथ फिर से खोलता है, इसलिए यह एक मौजूदा फ़ाइल खोलता है, इससे उसके BASE BLOCK का आवंटन होगा।

जब getBigPoolInfo फिर से कॉल किया जाता है, तो आकार 0x7a00 का एक नया "Clfs" पूल होगा, और इसका पता NtQuerySystemInformation को दो बार कॉल करके प्राप्त किया जाता है।

trigger blf फ़ाइल के BASE BLOCK का पता CLFS_kernelAddrArray वेरिएबल में संग्रहीत किया जाता है।

ध्यान दें कि यदि संशोधित trigger blf फ़ाइल में सही checksum नहीं है, तो CreateLogFile() फ़ंक्शन विफल हो जाएगा।

6-trigger blf के हैंडल के साथ AddLogContainer को कॉल करना:

fun_prepare फ़ंक्शन का अंतिम भाग, trigger blf फ़ाइल के हैंडल का उपयोग करके AddLogContainer api को कॉल करता है।

कंप्यूटर कोड का एक क्लोज़-अप, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

7-spray blf फ़ाइलें तैयार करना:

PoC के अंतिम फ़ंक्शन में, जिसे to_trigger कहा जाता है, दूसरे प्रकार की blf फ़ाइल बनाई जाएगी,

मैं इसे spray blf नाम दूँगा।

इस प्रकार की फ़ाइल का उपयोग मेमोरी स्थान भरने (स्प्रे) के लिए किया जाएगा, इस प्रकार की 10 समान फ़ाइलों की आवश्यकता होती है, लेकिन प्रारंभ में केवल एक बनाई जाती है। पाठ, फ़ॉन्ट, रेखा, स्क्रीनशॉट युक्त चित्र, स्वचालित रूप से निर्मित विवरण

इन फ़ाइलों के यादृच्छिक नामों को संग्रहीत करने के लिए तीन सरणियाँ बनाई जाएंगी:

stored_log_arrays: दस नए यादृच्छिक नामों के .blf फ़ाइलों को संग्रहीत करता है जिनका उपयोग CreateLogFile के साथ किया जाएगा।

stored_container_arrays: दस नई कंटेनर फ़ाइलें बनाने के लिए यादृच्छिक नाम संग्रहीत करता है।

stored_fopen_arrays: पहली सरणी (stored_log_arrays वेरिएबल) के लॉग फ़ाइलों के नाम संग्रहीत करता है, लेकिन उनके सामान्य पथ के साथ (बिना "LOG:" स्ट्रिंग के) और .blf एक्सटेंशन के साथ।

कंप्यूटर कोड का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

प्रत्येक पुनरावृत्ति में blf फ़ाइल को CopyFileW का उपयोग करके कॉपी किया जाता है, सरणियों में संग्रहीत नाम निर्दिष्ट किए जाते हैं।

fun_trigger फ़ंक्शन craftSprayBlfFile को कॉल करता है जहाँ प्रत्येक फ़ाइल में संशोधन किए जाते हैं और FixCRCFile CRCs को ठीक करेगा।

कंप्यूटर प्रोग्राम का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

संक्षेप में, मैंने निम्नलिखित संशोधनों के साथ यादृच्छिक नामों वाली 10 समान फ़ाइलें (spray blf) बनाई हैं:

कंप्यूटर का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

अंतिम परिवर्तन संपूर्ण ब्लॉक 0 (CONTROL BLOCK) को ब्लॉक 1 (CONTROL BLOCK SHADOW) में कॉपी करना है।

कंप्यूटर का एक स्क्रीन शॉट, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

इन परिवर्तनों का प्रभाव, साथ ही trigger blf फ़ाइल में किए गए परिवर्तनों का, बाद में डीबगिंग अध्याय में समझाया जाएगा।

इनमें से कुछ परिवर्तन वे हैं जो भेद्यता उत्पन्न करते हैं, जबकि अन्य केवल ड्राइवर की जाँचों को दरकिनार करने के लिए आवश्यक हैं।

इस बिंदु पर फ़ाइलें पहले ही बनाई और संशोधित की जा चुकी हैं, spray करने के लिए तैयार हैं, फिर जब वे CreateLogFile के साथ खोली जाती हैं, तो वे उस मेमोरी क्षेत्र में स्थित होंगी जिसे हम चाहते हैं, जैसा कि बाद में दिखाया जाएगा।

8-spray करने के लिए मेमोरी तैयार करना

to_trigger फ़ंक्शन में, 12 तत्वों की एक सरणी बनाई जाती है, जिसमें trigger blf फ़ाइल के BASE BLOCK का पता और 0x30 जोड़ा गया होता है।

फिर, fun_pipeSpray फ़ंक्शन में, मेमोरी को पाइप्स के स्प्रे से भर दिया जाता है, अंदर एक लूप होता है जो CreatePipe को कॉल करता है और पाइप्स की वह संख्या बनाता है जो पहले तर्क के रूप में पारित की जाती है, दूसरा तर्क एक सरणी है जो बनाए गए सभी पाइप्स के हैंडल संग्रहीत करेगी।

एक लूप के भीतर, यह रीड-राइट पाइप्स बनाने के लिए CreatePipe को कॉल करता है।

इस प्रकार पहले 0x5000 पाइप्स बनाए जाएंगे और फिर अन्य 0x4000 पाइप्स बनाने के लिए फिर से कॉल किया जाएगा।

फिर हाल ही में बनाई गई सरणी को trigger blf फ़ाइल के BASE BLOCK + 0x30 के पतों के साथ पहले 5000 पाइप्स में लिखने के लिए WriteFile का उपयोग करता है।

कंप्यूटर कोड का एक स्क्रीनशॉट, कम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

अब मेमोरी में पहले से ही एक कॉम्पैक्ट ब्लॉक बन चुका है, यह संख्या 0x2000 से लेकर 0x2667 तक 0x667 पाइप्स को मुक्त करेगा, चूँकि मेमोरी में पाइप्स उसी क्रम में नहीं होते जिस क्रम में वे बनाए गए थे, जो होगा वह यह कि इस मेमोरी ब्लॉक में खाली स्थान होंगे।

पाठ, स्क्रीनशॉट, फ़ॉन्ट, सॉफ़्टवेयर युक्त चित्र, स्वचालित रूप से निर्मित विवरणध्यान दें कि पाइप्स के आवंटन का उपयोगकर्ता आकार 0x90 बाइट्स है, इसलिए जब मुक्त किया जाएगा तो हमारे पास होगा

यह पाइप्स से भरी मेमोरी के बीच 0x90 आकार के मेमोरी स्थानों को मुक्त करता है।
फिर यह 10 spray blf फ़ाइलों के साथ CreateLogFile को कॉल करने के लिए लूप करता है।
जब CreateLogFile को मौजूदा फ़ाइलों को खोलने के लिए कॉल किया जाता है, तो प्रत्येक spray blf फ़ाइल के लिए m_rgBlocks हेतु 0x90 बाइट्स का आवंटन किया जाता है, इसलिए ये आवंटन उन खाली स्थानों को भर देंगे जो पाइप्स को मुक्त करते समय छोड़े गए थे क्योंकि वे समान आकार के हैं।

कंप्यूटर कोड का एक स्क्रीनशॉट, मध्यम आत्मविश्वास के साथ स्वचालित रूप से निर्मित विवरण

फिर अंतिम 0x4000 पाइप्स में वह सरणी लिखने की प्रक्रिया दोहराएँ जिसमें trigger blf के BASE BLOCK +0x30 का पता होता है।

9-बग को ट्रिगर करना

ये सभी हेरफेर एक नियंत्रित मेमोरी स्थान बनाते हैं, मैं आपको दिखाऊँगा कि यह डीबग करते समय कैसा होता है, लेकिन विचार यह है कि प्रत्येक spray blf फ़ाइल का m_rgBlocks उन 0x90 बाइट्स के खाली स्थानों को भरता है जो मुक्त किए गए थे।

फिर पहले से अंतिम भाग में, बग को while( 1 ) के भीतर spray blf फ़ाइलों में AddLogContainer के कॉल का उपयोग करके ट्रिगर किया जाता है।A picture containing text, font, line, number Description
automatically generated

इस while के भीतर बग ट्रिगर होता है:

A screenshot of a computer program Description automatically generated
with low confidence

यह while तब बाहर निकलेगा जब उसे System टोकन मिल जाएगा, NtFsControlFile फ़ंक्शन का उपयोग करते हुए, जो पाइप की विशेषताओं को पढ़ता है।

A screenshot of a computer code Description automatically generated
with low confidence

फिर CreateLogFile का उपयोग करके, हमारी प्रक्रिया के टोकन को हाल ही में मिले System टोकन से अधिलेखित कर देता है और इस प्रकार हम विशेषाधिकार उन्नयन प्राप्त करते हैं।

A picture containing text, font, line, screenshot Description
automatically generated

फिर कुछ मानों को पुनर्स्थापित करें, पाइपों और blf फ़ाइलों के हैंडल बंद करें, और यह सत्यापित करने के लिए Notepad को System के रूप में चलाएँ कि हमने सही ढंग से उन्नयन किया है।

A screenshot of a computer Description automatically generated with
medium confidence

PUBLIC फ़ोल्डर पर बनाई गई blf फ़ाइलों पर ध्यान दें। याद रखें कि यदि आप दोबारा प्रयास करना चाहते हैं, तो आपको पहले बनाई गई फ़ाइलों को हटाना होगा। कुछ लॉक हो जाएँगी और हटाई नहीं जा सकेंगी, लेकिन PoC फिर भी काम करेगा।

A screenshot of a computer Description automatically generated with
medium confidence

डिबगिंग:

1- मेमोरी स्प्रे की जाँच करना

शोषण करने के लिए trigger blf और spray blf फ़ाइलों में परिवर्तनों के प्रभाव से शुरुआत करने से पहले, मुझे यह सत्यापित करना होगा कि spray blf फ़ाइलों के m_rgBlocks, पाइप स्प्रे करने और बाद में एक निश्चित संख्या में पाइपों को रिलीज़ करने के बाद, मेमोरी वितरण में बने होल्स में स्थित हैं।

जब यह प्रक्रिया समाप्त होती है, तो m_rgBlocks के 0x90 बाइट्स के नीचे एक पाइप स्थित होना चाहिए, इसलिए जब m_rgBlocks का उपयोग किया जाता है, तो एक OUT OF BOUNDS स्थिति उत्पन्न होगी और यह नीचे स्थित उस पाइप से पढ़ेगा।

PoC के पास ब्रेकपॉइंट लगाने के लिए एक आदर्श बिंदु है:

A screen shot of a computer code Description automatically generated
with low confidence

इस बिंदु पर, spray blf फ़ाइलों को खोलना पूरा हो चुका है और AddLogContainer फ़ंक्शन को अभी भी कॉल नहीं किया गया है।

यूज़र मोड में डिबग करने के लिए, मैं x64dbg का उपयोग करूँगा और कर्नेल मोड के लिए, Windbg प्लगइन के साथ IDA का उपयोग करूँगा।

A screen shot of a computer Description automatically generated with
low confidence

इस बिंदु पर मेमोरी पहले से तैयार होनी चाहिए, और मैं वितरण देख सकता हूँ।

ब्रेकपॉइंट लगाने के लिए एक दिलचस्प बिंदु खोजने हेतु मैं IDA को रोकूँगा।

मैं CClfsBaseFilePersisted::AddContainer पर ब्रेकपॉइंट सेट करूँगा, जिसे AddLogContainer से कॉल किया जाता है और शुरुआत में, RCX रजिस्टर CClfsBaseFilePersisted संरचना की ओर इंगित करता है और ऑफसेट 0x30 पर m_rgBlocks का एक पॉइंटर होता है।

A screen shot of a computer Description automatically generated with
medium confidence

जब ब्रेकपॉइंट पहुँच जाता है, तो मैं कॉल स्टैक पर जाँच करता हूँ कि AddLogContainer मेरे PoC से कॉल हो रहा है।

A screenshot of a computer Description automatically generated with
medium confidence

RCX रजिस्टर इंगित करता है:

A screenshot of a computer Description automatically generated with
low confidence A screenshot of a computer
Description automatically generated with low
confidence

पहला फ़ील्ड vtable (CLFS! CClfsBaseFilePersisted::'vftable') का पॉइंटर है और ऑफसेट 0x30 पर m_rgBlocks का पॉइंटर है।

A screenshot of a computer code Description automatically generated
with medium confidence

ब्लॉक 0, 1, 4 और 5 ने अभी pbImage को सहेजा नहीं है, जबकि ब्लॉक 2 (BASE BLOCK) और 3 (SHADOW BLOCK) ने सहेजा है।

m_rgBlocks तालिका में प्रत्येक ब्लॉक का अपना cbOffset होता है जो फ़ाइल में ब्लॉक की शुरुआत का ऑफसेट है, cbImage ब्लॉक का आकार है, और eBlockType ब्लॉक का प्रकार है।

यदि स्प्रे सही है, तो m_rgBlocks के नीचे एक पाइप होना चाहिए और उसके भीतर trigger blf के BASE BLOCK + 0x30 के पॉइंटर होने चाहिए।

A screenshot of a computer code Description automatically generated
with low confidence

windbg पर "!pool" कमांड मेमोरी वितरण दिखाता है:

A screenshot of a computer Description automatically generated with
medium confidence

प्रत्येक m_rgBlocks में एक "Clfs” टैग होता है और इसका आकार 0xa0 है क्योंकि यह 0x90 यूज़र साइज़ plus 0x10 हेडर है और नीचे "NpFr" टैग वाला एक पाइप है जिसका आकार समान 0x90 यूज़र साइज़ + 0x10 हेडर है।

चूँकि वितरण कोई exact विज्ञान नहीं है, कुछ "Clfs” लगातार रखे गए, जो अवांछनीय है, लेकिन जिस पर मैं काम कर रहा हूँ, वह सही ढंग से रखा गया है और उसके बाद एक पाइप है।

2- trigger blf के RecordOffset[12] को देखना

जिन पहले परिवर्तनों का प्रभाव पड़ता है, उनमें से एक trigger blf फ़ाइल में ऑफसेट 0x858 पर किया गया परिवर्तन है, जहाँ मान 0x369 संग्रहीत होता है।

A close-up of a sign Description automatically generated with low
confidence

BASE BLOCK फ़ाइल में ऑफसेट 0x800 से शुरू होता है।

A picture containing text, screenshot, font, line Description
automatically generated

_CLFS_LOG_BLOCK_HEADER के अंदर ऑफसेट 0x800+0x58 पर (BASE BLOCK हेडर की शुरुआत से 0x58)।

A picture containing text, screenshot, font, display Description
automatically generated

ऑफसेट 0x28 पर सरणी RecordOffsets (DWORD) शुरू होती है।

0x30 बाइट्स आगे बढ़ने पर, ऑफसेट 0x58 (शुरुआत से 0x828+0x30=0x858) पर, RecordOffsets का फ़ील्ड 12 होता है।

A picture containing text, font, screenshot, graphics Description
automatically generated

मैं नीचे दिखाए गए अनुसार CreateLogFile के लिए PoC चलाता हूँ:

A screenshot of a computer code Description automatically generated
with low confidence A screenshot of a computer
code Description automatically generated with low
confidence

A screenshot of a computer Description automatically
generated

CreateLogFile में प्रवेश करने से पहले मैं एक ऐसी जगह ब्रेकपॉइंट लगाने जा रहा हूँ जहाँ 0x369 मान का अभी उपयोग नहीं हुआ है।

ऐसे मामले में जब CreateLogFile किसी मौजूदा फ़ाइल को खोलता है, तो m_rgBlocks संरचना यहाँ आवंटित होती है:

CClfsBaseFilePersisted::ReadImage+6E

इसलिए, मैं IDA पर ब्रेकपॉइंट यहीं सेट करूँगा:

A screenshot of a computer Description automatically generated with
medium confidence

जब ब्रेकपॉइंट ट्रिगर होता है**:**

A picture containing text, screenshot, font, number Description
automatically generated

m_rgBlocks में अभी भी कुछ कचरा है क्योंकि यह अभी भी अप्रारंभीकृत है, लेकिन जैसे ही ब्लॉक 2 का pbImage आवंटित होता है, पता शुरुआत से ऑफसेट 0x30 में सहेजा जाएगा, क्योंकि प्रत्येक CLFS_METADATA_BLOCK के अंदर पहला फ़ील्ड pbImage होता है।

A screen shot of a computer Description automatically generated with
medium confidence

A picture containing text, screenshot, font, line Description
automatically generated

अब मैं राइट पर एक हार्डवेयर ब्रेकपॉइंट सेट करता हूँ: ba w1 ffffd003'7f5bea30

शून्य से प्रारंभ करने के बाद, यह pbImage सहेजने पर रुकता है।

विश्लेषण कहता है कि यह block0 के अनुरूप है, क्योंकि यह स्थिरांक r14*8 पर विचार नहीं करता जो बाद में 0x30 है, परिणामस्वरूप यह वास्तव में block 2 का pbImage लिख रहा है।

A picture containing text, screenshot, font Description automatically
generated

ध्यान दें कि CClfsBaseFilePersisted::ReadMetadataBlock का उपयोग किसी भी ब्लॉक को आवंटित करने के लिए किया जाता है, तर्क के रूप में पारित आकार का उपयोग करके।

A picture containing text, font, screenshot, line Description
automatically generated

अब बेस ब्लॉक से 0x58 पर एक read/write ब्रेकपॉइंट सेट करें, यह देखने के लिए कि यह 0x369 मान का उपयोग कब करता है।

ba r1 FFFF978A'16ECF000+0x58

जब ब्रेकपॉइंट हिट होता है, तो यह RecordOffset[12] पर स्थित 0x369 मान को पढ़ता है, इसे r14 पर एक अजीब पॉइंटर में जोड़ता है और RAX+r14 की सामग्री को बढ़ाता है।

कोड में कुछ पंक्तियाँ ऊपर, ESI में मान 0x13 होता है और 0x18 से गुणा करता है, जो m_rgBlocks में प्रत्येक ब्लॉक का आकार है।

WINDBG>? 0x18*0x13

Evaluate expression: 456 = 00000000'000001c8

यदि मैं r8= 0x1c8 का मान, जो 0x90 से अधिक है, m_rgBlocks के प्रारंभिक पते में जोड़ता हूँ, तो यह OUT OF BOUNDS पढ़ेगा।

A screenshot of a computer Description automatically
generated

m_rgBlocks के नीचे, BASE BLOCK + 0x30 के पॉइंटर वाला पाइप है, यह उस पॉइंटर को पढ़ता है जिसे जानबूझकर पाइप के अंदर रखा गया था।

A screenshot of a computer program Description automatically generated
with low confidenceकोड में वर्तमान स्थिति मुख्य मॉड्यूल के while(1) कथन से कॉल की गई थी।

spray blf फ़ाइल के अंदर मैंने जानबूझकर मान 0x13 को ऑफसेट 0x48a (iFlushBlock) पर रखा है।

A picture containing text, font, line, screenshot Description
automatically generated

3- spray blf फ़ाइल में iFlushBlock मान को देखना

spray blf फ़ाइल के ऑफसेट 0x8a पर, BLOCK 0 का iFlushBlock स्थित है, जिसका मान 4 है, जबकि ऑफसेट 0x48a BLOCK 1 के iFlushBlock का है, और इसका मान 0x13 है।

A screenshot of a computer Description automatically generated with
medium confidence

अब मुझे यह पता लगाना है कि यह BLOCK 0 से iFlushBlock = 4 के बजाय BLOCK 1 से iFlushBlock = 0x13 क्यों पढ़ता है।

4- यह BLOCK 0 CONTROL के बजाय BLOCK 1 SHADOW से क्यों पढ़ता है?

अगर मैं पीछे देखूँ कि 0x13 कहाँ से आया, तो मैं कॉल स्टैक पर देखता हूँ कि WriteMetadataBlock को CClfsBaseFilePersisted::ExtendMetadataBlock+416 से कॉल किया गया है, वहाँ दूसरा iFlushBlock तर्क EDX=0x13 है, जो r9w से आता है।

A screenshot of a computer code Description automatically generated
with low confidence

A picture containing text, screenshot, font, line Description
automatically generated

A screenshot of a computer program Description automatically generated
with low confidenceकुछ पंक्तियाँ पहले, BLOCK 0 का पता प्राप्त करने के लिए CClfsBaseFile::GetControlRecord को कॉल किया गया था, शायद समस्या यहीं है, इसलिए मैं रीबूट करूँगा और उस पर ब्रेकपॉइंट लगाऊँगा।

GetControlRecord, CClfsBaseFile::AcquireMetadataBlock को कॉल करता है, जिसे m_rgBlocks तालिका को block 0 के पते से भरना चाहिए, जब मैं इस फ़ंक्शन को step over करता हूँ तो यह block 1 का पता प्राप्त करता है, इसलिए समस्या CClfsBaseFile::AcquireMetadataBlock के अंदर होती है।

प्राप्त पते में 0x8A जोड़कर, मैं पुष्टि कर सकता हूँ कि BLOCK 1 से संबंधित 0x13 मान मौजूद है।

A screenshot of a computer code Description automatically generated
with medium confidence

मैं रीबूट करूँगा और वहाँ ब्रेकपॉइंट सेट करूँगा:

A screenshot of a computer program Description automatically generated
with low confidence

CClfsBaseFile::GetControlRecord+27 call CClfsBaseFile::AcquireMetadataBlock

A screenshot of a computer Description automatically
generated

AcquireMetadataBlock को दिया गया दूसरा तर्क zero है, यह block 0 से मेल खाता है, यह फ़ाइल से कॉपी करके अपना पता m_rgBlocks में संग्रहीत करेगा A screenshot of a computer Description
automatically generated with medium confidence.

_CLFS_METADATA_BLOCK_TYPE ब्लॉक टाइप enumeration में, उनके नाम मेरे द्वारा उपयोग किए गए नामों से भिन्न हैं, लेकिन वे समान 6 ब्लॉक हैं।

A picture containing text, screenshot, font, line Description
automatically generated

यह जाँचने के बाद कि ब्लॉक प्रकार अधिकतम m_cBlocks=6 से कम है, यह उसी ब्लॉक को दो बार पढ़ने से बचने के लिए एक reference मान सहेजता है।

A screenshot of a computer code Description automatically generated
with low confidence

ReadMetadataBlock कॉल किया जाता है, block 0 के बजाय block 1 पढ़ने की समस्या इसी फ़ंक्शन के अंदर होगी।

A picture containing text, font, number, line Description
automatically generated

यदि सब कुछ ठीक है, तो यह आकार के रूप में cbImage का उपयोग करके आवंटित करता है और पते को m_rgBlocks में फ़ील्ड block 0-> pbImage में संग्रहीत करता है।

A picture containing text, font, line, screenshot Description
automatically generated

!pool कमांड आवंटित tag और size प्रदर्शित करता है।

A picture containing text, screenshot, font, line Description
automatically generated

A picture containing text, screenshot, font, line Description
automatically generatedतो, मेरे पास पहले से ही block 0 का pbImage पता m_rgBlocks में संग्रहीत है, इसलिए मुझे यह देखना होगा कि यह block 0 के बाइट्स के बजाय block 1 के बाइट्स वहाँ क्यों कॉपी करता है।

मैं CClfsContainer::ReadSector की कॉल तक पहुँचता हूँ, जहाँ बाइट्स लिखने के लिए pbImage वाले वेरिएबल का पॉइंटर पारित किया जाता है।

ReadSector को step over करते समय pbimage सामग्री में किए गए परिवर्तनों पर ध्यान दें।

pbImage में 0x8a जोड़कर मुझे मान 4 मिलता है जो सही मान है, 0x13 के बजाय, इसलिए समस्या बाद में होनी चाहिए।

ClfsDecodeBlock को कॉल करने के बाद यह त्रुटि 0x0C01A000A लौटाता है।

CClfsBaseFilePersisted::ReadMetadataBlock+153 calls to ClfsDecodeBlock

इस त्रुटि के बाद, यह प्रकार में 1 जोड़ता है और block 1 को पढ़ने के लिए CClfsBaseFilePersisted::ReadMetadataBlock को फिर से कॉल करता है, लेकिन प्रकार 1 के साथ।

A screenshot of a computer Description automatically
generated

CClfsBaseFilePersisted::ReadMetadataBlock में यह block 1 के लिए m_rgBlocks में एक नया pbImage आवंटित और संग्रहीत करता है।

A screenshot of a computer code Description automatically generated
with low confidence

Blocks 0 और 1 के पते अलग-अलग हैं, अब यदि मैं block 1 के पते में 0x8a जोड़ता हूँ तो इसका मान 0x13 है।

शायद चूँकि block 0 ने त्रुटि लौटाई, यह block 1 का उपयोग करता है और इसे Control Block के रूप में GetControlRecord को लौटा देता है।

जैसा पहले दिखाया गया है, जब यह 4 के बजाय 0x13 मान का उपयोग करता है, तो यह m_rgBlocks की सीमा से बाहर चला जाता है और मेरे द्वारा नियंत्रित पाइप स्प्रे मानों को पढ़ता है।

A picture containing text, screenshot, font Description automatically
generatedफिर यह block 0 से pbImage को मुक्त करता है और block 1 से block 0 में पॉइंटर कॉपी करता है।

A screenshot of a computer Description automatically
generated

उस मान को खोजना आवश्यक होगा जो ClfsDecodeBlock के अंदर त्रुटि 0x0C01A000A उत्पन्न करता है।

ClfsDecodeBlock के अंदर पहले ब्लॉक का checksum शून्य है, यही त्रुटि 0xC01A000A है।

A screenshot of a computer Description automatically generated with
medium confidence

5- blf स्प्रे फ़ाइलों में checksum शून्य के बराबर क्यों है?

AddLogContainer को कॉल करने से पहले, किसी भी spray blf फ़ाइल को हेक्साडेसिमल एडिटर से खोलने पर, checksum को zero में बदल दिया गया था।

A screenshot of a computer Description automatically
generated

इसे पहले ही बदल दिया जाना चाहिए था जब इसे CreateLogFile के साथ खोला गया था।

A picture containing text, screenshot, display, font Description
automatically generated

किसी कारण से spray blf फ़ाइलें, CreateLogFile से बाहर निकलने के बाद, block 0 के checksum के 0 के बराबर होने के साथ समाप्त होती हैं और एक valid handle लौटाती हैं, आइए देखें कि ऐसा क्यों होता है।

मैं कुछ spray blf फ़ाइल खोलने से पहले CreateLogFile पर रुकता हूँ।

A screenshot of a computer Description automatically generated with
medium confidence

ध्यान दें कि CreateLogFile को कॉल करने से पहले, spray files में block 0 में सही checksum होता है और फ़ंक्शन पूरा होने के बाद, checksum मान शून्य में बदल जाता है।

A screenshot of a computer code Description automatically generated
with low confidence

इसलिए, मैं अंदर देखने के लिए CClfsBaseFile::GetControlRecord पर ब्रेकपॉइंट सेट करता हूँ।

A picture containing text, screenshot, font, line Description
automatically generatedCClfsContainer::ReadSector को पार करने के बाद checksum शून्य नहीं है।

CRC32 की गणना करने से पहले, यह CRC की गणना करने के लिए मेमोरी में checksum फ़ील्ड को शून्य कर देता है, और परिणाम सही होता है।

A picture containing text, font, screenshot Description automatically
generated

A picture containing text, font, line, screenshot Description
automatically generated

फिर यह eExtendState =2 के मान की जाँच करता है और WriteMetadataBlock पर जाता है।

A screenshot of a computer Description automatically generated with
medium confidence

यहाँ मेमोरी में checksum अभी भी शून्य है, मुझे बस यह देखना है कि यह मान फ़ाइल में कब लिखा जाता है।

A picture containing text, font, line, screenshot Description
automatically generated

यह कुछ मानों की जाँच करता है जो blf spray फ़ाइल में तैयार किए गए हैं ताकि CClfsBaseFilePersisted::ExtendMetadataBlock तक पहुँचा जा सके।

A screenshot of a computer program Description automatically generated
with medium confidence

अभी तक न पढ़े गए ब्लॉकों को पढ़ने के लिए एक लूप के बाद, block 0 checksum = 0 के साथ जारी रहता है।

A white rectangle with black text Description automatically generated
with low confidence

WriteMetadataBlock पर पहुँचना।

चूँकि मैं block 0 को 1 से बदलने से पहले चला रहा हूँ, blf spray फ़ाइल का iFlushBlock मान अभी भी 4 है जो सही मान है।

A screenshot of a computer Description automatically generated with
medium confidence

अब यह block 4 के साथ काम कर रहा है, और यह block 4 को फ़ाइल में लिखेगा, अभी समस्या यहाँ नहीं है।

फिर यह CClfsBaseFilePersisted::FlushControlRecord पर आता है

A screenshot of a computer program Description automatically generated
with medium confidence

इसके अंदर यह WriteMetadataBlock तक पहुँचता है, लेकिन argument 0 के साथ, block 0 को फ़ाइल में लिखने के लिए।

A screenshot of a computer Description automatically generated with
medium confidence

फिर ClfsEncodeBlock त्रुटि 0xC01A000A लौटाता है, हालाँकि यह ठीक नीचे CClfsContainer::WriteSector में खराब block 0 के साथ फ़ाइल लिख देगा।

A screenshot of a computer Description automatically generated with
medium confidence

वेरिएबल var_54 0xC01A000A त्रुटि मान संग्रहीत करता है और फ़ंक्शन से बाहर निकलने से पहले जाँचा जाएगा।

A screenshot of a computer Description automatically generated with
medium confidence

लेकिन CClfsContainer::WriteSector को कॉल करने के बाद, जो कोई त्रुटि नहीं लौटाता, var_54 की सामग्री शून्य से अधिलेखित हो जाती है।

इसलिए, फ़ंक्शन बिना किसी त्रुटि के शून्य लौटाता है और यह काम करता रहता है क्योंकि CreateLogFile त्रुटि मान के बजाय एक handle लौटाएगा।

A screenshot of a computer Description automatically
generated

6- शोषण समाप्त करना

iFlushBlock में मान 0x13 इसे out of bounds जाने का कारण बनता है और यह उस पॉइंटर को पढ़ेगा जो पाइपों में है और जो trigger blf के Base Block +30 की ओर इंगित करता है।

A screenshot of a computer Description automatically
generatedफिर यह उस पॉइंटर में 0x28 जोड़ता है, ( trigger blf के आधार ब्लॉक की शुरुआत से 0x58) जिसका मान 0x369 है।

कंप्यूटर प्रोग्राम का स्क्रीनशॉट, विवरण स्वचालित रूप से उत्पन्न
मध्यम विश्वास के साथ

INC निर्देश मान 0x14 को 1 से बढ़ाएगा और 4 बार दोहराएगा, इसलिए 0x14 बढ़कर 0x18 हो जाता है।

WINDBG>db r14+369

ffffcb82'091e7397 14 00 00 00

उसके बाद, CreateLogFile कॉल किया जाता है, और 0x1858 मान पढ़ता है।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

कार्ड का क्लोज़-अप, विवरण स्वचालित रूप से कम
विश्वास के साथ उत्पन्नGetSymbol जाँच करता है कि क्या फेक ब्लॉक पहले trigger blf में बनाया गया, जो ऑफसेट 0x1858 द्वारा इंगित किया गया है, सही मान रखता है।

टेक्स्ट, फ़ॉन्ट, लाइन, स्क्रीनशॉट वाली तस्वीर, विवरण
स्वचालित रूप से उत्पन्न

अगर पॉइंटर को कई बार नहीं बढ़ाया गया होता, तो इसका मूल मान 0x1458 होता और यह सही ब्लॉक की ओर इंगित करता।

GetSymbol से बाहर निकलने के बाद, यह उस फेक ब्लॉक का उपयोग यहाँ करेगा।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

फिर यह फेक ब्लॉक के ऑफसेट 0x18 का मान पढ़ेगा जहाँ मैंने 0x05000000 रखा है, और वहाँ जो सामग्री है उस पर कूद जाएगा।

WINDBG>dps 0x5000000

00000000'05000000 00000000'05001000

यह 0x05000000 और उसके 0x05001000 की सामग्री पढ़ता है, और वहाँ ClfsEarlierLsn है।

कंप्यूटर प्रोग्राम का स्क्रीनशॉट, विवरण स्वचालित रूप से कम
विश्वास के साथ उत्पन्न

यह फ़ंक्शन RDX में मान 0xFFFFFFFF लौटाने के लिए उपयोग किया जाता है, हालाँकि इस पहली बार उस मान का उपयोग नहीं किया जाता है।

दूसरा कॉल यहाँ होता है, यह PoFxProcessorNotification को कॉल करता है जो 0x501000 +8 पर था

टेक्स्ट, फ़ॉन्ट, स्क्रीनशॉट, लाइन वाली तस्वीर, विवरण
स्वचालित रूप से उत्पन्न टेक्स्ट, फ़ॉन्ट,
स्क्रीनशॉट, लाइन वाली तस्वीर, विवरण स्वचालित रूप से
उत्पन्न

WINDBG>dps 00000000'05001000

00000000'05001000 fffff805'7ab13220 CLFS! ClfsEarlierLsn

00000000'05001008 fffff805'769dc3b0 nt! PoFxProcessorNotification

कंप्यूटर स्क्रीन का स्क्रीनशॉट, विवरण स्वचालित रूप से कम
विश्वास के साथ उत्पन्न

इस फ़ंक्शन में RCX = 0x05000000 , यह जाँचता है कि 0x40 बाइट्स बाद गैर-शून्य होना चाहिए

WINDBG>dps rcx+40

00000000'05000040 00000000'05000000

कूदने का पता 0x68 बाद होगा।

WINDBG>dps rcx+68

00000000'05000068 fffff805'7ab2bfb0 CLFS! ClfsMgmtDeregisterManagedClient

और तर्क 0x48 बाइट्स बाद होगा।

WINDBG>dps rcx+48

00000000'05000048 00000000'05000400

ClfsMgmtDeregisterManagedClient, यह एक सुविधाजनक फ़ंक्शन है क्योंकि मैं तर्क को नियंत्रित कर सकता हूँ और मेरे पास मेरे द्वारा नियंत्रित फ़ंक्शनों के लिए दो कूद भी हैं।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

पहला कॉल फिर से ClfsEarlierLsn के लिए है, जो RDX=0xFFFFFFFF में लौटा था।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

यह RDX=0xFFFFFFFF की सामग्री से लिखने के लिए स्रोत लेगा।

WINDBG>dps rdx

00000000'ffffffff ffff8005'3a4ee000

पते 0xFFFFFFFF पर मैंने system_EPROCESS & 0xfffffffffffff000 संग्रहीत किया था।

टेक्स्ट, फ़ॉन्ट, लाइन, नंबर वाली तस्वीर, विवरण
स्वचालित रूप से उत्पन्न

गंतव्य 0x5000400 +0x48 पर स्थित पॉइंटर है

*(UINT64*)0x5000448 = para_PipeAttributeobjInkernel + 0x18;

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

कर्नेल में PipeAttribute पॉइंटर, जो एक बफर की ओर इंगित करता है जो “A” से भरा है, SYSTEM EPROCESS पॉइंटर के उच्च भाग के साथ अधिलेखित कर दिया जाएगा।

यह पॉइंटर तब बनाया गया था जब मैंने पहले _NtFsControlFile को “A” से भरे बफर के साथ कॉल किया था।

कंप्यूटर प्रोग्राम का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

उस विशेषता की सामग्री को NtFsControlFile का उपयोग करके पढ़ा जा सकता है।

कंप्यूटर स्क्रीन का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

अब पाइप विशेषता अब “A” वाले बफर की ओर नहीं, बल्कि system_EPROCESS & 0xffffffffffffff000 की ओर इंगित करती है।

कंप्यूटर प्रोग्राम का स्क्रीनशॉट, विवरण स्वचालित रूप से कम
विश्वास के साथ उत्पन्न

यह कोड तब तक दोहराया जाएगा जब तक सिस्टम टोकन प्राप्त नहीं हो जाता।

कंप्यूटर कोड का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

विंडोज 11 पर सिस्टम टोकन हाल ही में पढ़ी गई EPROCESS संरचना के ऑफसेट 0x4b8 पर होता है।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

मुझे केवल CreateLogFile को कॉल करके उस सिस्टम टोकन को अपनी प्रक्रिया में लिखने की आवश्यकता है।

टेक्स्ट, फ़ॉन्ट, लाइन, स्क्रीनशॉट वाली तस्वीर, विवरण
स्वचालित रूप से उत्पन्न

यह कार्य करने के लिए, सिस्टम टोकन पढ़ने के लिए उपयोग किए गए चरण को दोहराएं।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

डबल कॉल में, यह पहले ClfsEarlierLsn को कॉल करता है ताकि RDX में 0xFFFFFFFF लौटे और फिर nt_SeSetAccessStateGenericMapping को कॉल करता है।

टेक्स्ट, स्क्रीनशॉट, फ़ॉन्ट, लाइन वाली तस्वीर, विवरण
स्वचालित रूप से उत्पन्न

मैं जाँचता हूँ कि RDX द्वारा इंगित मान सिस्टम टोकन है।

टेक्स्ट, स्क्रीनशॉट, फ़ॉन्ट वाली तस्वीर, विवरण स्वचालित रूप से
उत्पन्न

मेरी प्रक्रिया का टोकन है:

यह वहाँ लिखने जा रहा है।

WINDBG>dps rax+8

ffff9b8b'fc446578 ffffc402'f601c06c

WINDBG>dps rax+8

ffff9b8b'fc446578 ffffc402'ef841919

अब मेरी प्रक्रिया System है, मैं सत्यापित करने के लिए Notepad चला सकता हूँ।

टेक्स्ट, स्क्रीनशॉट, फ़ॉन्ट, लाइन वाली तस्वीर, विवरण
स्वचालित रूप से उत्पन्न

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

7-वास्तविक पैच

BINDIFF बहुत सारे बदले हुए फ़ंक्शन दिखाता है

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

कमजोर फ़ंक्शन यहाँ है:

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

प्राथमिक पैच किया गया संस्करण है, द्वितीयक कमजोर संस्करण है।

पैच CflsEncodeBlock के रिटर्न मान का परीक्षण करता है, जो 0xC01A000A है, इसे var_54 चर में संग्रहीत करता है, और चूंकि यह नकारात्मक है, यह जाँचता है और WriteSector से बचता है।

पैच, फ़ाइल को न लिखने के अलावा, फ़ंक्शन सही ढंग से 0xc01a000a लौटाता है, जिसके साथ CreateLogFile कोई हैंडल नहीं लौटाता और शोषण जारी नहीं रह सकता।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्न

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से
उत्पन्न

केवल अगर ClfsDecodeBlock नकारात्मक नहीं है, तो यह WriteSector पर जाता है लेकिन नकारात्मक मान 0xC01A000A लौटाता हुआ छोड़ता है।

कंप्यूटर का स्क्रीनशॉट, विवरण स्वचालित रूप से मध्यम विश्वास के साथ
उत्पन्नयह वास्तविक पैच है जो मेरे द्वारा अभी संलग्न किए गए PoC का उपयोग करके शोषण को वास्तव में रोकता है।

इस बिंदु पर हमने समझाया है कि बग का शोषण कैसे किया गया, यह उन फ़ंक्शनों को नियंत्रित करने की ओर ले जाता है जो हमें SYSTEM टोकन पढ़ने और स्थानीय विशेषाधिकार वृद्धि प्राप्त करने के लिए इसे अपनी प्रक्रिया में लिखने की अनुमति देते हैं। आप कार्यात्मक PoC यहाँ पा सकते हैं: Fortra का GitHub।

हमें उम्मीद है कि आपको यह उपयोगी लगेगा, यदि आपको कोई संदेह हो तो हमसे संपर्क कर सकते हैं:

[email protected] 
@ricnar456

 [email protected]
@solidclt

टूल डाउनलोड करें