
Windows PrintNightmare (CVE-2021-1675/34527) के लिए विस्तृत विश्लेषण और एक्सप्लॉइट कार्यान्वयन, जिसमें दुर्भावनापूर्ण प्रिंटर ड्राइवर स्थापना के माध्यम से RPC-आधारित विशेषाधिकार वृद्धि और दूरस्थ कोड निष्पादन शामिल है।
= Print Nightmare विश्लेषण रिपोर्ट :imagesdir: Figures :toc: :icons: font :figure-caption: चित्र :xrefstyle: short :pdf-theme: basic-theme.yml
29 जून 2021 को, एक अत्यंत गंभीर Windows प्रिंट सेवा भेद्यता को 0day के रूप में उजागर किया गया, भेद्यता का मूल स्कोर 8.8 था, और इसे GitHub पर प्रकाशित किया गया (अब हटा दिया गया)। यह भेद्यता प्रसिद्ध PrintNightmare है: CVE-2021-34527, जो EternalBlue से भी अधिक खतरनाक है।
== भेद्यता की मूल जानकारी
34527 भेद्यता Windows 7, Windows Server 2008 के बाद के लगभग सभी संस्करणों को प्रभावित करती है, विस्तृत जानकारी के लिए <> देखें।
हानि के दृष्टिकोण से, एक हमलावर सामान्य उपयोगकर्ता प्रमाणीकरण का उपयोग करके, प्रशासक अधिकारों के साथ दूरस्थ रूप से मनमाना कोड निष्पादित कर सकता है। शोषण की कठिनाई के संदर्भ में, इस भेद्यता का शोषण करना बहुत आसान है, इसलिए इससे बहुत अधिक नुकसान होता है।
भेद्यता की विशेषताओं से, 34527 भेद्यता CVE-2021-1675 भेद्यता पर आधारित है। जबकि 1675 भेद्यता एक स्थानीय विशेषाधिकार वृद्धि और दूरस्थ कोड निष्पादन भेद्यता है, और इसमें 34527 भेद्यता के साथ बहुत समानताएं हैं।
भेद्यता के कार्य सिद्धांत को समझने से पहले, हमें Windows प्रिंट बैकग्राउंड प्रोसेसर की वास्तुकला की सामान्य समझ होनी चाहिए, ताकि हम भेद्यता में शामिल विभिन्न मॉड्यूल के बीच संबंधों को आसानी से समझ सकें।
== CVE-2021-1675 कॉल प्रक्रिया
=== Windows प्रिंट बैकग्राउंड प्रोसेसर वास्तुकला
spooler वास्तुकला को <<spooler_arch>> द्वारा दर्शाया जा सकता है:
[[spooler_arch]] .Print Spooler Architecture image::Print Spooler Architecture.png[]
विशेष रूप से, बैकग्राउंड प्रिंटर प्रिंट कार्यों का प्रबंधन करता है, और इसमें निम्नलिखित घटक शामिल हैं:
winspool.drv:: उपयोगकर्ता को प्रदान की गई डायनामिक लिंक लाइब्रेरी फ़ाइल। यह फ़ाइल spooler से संबंधित Win32 API को परिभाषित करती है जिसे उपयोगकर्ता कॉल कर सकता है। इसके अंदर के सभी API रिमोट प्रोसीजर कॉल के रूप में सेवा प्राप्त करते हैं।
spoolsv.exe:: spoolsv.exe सिस्टम में सर्वर की भूमिका निभाता है, API कॉल को संसाधित करने वाला पहला प्रोग्राम है। यह डिज़ाइन इसलिए है ताकि print spooler स्थानीय प्रिंट कार्यों के साथ-साथ रिमोट प्रिंट कार्यों को भी समान रूप से संसाधित कर सके।
spoolsv.dll:: रूटिंग प्रोग्राम। यह spoolsv.exe द्वारा प्राप्त प्रिंट अनुरोधों को विभिन्न प्रिंट प्रदाताओं को भेजता है, और यह तय करता है कि कौन सा प्रिंट प्रदाता अंततः अनुरोध को संसाधित करेगा। इसका कार्य प्रिंट कार्य को दूरस्थ या स्थानीय के रूप में अलग करना है। दूरस्थ मशीन पर यह कार्य को स्थानीय प्रिंट प्रदाता को निर्दिष्ट करता है।
localspl.dll:: स्थानीय प्रिंट प्रदाता। प्रिंट प्रदाता का मुख्य कार्य प्रिंट कार्य प्रबंधन की आवश्यकता को हल करना है, और अधिकांश API इस मॉड्यूल के अंदर कार्यान्वित होते हैं।
उपरोक्त सिद्धांत के आधार पर अध्ययन जारी रखते हुए, उदाहरण के लिए, जब मैं AddPrinterDriverEx फ़ंक्शन (CVE-2021-1675) को कॉल करता हूं, तो यह निम्नलिखित प्रक्रिया से गुज़रता है:
=== फ़ंक्शन संस्करण चयन
सबसे पहले, यह फ़ंक्शन वास्तव में एक मैक्रो है, जो स्थानीय संकलन वातावरण के आधार पर Unicode संस्करण (W) या Ansi संस्करण (A) का चयन करता है, जैसा कि <> में दिखाया गया है:
[[AddPrinterDriverEx]] .AddPrinterDriverEx image::AddPrinterDriverEx.png[]
लेकिन चाहे वाइड कैरेक्टर या नैरो कैरेक्टर संस्करण हो, वास्तव में परिणाम में कोई अंतर नहीं है, क्योंकि Windows कर्नेल स्ट्रिंग्स Unicode एन्कोडिंग का उपयोग करती हैं, इसलिए अंततः Ansi संस्करण का कॉल Unicode संस्करण में परिवर्तित हो जाता है, जैसा कि <> में दिखाया गया है:
[[AnsiToUnicode]] .AnsiToUnicode image::AnsiToUnicode.png[]
जब Ansi फ़ंक्शन के पैरामीटर सभी Unicode संस्करण में परिवर्तित हो जाते हैं, तो एक फ़ंक्शन कॉल किया जाता है (<>):
[[AnsiCallUnicode]] .AnsiCallUnicode image::AnsiCallUnicode.png[]
और यह फ़ंक्शन वास्तव में AddPrinterDriverEx का Unicode संस्करण है (<>):
[[GetUnicodeProcAddress]] .GetUnicodeProcAddress image::GetUnicodeProcAddress.png[]
=== API फ़ंक्शन spooler सर्वर पर RPC अनुरोध भेजता है
Unicode संस्करण के फ़ंक्शन के अंदर प्रवेश करने के बाद, सबसे पहले Level के मान के अनुसार फ़ंक्शन पैरामीटर प्रकार का चयन किया जाता है:
image::pDriverInfo.png[]
इस भेद्यता में हम Level को 2 पर सेट करेंगे, अर्थात pDriverInfo पैरामीटर का प्रकार DRIVER_INFO_2 संरचना चुनेंगे। फिर Windows फ़ंक्शन पैरामीटर को संसाधित करेगा, और प्रसंस्करण पूरा होने के बाद, रिमोट प्रोसीजर कॉल के माध्यम से API को संसाधित करना जारी रखेगा:
image::set arguments.png[]
image::NdrClientCall3.png[]
=== MSRPC तंत्र
Microsoft का रिमोट प्रोसीजर कॉल तंत्र DCE मानक पर आधारित है। सरल शब्दों में समझाएं तो, रिमोट प्रोसीजर कॉल रिमोट सिस्टम पर प्रक्रियाएं चलाना है, जो प्रोग्रामर या सिस्टम द्वारा पूर्वनिर्धारित होती हैं।
RPC का विशिष्ट तरीका यह है कि रिमोट से कॉल करने वाले फ़ंक्शन को क्रमबद्ध किया जाता है, नेटवर्क के माध्यम से रिमोट सिस्टम पर प्रेषित किया जाता है, रिमोट सिस्टम इसे विपरीत क्रमबद्ध करता है, और इसे निष्पादित करता है। Microsoft द्वारा बनाई गई प्रणाली में, TCP/IP और SMB को आमतौर पर RPC कॉल को प्रसारित करने के लिए चुने गए प्रोटोकॉल हैं।
MSRPC का उपयोग करने के लिए, पहले कॉल किए जाने वाले फ़ंक्शन का IDL इंटरफ़ेस विवरण परिभाषित करना होगा, और फिर MIDL टूल का उपयोग करके क्लाइंट और सर्वर के लिए संबंधित क्रमबद्धता प्रोग्राम stub उत्पन्न करना होगा। कुछ Win32 API के लिए, उनमें पहले से ही सर्वर stub परिभाषित होता है, इसलिए हम केवल क्लाइंट stub उत्पन्न और उपयोग कर सकते हैं।
MSRPC एक विशिष्ट प्रकार के प्रोटोकॉल की पहचान करने के लिए UUID का उपयोग करता है, जैसे MS-RPRN रिमोट प्रिंट प्रोटोकॉल का वर्णन करता है, और सभी रिमोट प्रिंट से संबंधित फ़ंक्शन इस प्रोटोकॉल का हिस्सा हैं। MSPRC UUID 12345678-1234-ABCD-EF00-0123456789AB का उपयोग करके इस प्रोटोकॉल की पहचान करता है (<<rprn_uuid>>):
[[rprn_uuid]] .MS-RPRN UUID image::spoolss uuid.png[]
इसके बाद, इस कनेक्शन के आधार पर, प्रोटोकॉल के अंदर फ़ंक्शन की पहचान करने के लिए operator number का उपयोग किया जा सकता है, ताकि दूरस्थ रूप से कॉल किया जा सके, उदाहरण के लिए AddPrinterDriverEx स्वयं को 89 से पहचानता है (<<addPrinterDriverEx_opnum>>):
[[addPrinterDriverEx_opnum]] .AddPrinterDriverEx Opnum image::AddPrinterDriverEx Opnum.png[]
MSRPC का उपयोग करते समय, दो बातों पर ध्यान देने योग्य है:
"As you can see in your output, the scripts are trying to connect to port 135 (endpoint mapper) in order to get the TCP/IP port where the DCOM endpoint is listening (that is a dynamic port)." -- SecureAuthCorp/impacket issue #412
=== spoolsv.exe API अनुरोध को संसाधित करता है
[[call_flow]] .RpcAddPrinterDriverEx Call Flow image::Function Calls.png[]
<<call_flow>> से देखा जा सकता है कि spoolsv.exe इन फ़ंक्शनों को कॉल करता है, और फ़ंक्शन के अंदरूनी विश्लेषण से, इस मॉड्यूल में आरंभीकरण के अलावा कोई अन्य कार्य पूरा नहीं होता है। अंत में, यह मॉड्यूल pLocalProvidor द्वारा इंगित फ़ंक्शन को कॉल करता है, अर्थात localspl.dll मॉड्यूल के अंदर फ़ंक्शन LocalAddPrinterDriverEx। localspl एक स्थानीय प्रिंट प्रदाता के रूप में, वास्तव में API कार्यक्षमता को लागू करने वाला मॉड्यूल है।
=== स्थानीय प्रिंट प्रदाता का फ़ंक्शन कार्यान्वयन तर्क
[[LocalAddPrinterDriverEx]] .LocalAddPrinterDriverEx image::LocalAddPrinterDriverEx.png[]
सबसे पहले <> बताता है कि यह मॉड्यूल spooler के सामान्य संचालन को सत्यापित करता है, फिर फ़ंक्शन SplAddPrinterDriverEx पर कूदता है।
[[SplAddPrinterDriverEx]] .SplAddPrinterDriverEx image::SplAddPrinterDriverEx.png[]
<> फ़ंक्शन के अंदर वह महत्वपूर्ण स्थान है जहाँ AddPrinterDriverEx फ़ंक्शन के सफल निष्पादन का निर्णय होता है। पहले भाग को देखने की आवश्यकता नहीं है, क्योंकि WPP एक लॉगिंग से संबंधित तकनीक है, इसे अभी छोड़ दें।
बाद के भाग में, Microsoft ने एक चर v12 परिभाषित किया है, जो एक फ्लैग है जो यह निर्धारित करता है कि फ़ंक्शन निष्पादन जारी रखना है या सीधे बाहर निकलना है।
[[bittest]] .bittest dwFileCopyFlags image::bittest in spl.png[]