
यह कमजोर हस्ताक्षरित ड्राइवरों को हथियार बनाता है ताकि EDR कर्नेल कॉलबैक, ऑब्जेक्ट कॉलबैक, ETW TI प्रदाता, और यूज़रलैंड हुक्स को बायपास कर LSASS मेमोरी डंपिंग और क्रेडेंशियल निष्कर्षण किया जा सके।
EDRSandBlast एक C में लिखा गया एक उपकरण है जो एक कमजोर हस्ताक्षरित ड्राइवर को हथियार बनाकर EDR डिटेक्शन (Notify Routine कॉलबैक, Object Callbacks और ETW TI प्रदाता) और LSASS सुरक्षाओं को बायपास करता है। उपयोगकर्ता-स्तरीय निगरानी से बचने के लिए कई उपयोगकर्ता-लैंड अनहुकिंग तकनीकें भी लागू की गई हैं।
रिलीज़ के अनुसार, उपयोगकर्ता-लैंड (--usermode) और कर्नेल-लैंड (--kernelmode) तकनीकों के संयोजन का उपयोग EDR जांच के तहत LSASS मेमोरी को डंप करने के लिए किया गया, बिना अवरुद्ध हुए या उत्पाद (क्लाउड) कंसोल में "OS Credential Dumping"-संबंधित घटनाएँ उत्पन्न किए। परीक्षण 3 अलग-अलग EDR उत्पादों पर किए गए और प्रत्येक मामले में सफल रहे।
EDR उत्पाद विंडोज पर कर्नेल "Notify Routines" कॉलबैक का उपयोग करते हैं ताकि कर्नेल को सिस्टम गतिविधि, जैसे प्रक्रिया और थ्रेड निर्माण और छवियों (exe / DLL) के लोड होने की सूचना दी जा सके।
ये कर्नेल कॉलबैक कर्नेल-लैंड से परिभाषित किए जाते हैं, आमतौर पर कॉलबैक को लागू करने वाले ड्राइवर से, कई दस्तावेजित API (nt!PsSetCreateProcessNotifyRoutine, nt!PsSetCreateThreadNotifyRoutine, आदि) का उपयोग करके। ये API कर्नेल-स्पेस में अनिर्दिष्ट रूटीन्स की सरणियों में ड्राइवर-आपूर्ति किए गए कॉलबैक रूटीन्स को जोड़ते हैं:
PspCreateProcessNotifyRoutinePspCreateThreadNotifyRoutinePspLoadImageNotifyRoutineEDRSandBlast उन सरणियों में परिभाषित रूटीन्स को गिनता है और EDR ड्राइवरों की एक पूर्वनिर्धारित सूची से जुड़े किसी भी कॉलबैक रूटीन को हटा देता है (1000 से अधिक सुरक्षा उत्पादों के ड्राइवर समर्थित हैं, EDR ड्राइवर अनुभाग देखें)। गणना और हटाने को एक कमजोर ड्राइवर (देखें कमजोर ड्राइवर अनुभाग) के शोषण द्वारा प्रदान किए गए एक मनमाने कर्नेल मेमोरी पढ़ने/लिखने के प्रिमिटिव के माध्यम से संभव बनाया गया है।
उपरोक्त सरणियों के ऑफसेट को कई तकनीकों का उपयोग करके पुनर्प्राप्त किया जाता है, कृपया ऑफसेट अनुभाग देखें।
EDR (और यहाँ तक कि EPP) उत्पाद अक्सर nt!ObRegisterCallbacks कर्नेल API के उपयोग के माध्यम से "ऑब्जेक्ट कॉलबैक" पंजीकृत करते हैं। ये कॉलबैक सुरक्षा उत्पाद को विशिष्ट ऑब्जेक्ट प्रकारों (प्रक्रियाएँ, थ्रेड और डेस्कटॉप से संबंधित ऑब्जेक्ट कॉलबैक अब विंडोज द्वारा समर्थित हैं) पर प्रत्येक हैंडल निर्माण पर सूचित होने की अनुमति देते हैं। एक हैंडल निर्माण ऑब्जेक्ट खोलने पर हो सकता है (OpenProcess, OpenThread, आदि पर कॉल) साथ ही हैंडल डुप्लिकेशन (DuplicateHandle पर कॉल, आदि)।
इनमें से प्रत्येक संचालन पर कर्नेल द्वारा सूचित होने पर, एक सुरक्षा उत्पाद हैंडल निर्माण की वैधता का विश्लेषण कर सकता है (जैसे, कोई अज्ञात प्रक्रिया LSASS खोलने का प्रयास कर रही है), और यदि कोई खतरा पाया जाता है तो उसे अवरुद्ध भी कर सकता है।
ObRegisterCallbacks का उपयोग करके प्रत्येक कॉलबैक पंजीकरण पर, _OBJECT_TYPE ऑब्जेक्ट में मौजूद CallbackList दोहरी-लिंक्ड सूची में एक नया आइटम जोड़ा जाता है जो कॉलबैक से प्रभावित ऑब्जेक्ट के प्रकार (या तो प्रक्रिया, थ्रेड या डेस्कटॉप) का वर्णन करता है। दुर्भाग्य से, इन आइटमों का वर्णन एक ऐसी संरचना द्वारा किया जाता है जो Microsoft द्वारा दस्तावेजित नहीं है और न ही प्रतीक फ़ाइलों में प्रकाशित है। हालाँकि, विभिन्न ntoskrnl.exe संस्करणों से इसका अध्ययन करने से संकेत मिलता है कि संरचना कम से कम Windows 10 बिल्ड 10240 और 22000 (2015 से 2022) के बीच नहीं बदली।
उल्लिखित संरचना, जो एक ऑब्जेक्ट कॉलबैक पंजीकरण का प्रतिनिधित्व करती है, निम्नलिखित है:```C typedef struct OB_CALLBACK_ENTRY_t { LIST_ENTRY CallbackList; // linked element tied to _OBJECT_TYPE.CallbackList OB_OPERATION Operations; // bitfield : 1 for Creations, 2 for Duplications BOOL Enabled; // self-explanatory OB_CALLBACK* Entry; // points to the structure in which it is included POBJECT_TYPE ObjectType; // points to the object type affected by the callback POB_PRE_OPERATION_CALLBACK PreOperation; // callback function called before each handle operation POB_POST_OPERATION_CALLBACK PostOperation; // callback function called after each handle operation KSPIN_LOCK Lock; // lock object used for synchronization } OB_CALLBACK_ENTRY;
ऊपर उल्लिखित `OB_CALLBACK` संरचना भी अप्रलेखित है, और इसे निम्नलिखित द्वारा परिभाषित किया गया है:```C
typedef struct OB_CALLBACK_t {
USHORT Version; // usually 0x100
USHORT OperationRegistrationCount; // number of registered callbacks
PVOID RegistrationContext; // arbitrary data passed at registration time
UNICODE_STRING AltitudeString; // used to determine callbacks order
struct OB_CALLBACK_ENTRY_t EntryItems[1]; // array of OperationRegistrationCount items
WCHAR AltitudeBuffer[1]; // is AltitudeString.MaximumLength bytes long, and pointed by AltitudeString.Buffer
} OB_CALLBACK;
EDR-पंजीकृत ऑब्जेक्ट कॉलबैक को अक्षम करने के लिए, EDRSandblast में तीन तकनीकें लागू की गई हैं; हालांकि फिलहाल केवल एक ही सक्षम है।
OB_CALLBACK_ENTRY के Enabled फ़ील्ड का उपयोग करनायह EDRSandblast में सक्षम डिफ़ॉल्ट तकनीक है। EDR-संबंधित ऑब्जेक्ट कॉलबैक का पता लगाने और अक्षम करने के लिए, Process और Thread प्रकारों से जुड़े _OBJECT_TYPE ऑब्जेक्ट्स में स्थित CallbackList सूची को ब्राउज़ किया जाता है। दोनों _OBJECT_TYPE कर्नेल में सार्वजनिक ग्लोबल सिंबल, PsProcessType और PsThreadType द्वारा इंगित किए जाते हैं।
सूची के प्रत्येक आइटम को ऊपर वर्णित OB_CALLBACK_ENTRY संरचना में फिट होना माना जाता है (यह धारणा कम से कम इस लेखन के समय सभी Windows 10 बिल्ड में मान्य प्रतीत होती है)। PreOperation और PostOperation फ़ील्ड में परिभाषित फ़ंक्शंस को यह जांचने के लिए स्थित किया जाता है कि वे किसी EDR ड्राइवर से संबंधित हैं या नहीं, और यदि हाँ, तो कॉलबैक को Enabled फ़्लैग को टॉगल करके आसानी से अक्षम कर दिया जाता है।
हालांकि यह काफी सुरक्षित तकनीक है, इसका नुकसान यह है कि यह एक अनिर्दिष्ट संरचना पर निर्भर करती है; इस संरचना के असुरक्षित हेरफेर के जोखिम को कम करने के लिए, यह सत्यापित करने के लिए बुनियादी जाँच की जाती है कि कुछ फ़ील्ड्स के अपेक्षित मान हैं:
Enabled या तो TRUE है या FALSE (हँसें नहीं, एक BOOL एक int है, इसलिए यह 1 या 0 के अलावा कुछ और भी हो सकता है);Operations OB_OPERATION_HANDLE_CREATE, OB_OPERATION_HANDLE_DUPLICATE या दोनों है;ObjectType PsProcessType या PsThreadType पर इंगित करता है।CallbackList को अनलिंक करनाएक अन्य रणनीति जो किसी अनिर्दिष्ट संरचना पर निर्भर नहीं करती है (और इस प्रकार सैद्धांतिक रूप से NT कर्नेल परिवर्तनों के विरुद्ध अधिक मजबूत है) वह प्रक्रियाओं और थ्रेड दोनों के लिए संपूर्ण CallbackList को अनलिंक करना है। _OBJECT_TYPE ऑब्जेक्ट इस प्रकार है:```C
struct _OBJECT_TYPE {
LIST_ENTRY TypeList;
UNICODE_STRING Name;
[...]
_OBJECT_TYPE_INITIALIZER TypeInfo;
[...]
LIST_ENTRY CallbackList;
}
`Flink` और `Blink` पॉइंटर्स को `CallbackList` के `LIST_ENTRY` की ओर इंगित करना, `LIST_ENTRY` को स्वयं की ओर इंगित करके प्रभावी रूप से लिस्ट को खाली कर देता है। चूँकि `_OBJECT_TYPE` संरचना कर्नेल के सिंबल में प्रकाशित होती है, यह तकनीक हार्डकोडेड ऑफ़सेट/स्ट्रक्चर पर निर्भर नहीं करती। हालाँकि, इसकी कुछ कमियाँ हैं।
पहली कमी यह है कि केवल EDR के कॉलबैक को अक्षम करना संभव नहीं है; वास्तव में, यह तकनीक सभी ऑब्जेक्ट कॉलबैक को प्रभावित करती है जो "वैध" सॉफ़्टवेयर द्वारा पंजीकृत किए गए होंगे। फिर भी, यह ध्यान दिया जाना चाहिए कि विंडोज 10 पर (इस लेखन के समय) कोई भी पूर्व-स्थापित घटक ऑब्जेक्ट कॉलबैक का उपयोग नहीं करता है, इसलिए उन्हें अक्षम करने से मशीन की स्थिरता प्रभावित नहीं होनी चाहिए (और भी अधिक यदि अक्षमीकरण केवल अस्थायी हो)।
दूसरी कमी यह है कि प्रक्रिया या थ्रेड हैंडल संचालन OS के सामान्य संचालन में वास्तव में बार-बार (लगभग निरंतर) होते हैं। इस प्रकार, यदि उपयोग किया गया कर्नेल राइट प्रिमिटिव "एटॉमिकली" एक `QWORD` राइट नहीं कर सकता, तो इस बात की अच्छी संभावना है कि कर्नेल इसके ओवरराइट होने के बीच में `_OBJECT_TYPE.CallbackList.Flink` पॉइंटर तक पहुँच जाएगा। उदाहरण के लिए, MSI कमजोर ड्राइवर `RTCore64.sys` एक बार में केवल एक `DWORD` राइट कर सकता है, इसलिए पॉइंटर को ओवरराइट करने के लिए 2 अलग-अलग IOCTL की आवश्यकता होगी, जिनके बीच कर्नेल के इसका उपयोग करने की उच्च संभावना है (जिसके परिणामस्वरूप क्रैश होता है)। दूसरी ओर, कमजोर DELL ड्राइवर `DBUtil_2_3.sys` एक IOCTL में मनमाने आकार के राइट कर सकता है, इसलिए इस विधि का उपयोग करने से क्रैश होने का जोखिम नहीं होता।
#### ऑब्जेक्ट कॉलबैक को पूरी तरह से अक्षम करना
एक अंतिम तकनीक जो हमने पाई वह थी थ्रेड और प्रक्रियाओं के लिए ऑब्जेक्ट कॉलबैक समर्थन को पूरी तरह से अक्षम करना। प्रक्रिया और थ्रेड प्रकारों के अनुरूप `_OBJECT_TYPE` संरचना के अंदर एक `TypeInfo` फ़ील्ड होती है, जो दस्तावेज़ित `_OBJECT_TYPE_INITIALIZER` संरचना का अनुसरण करती है। बाद वाले में एक `ObjectTypeFlags` बिट फ़ील्ड होता है, जिसका `SupportsObjectCallbacks` फ़्लैग यह निर्धारित करता है कि वर्णित ऑब्जेक्ट प्रकार (Process, Thread, Desktop, Token, File, आदि) ऑब्जेक्ट कॉलबैक पंजीकरण का समर्थन करता है या नहीं। जैसा कि पहले कहा गया है, इस लेखन के समय विंडोज इंस्टॉलेशन पर केवल Process, Thread और Desktop ऑब्जेक्ट प्रकार ही इन कॉलबैक का समर्थन करते हैं।
चूँकि `SupportsObjectCallbacks` बिट `ObpCreateHandle` या `ObDuplicateObject` द्वारा `CallbackList` को पढ़ने से पहले (और निश्चित रूप से कॉलबैक निष्पादित करने से पहले) जाँचा जाता है, कर्नेल रनटाइम पर बिट को फ़्लिप करने से सभी ऑब्जेक्ट कॉलबैक निष्पादन प्रभावी रूप से अक्षम हो जाते हैं।
इस विधि का मुख्य दोष यह है कि *KPP* ("*PatchGuard*") कुछ (सभी?) `_OBJECT_TYPE` संरचनाओं की अखंडता की निगरानी करता है, और पैरामीटर 4 के `0x8` होने पर [`0x109 Bug Check`](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/bug-check-0x109---critical-structure-corruption) ट्रिगर करता है, जिसका अर्थ है कि एक ऑब्जेक्ट प्रकार संरचना को बदल दिया गया है।
हालाँकि, अक्षमीकरण / पुनः-सक्षमीकरण (और बीच में "दुर्भावनापूर्ण" कार्रवाई) को पर्याप्त तेज़ी से करना *PatchGuard* को "पछाड़ने" के लिए पर्याप्त होना चाहिए (जब तक कि आप बदकिस्मत न हों और एक आवधिक जाँच गलत समय पर न हो)।
### मिनीफ़िल्टर के कॉलबैक अनलिंकिंग के माध्यम से EDR बाईपास
विंडोज फ़िल्टर मैनेजर सिस्टम एक EDR को एक "मिनीफ़िल्टर" ड्राइवर लोड करने और I/O संचालनों, जैसे फ़ाइल खोलना, पढ़ना, लिखना आदि, के बारे में सूचित होने के लिए कॉलबैक पंजीकृत करने की अनुमति देता है।
यहाँ फ़िल्टर मैनेजर द्वारा उपयोग की जाने वाली विभिन्न आंतरिक संरचनाओं का एक त्वरित सारांश दिया गया है:
- फ़िल्टर मैनेजर अपनी मूल संरचना के रूप में एक "फ्रेम" (`_FLTP_FRAME`) स्थापित करता है;
- फ़िल्टर मैनेजर द्वारा प्रबंधित प्रत्येक "डिस्क" के लिए एक "वॉल्यूम" संरचना (`_FLT_VOLUME`) इंस्टेंसिएट की जाती है (यह पार्टीशन, शैडो कॉपी, या नेम्ड पाइप या रिमोट फ़ाइल सिस्टम के अनुरूप विशेष वॉल्यूम हो सकते हैं);
- प्रत्येक पंजीकृत मिनीफ़िल्टर ड्राइवर के लिए एक "फ़िल्टर" संरचना (`_FLT_FILTER`) होती है, जो इसके समर्थित संचालनों जैसे विभिन्न गुणों का वर्णन करती है;
- ये मिनीफ़िल्टर सभी वॉल्यूम से संलग्न नहीं होते हैं; प्रत्येक फ़िल्टर<->वॉल्यूम एसोसिएशन को चिह्नित करने के लिए एक "इंस्टेंस" (`_FLT_INSTANCE`) संरचना बनाई जाती है;
- मिनीफ़िल्टर कॉलबैक फ़ंक्शन पंजीकृत करते हैं जो विशिष्ट संचालनों (फ़ाइल खोलना, लिखना, पढ़ना आदि) से पहले और/या बाद में निष्पादित किए जाने हैं। ये कॉलबैक `_CALLBACK_NODE` संरचनाओं में वर्णित होते हैं, और विभिन्न तरीकों से एक्सेस किए जा सकते हैं:
- एक मिनीफ़िल्टर के एक इंस्टेंस द्वारा कार्यान्वित सभी `_CALLBACK_NODE` की एक सारणी `_FLT_INSTANCE` संरचना में पाई जा सकती है; सारणी IRP "मेजर फ़ंक्शन" कोड द्वारा अनुक्रमित होती है, जो कॉलबैक द्वारा संभाले जाने वाले संचालनों का प्रतिनिधित्व करने वाला एक स्थिरांक है (`IRP_MJ_CREATE`, `IRP_MJ_READ`, आदि)।
- इसके अलावा, एक विशिष्ट वॉल्यूम से जुड़े इंस्टेंस द्वारा कार्यान्वित सभी `_CALLBACK_NODE` को IRP मेजर फ़ंक्शन कोड द्वारा अनुक्रमित `_FLT_VOLUME.Callbacks.OperationLists` सरणी में संग्रहीत लिंक्ड लिस्ट में पुनर्गठित किया जाता है।
इन विभिन्न संरचनाओं को `EDRSandblast` द्वारा EDR-संबंधित ड्राइवरों से जुड़े फ़िल्टर का पता लगाने के लिए ब्राउज़ किया जाता है, और निगरानी फ़ंक्शन वाले कॉलबैक नोड्स की गणना की जाती है। उनके प्रभाव को अक्षम करने के लिए, नोड्स को उनकी सूचियों से अनलिंक कर दिया जाता है, जिससे वे फ़िल्टर मैनेजर को अस्थायी रूप से अदृश्य हो जाते हैं।
इस प्रकार, एक निर्दिष्ट अवधि के दौरान, EDR किसी भी फ़ाइल संचालन से पूरी तरह अनजान रह सकता है। एक बुनियादी उदाहरण डिस्क पर lsass मेमोरी डंप फ़ाइल का निर्माण होगा, जो EDR से कोई विश्लेषण नहीं ट्रिगर करेगा, और इस प्रकार फ़ाइल पर आधारित कोई पहचान नहीं होगी।
### ETW Microsoft-Windows-Threat-Intelligence प्रदाता के निष्क्रियीकरण के माध्यम से EDR बाईपास
`ETW Microsoft-Windows-Threat-Intelligence` प्रदाता कुछ विंडोज API के दुर्भावनापूर्ण रूप से सामान्यतः उपयोग किए जाने वाले उपयोगों के बारे में डेटा लॉग करता है। इसमें `nt!MiReadWriteVirtualMemory` API शामिल है, जिसे `nt!NtReadVirtualMemory` (जो `LSASS` मेमोरी डंप करने के लिए उपयोग किया जाता है) द्वारा कॉल किया जाता है और `nt!EtwTiLogReadWriteVm` फ़ंक्शन द्वारा निगरानी की जाती है।
EDR उत्पाद `ETW TI` प्रदाता द्वारा उत्पन्न लॉग का उपभोग क्रमशः `SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT` या `PS_PROTECTED_ANTIMALWARE_LIGHT` के रूप में चलने वाली सेवाओं या प्रक्रियाओं के माध्यम से कर सकते हैं, और एक `Early Launch Anti Malware (ELAM)` ड्राइवर से जुड़े होते हैं।
जैसा कि [`slaeryan` ने `CNO Development Labs` ब्लॉग पोस्ट](https://public.cnotools.studio/bring-your-own-vulnerable-kernel-driver-byovkd/exploits/data-only-attack-neutralizing-etwti-provider) में प्रकाशित किया है, `ETW TI` प्रदाता को कर्नेल मेमोरी में इसकी `ProviderEnableInfo` विशेषता को `0x0` पर पैच करके पूरी तरह से अक्षम किया जा सकता है। तकनीक के बारे में अधिक जानकारी के लिए उपरोक्त शानदार ब्लॉग पोस्ट देखें।
कर्नेल कॉलबैक हटाने के समान, आवश्यक `ntoskrnl.exe` ऑफ़सेट (`nt!EtwThreatIntProvRegHandleOffset`, `_ETW_REG_ENTRY` का `GuidEntry`, और `_ETW_GUID_ENTRY` का `ProviderEnableInfo`) विंडोज कर्नेल संस्करणों की संख्या के लिए `NtoskrnlOffsets.csv` फ़ाइल में गणना की जाती है।
### यूज़रलैंड हुकिंग बाईपास के माध्यम से EDR बाईपास
#### यूज़रलैंड हुकिंग कैसे काम करता है
प्रक्रियाओं द्वारा किए गए कार्यों की आसानी से निगरानी करने के लिए, EDR उत्पाद अक्सर एक तंत्र का उपयोग करते हैं जिसे *यूज़रलैंड हुकिंग* कहा जाता है। सबसे पहले, EDR उत्पाद एक कर्नेल कॉलबैक (आमतौर पर *इमेज लोडिंग* या *प्रक्रिया निर्माण* कॉलबैक, ऊपर देखें) पंजीकृत करते हैं जो उन्हें प्रत्येक प्रक्रिया प्रारंभ होने पर सूचित होने की अनुमति देता है।
जब Windows द्वारा एक प्रक्रिया लोड की जाती है, और इसके वास्तव में शुरू होने से पहले, EDR प्रक्रिया के एड्रेस स्पेस में कुछ कस्टम DLL इंजेक्ट करने में सक्षम होता है, जिसमें इसकी निगरानी तर्क होता है। लोड करते समय, यह DLL प्रत्येक फ़ंक्शन की शुरुआत में "*हुक*" इंजेक्ट करता है जिसे EDR द्वारा निगरानी किया जाना है। रनटाइम पर, जब निगरानी किए गए फ़ंक्शन निगरानी के तहत प्रक्रिया द्वारा कॉल किए जाते हैं, तो ये हुक नियंत्रण प्रवाह को EDR के DLL में मौजूद कुछ पर्यवेक्षण कोड की ओर मोड़ देते हैं, जो इसे इन कॉल के तर्कों और वापसी मानों का निरीक्षण करने की अनुमति देता है।
अधिकांश समय, निगरानी किए गए फ़ंक्शन सिस्टम कॉल होते हैं (जैसे `NtReadVirtualMemory`, `NtOpenProcess`, आदि), जिनका कार्यान्वयन `ntdll.dll` में निहित होता है। `Nt*` फ़ंक्शनों के कॉल को इंटरसेप्ट करने से उत्पाद यूज़रलैंड / कर्नेल-लैंड सीमा के जितना संभव हो उतना करीब (यूज़रलैंड में रहते हुए) हो सकते हैं, लेकिन कुछ उच्च-स्तरीय DLL के फ़ंक्शन भी निगरानी किए जा सकते हैं।
नीचे एक ही फ़ंक्शन के उदाहरण दिए गए हैं, EDR उत्पाद द्वारा हुक किए जाने से पहले और बाद में:```assembly
NtProtectVirtualMemory proc near
mov r10, rcx
mov eax, 50h
test byte ptr ds:7FFE0308h, 1
jnz short loc_18009D1E5
syscall
retn
loc_18009D1E5:
int 2Eh
retn
NtProtectVirtualMemory endp
Please provide the Markdown content to translate.```assembly NtProtectVirtualMemory proc near jmp sub_7FFC74490298 ; --> "hook", jump to EDR analysis function int 3 ; overwritten instructions int 3 ; overwritten instructions int 3 ; overwritten instructions test byte_7FFE0308, 1 ; <-- execution resumes here after analysis jnz short loc_7FFCB44AD1E5 syscall retn loc_7FFCB44AD1E5: int 2Eh retn NtProtectVirtualMemory endp
#### Hooks detection
Userland hooks में "कमजोरी" यह है कि वे userland memory में स्थित होते हैं, जिसका अर्थ है कि वे जांच के तहत प्रक्रिया द्वारा सीधे देखे और संशोधित किए जा सकते हैं। प्रक्रिया एड्रेस स्पेस में हुक्स का स्वचालित रूप से पता लगाने के लिए, मुख्य विचार डिस्क पर मूल DLL और मेमोरी में स्थित लाइब्रेरी के बीच अंतर की तुलना करना है, जिसे संभवतः किसी EDR द्वारा बदला गया हो। यह तुलना करने के लिए, EDRSandblast द्वारा निम्नलिखित चरणों का पालन किया जाता है:
* सभी लोड किए गए DLLs की सूची `PEB` में स्थित `InLoadOrderModuleList` के माध्यम से प्राप्त की जाती है (किसी भी API को कॉल करने से बचने के लिए जो मॉनिटर और संदिग्ध हो सकती है)
* प्रत्येक लोड किए गए DLL के लिए, डिस्क पर इसकी सामग्री पढ़ी जाती है और इसके हेडर पार्स किए जाते हैं। मेमोरी में स्थित संबंधित लाइब्रेरी को भी सेक्शन, एक्सपोर्ट्स आदि की पहचान करने के लिए पार्स किया जाता है।
* DLL के रिलोकेशन को पार्स किया जाता है और संबंधित लोड किए गए लाइब्रेरी के बेस एड्रेस को ध्यान में रखते हुए लागू किया जाता है। यह इन-मेमोरी लाइब्रेरी और डिस्क से उत्पन्न DLL दोनों की सामग्री को (जिन सेक्शन पर रिलोकेशन लागू होते हैं) बिल्कुल समान बनाता है, और इस प्रकार तुलना को विश्वसनीय बनाता है।
* एक्सपोर्टेड फंक्शन्स की गणना की जाती है और "इन-मेमोरी" और "ऑन-डिस्क" संस्करणों के पहले बाइट्स की तुलना की जाती है। कोई भी अंतर DLL लोड होने के बाद किए गए परिवर्तन को इंगित करता है, और इस प्रकार यह संभवतः एक EDR हुक है।
नोट: इस प्रक्रिया को सामान्यीकृत किया जा सकता है ताकि केवल एक्सपोर्टेड फंक्शन्स की शुरुआत में ही नहीं, बल्कि नॉन-राइटेबल सेक्शन में कहीं भी अंतर खोजा जा सके, उदाहरण के लिए यदि EDR उत्पाद फंक्शन के बीच में हुक लगाना शुरू कर दें :) इस प्रकार उपकरण द्वारा उपयोग नहीं किया जाता, इसे `findDiffsInNonWritableSections` में लागू किया गया है।
इन हुक्स द्वारा किए गए निगरानी को बायपास करने के लिए, कई तकनीकें संभव हैं, और प्रत्येक के अपने लाभ और कमियां हैं।
#### Hook bypass using ... unhooking
हुक-आधारित निगरानी को बायपास करने का सबसे सहज तरीका हुक्स को हटाना है। चूंकि हुक्स उस मेमोरी में मौजूद हैं जो प्रक्रिया द्वारा स्वयं सुलभ है, हुक को हटाने के लिए, प्रक्रिया बस यह कर सकती है:
* उस पेज पर अनुमतियां बदलें जहां हुक स्थित है (RX -> RWX या RW)
* मूल बाइट्स लिखें जो डिस्क DLL सामग्री के कारण ज्ञात हैं
* अनुमतियां वापस RX में बदलें
यह दृष्टिकोण काफी सरल है, और इसका उपयोग सभी पाए गए हुक्स को एक साथ हटाने के लिए किया जा सकता है। किसी आक्रामक उपकरण द्वारा इसकी शुरुआत में प्रदर्शन करने से, यह शेष कोड को हुकिंग तंत्र से पूरी तरह अनजान रहने और बिना निगरानी के सामान्य रूप से कार्य करने की अनुमति देता है।
हालाँकि, इसके दो मुख्य दोष हैं। EDR संभवतः `NtProtectVirtualMemory` के उपयोग की निगरानी कर रहा है, इसलिए इसका उपयोग उस पेज की अनुमतियों को बदलने के लिए करना जहां हुक स्थापित किए गए हैं, (कम से कम अवधारणात्मक रूप से) एक बुरा विचार है। साथ ही, यदि EDR द्वारा एक थ्रेड निष्पादित किया जाता है और समय-समय पर हुक्स की अखंडता की जांच करता है, तो यह भी कुछ पहचान को ट्रिगर कर सकता है।
कार्यान्वयन विवरण के लिए, `unhook()` फ़ंक्शन के कोड पथ की जांच करें जब `unhook_method` `UNHOOK_WITH_NTPROTECTVIRTUALMEMORY` हो।
**महत्वपूर्ण नोट: सरलता के लिए, इस तकनीक को EDRSandblast में अन्य बायपास तकनीकों को *प्रदर्शित* करने के लिए उपयोग की जाने वाली आधार तकनीक के रूप में लागू किया गया है; उनमें से प्रत्येक दर्शाता है कि `NtProtectVirtualMemory` का एक अनमॉनिटर्ड संस्करण कैसे प्राप्त किया जाए, लेकिन उसके बाद समान ऑपरेशन (एक विशिष्ट हुक को अनहुक करना) करता है।**
#### Hook bypass using a custom trampoline
एक विशिष्ट हुक को बायपास करने के लिए, बस "हुक के ऊपर से कूदना" और शेष फ़ंक्शन को ज्यों का त्यों निष्पादित करना संभव है। पहले, मॉनिटर किए गए फ़ंक्शन के मूल बाइट्स, जिन्हें EDR द्वारा हुक स्थापित करने के लिए अधिलेखित कर दिया गया था, DLL फ़ाइल से पुनर्प्राप्त किए जाने चाहिए। हमारे पिछले कोड उदाहरण में, ये निम्नलिखित निर्देशों के अनुरूप बाइट्स होंगे:```assembly
mov r10, rcx
mov eax, 50h
इन बाइट्स की पहचान करना एक सरल कार्य है, क्योंकि हम पहले बताए अनुसार, लाइब्रेरी के मेमोरी और डिस्क दोनों संस्करणों का एक साफ diff कर सकते हैं। फिर, हम एक जंप इंस्ट्रक्शन बनाते हैं जो नियंत्रण प्रवाह को हुक के ठीक बाद के कोड पर पुनर्निर्देशित करने के लिए बनाया गया है, जो पते NtProtectVirtualMemory + sizeof(overwritten_instructions) पर है।```assembly
jmp NtProtectVirtualMemory+8
अंत में, हम इन opcodes को संयोजित करते हैं, उन्हें (नवनिर्मित) निष्पादन योग्य मेमोरी में संग्रहीत करते हैं और उनके लिए एक पॉइंटर रखते हैं। इस वस्तु को "*ट्रैम्पोलिन*" कहा जाता है और फिर इसका उपयोग फ़ंक्शन पॉइंटर के रूप में किया जा सकता है, जो मूल `NtProtectVirtualMemory` फ़ंक्शन के बिल्कुल समतुल्य है।
इस तकनीक का मुख्य लाभ, जैसा कि नीचे दी गई सभी तकनीकों के लिए है, यह है कि हुक कभी मिटाया नहीं जाता, इसलिए EDR द्वारा हुकों पर किए गए किसी भी अखंडता जांच को पास हो जाना चाहिए। हालांकि, इसके लिए पहले लिखने योग्य फिर निष्पादन योग्य मेमोरी आवंटित करने की आवश्यकता होती है, जो एक शेलकोड आवंटन की विशिष्ट है, इस प्रकार EDR का ध्यान आकर्षित करती है।
कार्यान्वयन विवरण के लिए, `unhook()` फ़ंक्शन के कोड पथ की जाँच करें जब `unhook_method` `UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE` हो। कृपया याद रखें कि यह तकनीक केवल हमारे कार्यान्वयन में प्रदर्शित की गई है और अंततः, इसका उपयोग मेमोरी से हुकों को **हटाने** के लिए किया जाता है, जैसा कि नीचे दी गई हर तकनीक में होता है।
#### स्वयं EDR के ट्रैम्पोलिन का उपयोग करके हुक बाईपास
EDR उत्पाद को, अपने हुक के काम करने के लिए, मेमोरी में कहीं उन opcodes को सहेजना होगा जिन्हें उसने हटाया है। सबसे बुरी (*या "बेहतर", हमलावर के दृष्टिकोण से*), मूल निर्देशों का प्रभावी ढंग से उपयोग करने के लिए EDR ने संभवतः अपने लिए कहीं एक *ट्रैम्पोलिन* आवंटित किया है ताकि कॉल को इंटरसेप्ट करने के बाद मूल फ़ंक्शन को निष्पादित किया जा सके।
इस ट्रैम्पोलिन को खोजा जा सकता है और हुक किए गए फ़ंक्शन के प्रतिस्थापन के रूप में उपयोग किया जा सकता है, बिना निष्पादन योग्य मेमोरी आवंटित करने की आवश्यकता के, या `VirtualQuery` को छोड़कर किसी भी API को कॉल करने की आवश्यकता के, जो संभवतः एक हानिरहित फ़ंक्शन होने के कारण मॉनिटर नहीं किया जाता है।
मेमोरी में ट्रैम्पोलिन खोजने के लिए, हम `VirtualQuery` का उपयोग करके पूरे एड्रेस स्पेस को ब्राउज़ करते हैं और कमिटेड और निष्पादन योग्य मेमोरी की तलाश करते हैं। मेमोरी के ऐसे प्रत्येक क्षेत्र के लिए, हम एक जंप इंस्ट्रक्शन की तलाश करते हैं जो अधिलेखित निर्देशों के बाद के एड्रेस को लक्षित करता है (हमारे पिछले उदाहरण में `NtProtectVirtualMemory+8`)। फिर ट्रैम्पोलिन का उपयोग हुक को ट्रिगर किए बिना हुक किए गए फ़ंक्शन को कॉल करने के लिए किया जा सकता है।
यह तकनीक आश्चर्यजनक रूप से अच्छी तरह से काम करती है क्योंकि यह परीक्षण किए गए EDR पर लगभग सभी ट्रैम्पोलिन को पुनर्प्राप्त कर लेती है। कार्यान्वयन विवरण के लिए, `unhook()` फ़ंक्शन के कोड पथ की जाँच करें जब `unhook_method` `UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE` हो।
#### डुप्लिकेट DLL का उपयोग करके हुक बाईपास
`NtProtectVirtualMemory` फ़ंक्शन के एक अनमॉनिटर्ड संस्करण तक पहुंच प्राप्त करने का एक और सरल तरीका प्रक्रिया एड्रेस स्पेस में `ntdll.dll` लाइब्रेरी का एक डुप्लिकेट संस्करण लोड करना है। चूंकि दो समान DLLs को एक ही प्रक्रिया में लोड किया जा सकता है, बशर्ते उनके अलग-अलग नाम हों, हम बस वैध `ntdll.dll` फ़ाइल को किसी अन्य स्थान पर कॉपी कर सकते हैं, `LoadLibrary` (या लोडिंग प्रक्रिया को पुनः कार्यान्वित करके) का उपयोग करके इसे लोड कर सकते हैं, और उदाहरण के लिए `GetProcAddress` का उपयोग करके फ़ंक्शन तक पहुंच सकते हैं।
यह तकनीक समझने और लागू करने में बहुत सरल है, और सफलता की एक अच्छी संभावना है, क्योंकि अधिकांश EDR उत्पाद प्रक्रिया चलने के बाद नव लोड किए गए DLLs पर हुक पुनः स्थापित नहीं करते हैं। हालांकि, प्रमुख कमी यह है कि Microsoft हस्ताक्षरित बाइनरी को एक अलग नाम के तहत कॉपी करना अक्सर EDR उत्पादों द्वारा स्वयं संदिग्ध माना जाता है।
यह तकनीक फिर भी `EDRSandblast` में लागू की गई है। कार्यान्वयन विवरण के लिए, `unhook()` फ़ंक्शन के कोड पथ की जाँच करें जब `unhook_method` `UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY` हो।
#### प्रत्यक्ष सिस्कॉल का उपयोग करके हुक बाईपास
सिस्टम कॉल से संबंधित फ़ंक्शन का उपयोग करने के लिए, एक प्रोग्राम सिस्कॉल को (असेंबली में) पुनः कार्यान्वित कर सकता है ताकि संबंधित OS सुविधाओं को कॉल किया जा सके, बिना `ntdll.dll` में कोड को छूए, जो EDR द्वारा मॉनिटर किया जा सकता है। यह पूरी तरह से `ntdll.dll` में सिस्कॉल फ़ंक्शन पर किए गए किसी भी यूज़रलैंड हुकिंग को बायपास करता है।
फिर भी इसके कुछ नुकसान हैं। सबसे पहले, इसका अर्थ है कि प्रोग्राम को जिन फ़ंक्शन की आवश्यकता है, उनके सिस्कॉल नंबरों की सूची जानने में सक्षम होना, जो विंडोज़ के प्रत्येक संस्करण के लिए बदलता है। हालांकि, यह कई ह्यूरिस्टिक्स को लागू करके कम किया जाता है जो विंडोज़ NT के सभी पिछले संस्करणों में काम करने के लिए जाने जाते हैं (`ntdll` के `Zw*` एक्सपोर्ट्स को सॉर्ट करना, संबंधित `ntdll` फ़ंक्शन में `mov rax, #syscall_number` इंस्ट्रक्शन की खोज करना, आदि), और यह जांचना कि वे सभी एक ही परिणाम देते हैं (अधिक जानकारी के लिए `Syscalls.c` देखें)।
इसके अलावा, जो फ़ंक्शन तकनीकी रूप से सिस्कॉल नहीं हैं (जैसे `LoadLibraryX`/`LdrLoadDLL`) भी मॉनिटर किए जा सकते हैं, और सिस्कॉल का उपयोग करके आसानी से पुनः कार्यान्वित नहीं किए जा सकते।
प्रत्यक्ष सिस्कॉल तकनीक EDRSandblast में लागू की गई है। जैसा कि पहले कहा गया, इसका उपयोग केवल `NtProtectVirtualMemory` को सुरक्षित रूप से निष्पादित करने और सभी पहचाने गए हुकों को हटाने के लिए किया जाता है।
कार्यान्वयन विवरण के लिए, `unhook()` फ़ंक्शन के कोड पथ की जाँच करें जब `unhook_method` `UNHOOK_WITH_DIRECT_SYSCALL` हो।
### कमजोर ड्राइवरों का शोषण
जैसा कि पहले कहा गया, प्रत्येक कार्य जिसमें कर्नेल मेमोरी रीड या राइट की आवश्यकता होती है, इस प्रिमिटिव को देने के लिए एक कमजोर ड्राइवर पर निर्भर करता है। EDRSanblast में, रीड/राइट प्रिमिटिव प्रदान करने वाले नए ड्राइवर के लिए समर्थन जोड़ना "आसानी से" किया जा सकता है, केवल तीन फ़ंक्शन लागू करने की आवश्यकता है:
* एक `ReadMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer)` फ़ंक्शन, जो कर्नेल एड्रेस `Address` से `Size` बाइट्स को यूज़रलैंड बफर `Buffer` में कॉपी करता है;
* एक `WriteMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer)` फ़ंक्शन, जो यूज़रलैंड बफर `Buffer` से `Size` बाइट्स को कर्नेल एड्रेस `Address` में कॉपी करता है;
* एक `CloseDriverHandle_DRIVERNAME()` फ़ंक्शन जो सुनिश्चित करता है कि ड्राइवर के सभी हैंडल बंद हैं (अनइंस्टॉल ऑपरेशन से पहले आवश्यक है जो ड्राइवर-अज्ञेय है, फिलहाल के लिए)।
उदाहरण के लिए, वर्तमान में EDRSandblast द्वारा दो ड्राइवर समर्थित हैं, `RTCore64.sys` (SHA256: `01AA278B07B58DC46C84BD0B1B5C8E9EE4E62EA0BF7A695862444AF32E87F1FD`) और `DBUtils_2_3.sys` (SHA256: `0296e2ce999e67c76352613a718e11516fe1b0efc3ffdb8918fc999dd76a73a5`)। यदि उपयोग किए जाने वाले कमजोर ड्राइवर को बदलने की आवश्यकता है, या एक नया लागू किया गया है, तो `KernelMemoryPrimitives.h` में निम्नलिखित कोड को अपडेट किया जाना है।```C
#define RTCore 0
#define DBUtil 1
// Select the driver to use with the following #define
#define VULN_DRIVER RTCore
#if VULN_DRIVER == RTCore
#define DEFAULT_DRIVER_FILE TEXT("RTCore64.sys")
#define CloseDriverHandle CloseDriverHandle_RTCore
#define ReadMemoryPrimitive ReadMemoryPrimitive_RTCore
#define WriteMemoryPrimitive WriteMemoryPrimitive_RTCore
#elif VULN_DRIVER == DBUtil
#define DEFAULT_DRIVER_FILE TEXT("DBUtil_2_3.sys")
#define CloseDriverHandle CloseDriverHandle_DBUtil
#define ReadMemoryPrimitive ReadMemoryPrimitive_DBUtil
#define WriteMemoryPrimitive WriteMemoryPrimitive_DBUtil
#endif
यह निर्धारित करने के लिए वर्तमान में कई तकनीकों का उपयोग किया जाता है कि कोई विशिष्ट ड्राइवर या प्रक्रिया किसी EDR उत्पाद से संबंधित है या नहीं।
पहले, ड्राइवर का नाम सीधे इस उद्देश्य के लिए उपयोग किया जा सकता है। वास्तव में, Microsoft सभी ड्राइवर्स के लिए जिन्हें कर्नेल में कॉलबैक सम्मिलित करने की आवश्यकता होती है, "Altitudes" नामक विशिष्ट संख्याएँ आवंटित करता है। यह कॉलबैक निष्पादन में एक नियतात्मक क्रम की अनुमति देता है, जो पंजीकरण क्रम से स्वतंत्र होता है, लेकिन केवल ड्राइवर उपयोग पर आधारित होता है। उन ड्राइवर्स के (विक्रेताओं की) सूची जिन्होंने विशिष्ट altitude आरक्षित किया है, MSDN पर पाई जा सकती है। परिणामस्वरूप, सुरक्षा उत्पादों से जुड़े सुरक्षा ड्राइवर नामों की एक लगभग व्यापक सूची Microsoft द्वारा प्रदान की जाती है, मुख्यतः "FSFilter Anti-Virus" और "FSFilter Activity Monitor" सूचियों में। ड्राइवर नामों की ये सूचियाँ EDRSandblast में शामिल हैं, साथ ही अतिरिक्त योगदान भी।
इसके अलावा, EDR निष्पादन योग्य और DLL अक्सर विक्रेता के हस्ताक्षर प्रमाणपत्र का उपयोग करके डिजिटल रूप से हस्ताक्षरित होते हैं। इस प्रकार, किसी प्रक्रिया से जुड़े किसी निष्पादन योग्य या DLL के हस्ताक्षरकर्ता की जाँच करने से EDR उत्पादों की त्वरित पहचान हो सकती है।
साथ ही, ड्राइवर्स को कर्नेल स्पेस में लोड करने की अनुमति देने के लिए सीधे Microsoft द्वारा हस्ताक्षरित होना आवश्यक है। जबकि ड्राइवर का विक्रेता सीधे तौर पर ड्राइवर का हस्ताक्षरकर्ता नहीं होता है, ऐसा प्रतीत होता है कि विक्रेता का नाम अभी भी हस्ताक्षर के एक गुण के अंतर्गत शामिल है; हालाँकि इस पहचान तकनीक की अभी जाँच और कार्यान्वयन किया जाना बाकी है।
अंत में, जब EDRSandblast के लिए अज्ञात किसी EDR का सामना करना पड़ता है, तो सबसे अच्छा तरीका टूल को "audit" मोड में चलाना और कर्नेल कॉलबैक पंजीकृत करने वाले ड्राइवर्स की सूची की जाँच करना है; फिर ड्राइवर का नाम सूची में जोड़ा जा सकता है, टूल को पुनर्संकलित और पुनः चलाया जा सकता है।
Local Security Authority (LSA) Protection तंत्र, जिसे पहली बार Windows 8.1 और Windows Server 2012 R2 में पेश किया गया था, LSASS प्रक्रिया तक पहुँच को प्रतिबंधित करने के लिए Protected Process Light (PPL) तकनीक का लाभ उठाता है। PPL सुरक्षा उन कार्यों को नियंत्रित और प्रतिबंधित करती है, जैसे कि संरक्षित प्रक्रियाओं की मेमोरी इंजेक्शन या मेमोरी डंपिंग, यहाँ तक कि SeDebugPrivilege विशेषाधिकार रखने वाली प्रक्रिया से भी। प्रक्रिया सुरक्षा मॉडल के तहत, केवल उच्च सुरक्षा स्तरों वाली प्रक्रियाएँ ही संरक्षित प्रक्रियाओं पर संचालन कर सकती हैं।
_EPROCESS संरचना, जिसका उपयोग Windows कर्नेल कर्नेल मेमोरी में एक प्रक्रिया का प्रतिनिधित्व करने के लिए करता है, में एक _PS_PROTECTION फ़ील्ड शामिल है, जो अपने Type (_PS_PROTECTED_TYPE) और Signer (_PS_PROTECTED_SIGNER) विशेषताओं के माध्यम से एक प्रक्रिया के सुरक्षा स्तर को परिभाषित करता है।
कर्नेल मेमोरी में लिखकर, EDRSandblast प्रक्रिया अपने सुरक्षा स्तर को PsProtectedSignerWinTcb-Light तक अपग्रेड करने में सक्षम है। यह स्तर LSASS प्रक्रिया मेमोरी को डंप करने के लिए पर्याप्त है, क्योंकि यह PsProtectedSignerLsa-Light पर "हावी" है, जो RunAsPPL तंत्र के साथ चल रही LSASS प्रक्रिया का सुरक्षा स्तर है।
EDRSandBlast आत्म-सुरक्षा को निम्नानुसार लागू करता है:
NtQuerySystemInformation का उपयोग करके सभी सिस्टम हैंडल को लीक करें ताकि वर्तमान प्रक्रिया पर खुले हैंडल और कर्नेल मेमोरी में वर्तमान प्रक्रिया के EPROCESS संरचना का पता लगाया जा सके।_PS_PROTECTION फ़ील्ड को ओवरराइट करने के लिए कमजोर ड्राइवर की आर्बिट्रेरी रीड/राइट भेद्यता का उपयोग करें। _PS_PROTECTION फ़ील्ड के ऑफ़सेट (जो उपयोग में ntoskrnl संस्करण द्वारा परिभाषित होते हैं) EPROCESS संरचना के सापेक्ष NtoskrnlOffsets.csv फ़ाइल में गणना किए जाते हैं।Microsoft Credential Guard एक वर्चुअलाइजेशन-आधारित पृथक्करण तकनीक है, जिसे Microsoft के Windows 10 (Enterprise edition) में पेश किया गया था, जो LSASS प्रक्रिया में संग्रहीत क्रेडेंशियल्स तक सीधी पहुँच को रोकता है।
जब Credentials Guard सक्रिय होता है, तो Virtual Secure Mode में एक LSAIso (LSA Isolated) प्रक्रिया बनाई जाती है, जो एक ऐसी सुविधा है जो मेमोरी में डेटा की अतिरिक्त सुरक्षा प्रदान करने के लिए CPU के वर्चुअलाइजेशन एक्सटेंशन का लाभ उठाती है। LSAIso प्रक्रिया तक पहुँच NT AUTHORITY\SYSTEM सुरक्षा संदर्भ वाली पहुँच के लिए भी प्रतिबंधित है। हैश को संसाधित करते समय, LSA प्रक्रिया LSAIso प्रक्रिया को एक RPC कॉल करती है, और जारी रखने के लिए LSAIso परिणाम की प्रतीक्षा करती है। इस प्रकार, LSASS प्रक्रिया में कोई रहस्य नहीं होगा और इसके बजाय यह LSA Isolated Data संग्रहीत करेगी।
जैसा कि N4kedTurtle द्वारा किए गए मूल शोध में कहा गया है: "क्रेडेंशियल गार्ड वाले सिस्टम पर Wdigest को मेमोरी में g_fParameter_useLogonCredential और g_IsCredGuardEnabled के मानों को पैच करके सक्षम किया जा सकता है"। Wdigest के सक्रियण के परिणामस्वरूप किसी भी नए इंटरैक्टिव लॉगऑन के लिए स्पष्ट टेक्स्ट क्रेडेंशियल्स LSASS मेमोरी में संग्रहीत होंगे (सिस्टम के रिबूट की आवश्यकता नहीं है)। इस तकनीक के बारे में अधिक जानकारी के लिए मूल शोध ब्लॉग पोस्ट देखें।
EDRSandBlast केवल मूल PoC को थोड़ा और opsec-अनुकूल बनाता है और कई wdigest.dll संस्करणों के लिए समर्थन प्रदान करता है (g_fParameter_useLogonCredential और g_IsCredGuardEnabled के लिए गणना किए गए ऑफ़सेट के माध्यम से)।
कर्नेल मॉनिटरिंग बायपास संचालन को विश्वसनीय रूप से करने के लिए, EDRSandblast को यह जानना आवश्यक है कि कर्नेल मेमोरी को वास्तव में कहाँ पढ़ना और लिखना है। यह लक्षित इमेज (ntoskrnl.exe, wdigest.dll) के अंदर वैश्विक चरों के ऑफ़सेट के साथ-साथ संरचनाओं में विशिष्ट फ़ील्ड के ऑफ़सेट का उपयोग करके किया जाता है, जिनकी परिभाषाएँ Microsoft द्वारा प्रतीक फ़ाइलों में प्रकाशित की जाती हैं। ये ऑफ़सेट लक्षित इमेज के प्रत्येक बिल्ड के लिए विशिष्ट होते हैं, और किसी विशिष्ट प्लेटफ़ॉर्म संस्करण के लिए कम से कम एक बार एकत्र किए जाने चाहिए।
EDRSandblast द्वारा उपयोग की जाने वाली संरचनाओं और चरों का पता लगाने के लिए पैटर्न खोजों के बजाय "हार्डकोडेड" ऑफ़सेट का उपयोग करने का विकल्प इस तथ्य से उचित है कि कर्नेल कॉलबैक जोड़ने/हटाने के लिए जिम्मेदार अप्रलेखित API परिवर्तन के अधीन हैं और कर्नेल मेमोरी को गलत पते पर पढ़ने या लिखने का कोई भी प्रयास Bug Check (Blue Screen of Death) का कारण बन सकता है (और अक्सर होगा)। एक मशीन क्रैश रेड-टीमिंग और सामान्य पैठ परीक्षण दोनों परिदृश्यों में स्वीकार्य नहीं है, क्योंकि एक मशीन जो क्रैश होती है, वह रक्षकों द्वारा अत्यधिक दिखाई देती है, और हमले के समय मेमोरी में मौजूद किसी भी क्रेडेंशियल को खो देगी।
Windows के प्रत्येक विशिष्ट संस्करण के लिए ऑफ़सेट पुनर्प्राप्त करने के लिए, दो दृष्टिकोण लागू किए गए हैं।
आवश्यक ntoskrnl.exe और wdigest.dll ऑफ़सेट को दिए गए ExtractOffsets.py Python स्क्रिप्ट का उपयोग करके निकाला जा सकता है, जो PDB फ़ाइलों से प्रतीकों को डाउनलोड और पार्स करने के लिए radare2 और r2pipe पर निर्भर करता है, और उनसे आवश्यक ऑफ़सेट निकालता है। ऑफ़सेट को बाद में EDRSandblast द्वारा उपयोग के लिए CSV फ़ाइलों में संग्रहीत किया जाता है।
Windows बिल्ड की एक विस्तृत श्रृंखला को तुरंत समर्थन देने के लिए, ntoskrnl.exe और wdigest.dll बाइनरी के कई संस्करण Winbindex द्वारा संदर्भित हैं, और ExtractOffsets.py द्वारा स्वचालित रूप से डाउनलोड किए जा सकते हैं (और उनके ऑफ़सेट निकाले जा सकते हैं)। यह लगभग उन सभी फ़ाइलों से ऑफ़सेट निकालने की अनुमति देता है जो कभी Windows अद्यतन पैकेजों में प्रकाशित हुई हैं (आज तक 450+ ntoskrnl.exe और 30+ wdigest.dll संस्करण उपलब्ध और पूर्व-गणना किए गए हैं)।
EDRSandBlast में एक अतिरिक्त विकल्प लागू किया गया है ताकि प्रोग्राम स्वयं Microsoft Symbol Server से आवश्यक .pdb फ़ाइलें डाउनलोड कर सके, आवश्यक ऑफ़सेट निकाल सके, और यदि मौजूद हो तो संबंधित .csv फ़ाइलों को भी अद्यतन कर सके।
--internet विकल्प का उपयोग करने से टूल का निष्पादन बहुत सरल हो जाता है, जबकि एक अतिरिक्त OpSec जोखिम पेश करता है, क्योंकि इस प्रक्रिया के दौरान एक .pdb फ़ाइल डाउनलोड की जाती है और डिस्क पर छोड़ी जाती है। यह प्रतीक डेटाबेस को पार्स करने के लिए उपयोग किए जाने वाले dbghelp.dll फ़ंक्शन द्वारा आवश्यक है; हालाँकि, भविष्य में इस आवश्यकता को दूर करने और टूल के पदचिह्न को कम करने के लिए पूर्ण इन-मेमोरी PDB पार्सिंग लागू की जा सकती है।
EDRSandblast सार्वजनिक रूप से कम से कम 3 कमजोर ड्राइवर्स, gdrv.sys (डिफ़ॉल्ट),
RTCore64.sys और DBUtil_2_3.sys के लिए समर्थन लागू करता है। वास्तव में उपयोग किया जाने वाला ड्राइवर टूल के संकलन से पहले तय किया जाता है (देखें #define VULN_DRIVER <driver name> in includes/KernelMemoryPrimitive.h)। कर्नेल संचालन के काम करने के लिए EDRSandblast को एक कमजोर ड्राइवर की प्रतिलिपि डाउनलोड और प्रदान की जानी चाहिए।
परीक्षण किए गए ड्राइवर्स के हैश प्रत्येक Driver<name>.c फ़ाइल की शुरुआत में उल्लिखित हैं जो EDRSanblast द्वारा उपयोग की जाने वाली कर्नेल मेमोरी रीड और राइट प्रिमिटिव को लागू करता है। इन हैश का उपयोग करके, ड्राइवर नमूने इंटरनेट पर, विशेष रूप से https://www.loldrivers.io पर आसानी से पाए जा सकते हैं।
समर्थित कमजोर ड्राइवर्स की सूची डाउनलोड लिंक के साथ यहाँ दी गई है:
Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] <audit | dump | cmd | credguard | firewall | load_unsigned_driver> [--usermode] [--unhook-method ] [--direct-syscalls] [--add-dll ]* [--kernelmode] [--dont-unload-driver] [--no-restore] [--nt-offsets <NtoskrnlOffsets.csv>] [--fltmgr-offsets <FltmgrOffsets.csv>] [--wdigest-offsets <WdigestOffsets.csv>] [--ci-offsets <CiOffsets.csv>] [--internet] [--vuln-driver <RTCore64.sys>] [--vuln-service <SERVICE_NAME>] [--unsigned-driver <evil.sys>] [--unsigned-service <SERVICE_NAME>] [--no-kdp] [-o | --dump-output <DUMP_FILE>]
### विकल्प```
-h | --help Show this help message and exit.
-v | --verbose Enable a more verbose output.
Actions mode:
audit Display the user-land hooks and / or Kernel callbacks without taking actions.
dump Dump the process specified by --process-name (LSASS process by default), as '<process_name>' in the current directory or at the
specified file using -o | --output <DUMP_FILE>.
cmd Open a cmd.exe prompt.
credguard Patch the LSASS process' memory to enable Wdigest cleartext passwords caching even if
Credential Guard is enabled on the host. No kernel-land actions required.
firewall Add Windows firewall rules to block network access for the EDR processes / services.
load_unsigned_driver Load the specified unsigned driver, bypassing Driver Signature Enforcement (DSE).
WARNING: currently an experimental feature, only works if KDP is not present and enabled.
--usermode Perform user-land operations (DLL unhooking).
--kernelmode Perform kernel-land operations (Kernel callbacks removal and ETW TI disabling).
Hooking-related options:
--add-dll <dll name or path> Loads arbitrary libraries into the process' address space, before starting
anything.This can be useful to audit userland hooking for DLL that are not
loaded by default by this program. Use this option multiple times to load
multiple DLLs all at once.
Example of interesting DLLs to look at: user32.dll, ole32.dll, crypt32.dll,
samcli.dll, winhttp.dll, urlmon.dll, secur32.dll, shell32.dll...
--unhook-method <N> Choose the userland un-hooking technique, from the following:
0 Do not perform any unhooking (used for direct syscalls operations).
1 (Default) Uses the (probably monitored) NtProtectVirtualMemory function in ntdll to remove all
present userland hooks.
2 Constructs a 'unhooked' (i.e. unmonitored) version of NtProtectVirtualMemory, by allocating an executable trampoline jumping over the hook, and remove all present
userland hooks.
3 Searches for an existing trampoline allocated by the EDR itself, to get an 'unhooked'
(i.e. unmonitored) version of NtProtectVirtualMemory, and remove all present userland
hooks.
4 Loads an additional version of ntdll library into memory, and use the (hopefully unmonitored) version of NtProtectVirtualMemory present in this library to remove all
present userland hooks.
5 Allocates a shellcode that uses a direct syscall to call NtProtectVirtualMemory, and uses it to remove all detected hooks
--direct-syscalls Use direct syscalls to dump the selected process memory without unhooking unserland hooks.
BYOVD options:
--dont-unload-driver Keep the vulnerable driver installed on the host
Default to automatically unsinstall the driver.
--no-restore Do not restore the EDR drivers' Kernel Callbacks that were removed.
Default to restore the callbacks.
--vuln-driver <gdrv.sys> Path to the vulnerable driver file.
Default to 'gdrv.sys' in the current directory.
--vuln-service <SERVICE_NAME> Name of the vulnerable service to intall / start.
Driver sideloading options:
--unsigned-driver <evil.sys> Path to the unsigned driver file.
Default to 'evil.sys' in the current directory.
--unsigned-service <SERVICE_NAME> Name of the unsigned driver's service to intall / start.
--no-kdp Switch to g_CiOptions patching method for disabling DSE (default is callback swapping).
Offset-related options:
--nt-offsets <NtoskrnlOffsets.csv> Path to the CSV file containing the required ntoskrnl.exe's offsets.
Default to 'NtoskrnlOffsets.csv' in the current directory.
--fltmgr-offsets <FltmgrOffsets.csv> Path to the CSV file containing the required fltmgr.sys's offsets
Default to 'FltmgrOffsets.csv' in the current directory.
--wdigest-offsets <WdigestOffsets.csv> Path to the CSV file containing the required wdigest.dll's offsets
(only for the 'credguard' mode).
Default to 'WdigestOffsets.csv' in the current directory.
--ci-offsets <CiOffsets.csv> Path to the CSV file containing the required ci.dll's offsets
(only for the 'load_unsigned_driver' mode).
Default to 'WdigestOffsets.csv' in the current directory.
-i | --internet Enables automatic symbols download from Microsoft Symbol Server
If a corresponding *Offsets.csv file exists, appends the downloaded offsets to the file for later use
OpSec warning: downloads and drops on disk a PDB file for the corresponding image
Dump options:
-o | --dump-output <DUMP_FILE> Output path to the dump file that will be generated by the 'dump' mode.
Default to 'process_name' in the current directory.
--process-name <NAME> File name of the process to dump (defaults to 'lsass.exe')
EDRSandBlast (केवल x64) को Visual Studio 2019 पर निर्मित किया गया था (Windows SDK
संस्करण: 10.0.19041.0 और प्लेटफ़ॉर्म टूलसेट: Visual Studio 2019 (v142)).
ध्यान दें कि ExtractOffsets.py का केवल Windows पर परीक्षण किया गया है।```
pip.exe install -m .\requirements.txt
ExtractOffsets.py [-h] -i INPUT [-o OUTPUT] [-d] mode
positional arguments: mode ntoskrnl or wdigest. Mode to download and extract offsets for either ntoskrnl or wdigest
optional arguments: -h, --help show this help message and exit -i INPUT, --input INPUT Single file or directory containing ntoskrnl.exe / wdigest.dll to extract offsets from. If in download mode, the PE downloaded from MS symbols servers will be placed in this folder. -o OUTPUT, --output OUTPUT CSV file to write offsets to. If the specified file already exists, only new ntoskrnl versions will be downloaded / analyzed. Defaults to NtoskrnlOffsets.csv / WdigestOffsets.csv in the current folder. -d, --download Flag to download the PE from Microsoft servers using list of versions from winbindex.m417z.com.
## पहचान
रक्षक (EDR विक्रेता, Microsoft, EDR के टेलीमेट्री देखने वाले SOC विश्लेषक, ...) के दृष्टिकोण से, इस प्रकार की तकनीकों का पता लगाने या रोकने के लिए कई संकेतकों का उपयोग किया जा सकता है।
### ड्राइवर व्हाइटलिस्टिंग
चूंकि टूल द्वारा कर्नेल-मोड मेमोरी में किए गए प्रत्येक कार्य को मनमाना सामग्री पढ़ने/लिखने के लिए एक कमजोर ड्राइवर पर निर्भर करता है, ड्राइवर लोडिंग घटनाओं की EDR उत्पाद (या SOC विश्लेषकों) द्वारा गहन जांच की जानी चाहिए, और किसी भी असामान्य ड्राइवर लोडिंग पर अलर्ट बढ़ाना चाहिए, या ज्ञात कमजोर ड्राइवरों को ब्लॉक भी करना चाहिए। यह बाद वाला दृष्टिकोण [Microsoft द्वारा स्वयं अनुशंसित](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules) है: कोई भी HVCI (*Hypervisor-protected code integrity*) सक्षम Windows डिवाइस एक ड्राइवर ब्लॉकलिस्ट एम्बेड करता है, और यह धीरे-धीरे Windows पर एक डिफ़ॉल्ट व्यवहार बन जाएगा (यह Windows 11 पर पहले से ही है)।
### कर्नेल-मेमोरी अखंडता जांच
चूंकि एक हमलावर मेमोरी में समान क्रियाएं करने के लिए अभी भी एक अज्ञात कमजोर ड्राइवर का उपयोग कर सकता है, EDR ड्राइवर समय-समय पर जांच सकता है कि उसके कर्नेल कॉलबैक अभी भी पंजीकृत हैं, या तो सीधे कर्नेल मेमोरी का निरीक्षण करके (जैसे यह टूल करता है), या केवल ईवेंट ट्रिगर करके (प्रक्रिया निर्माण, थ्रेड निर्माण, इमेज लोडिंग, आदि) और जांच करके कि कॉलबैक फ़ंक्शन वास्तव में एक्जीक्यूटिव कर्नेल द्वारा कॉल किए जाते हैं।
एक साइड नोट के रूप में, इस प्रकार की डेटा संरचना को हाल के [Kernel Data Protection (KDP)](https://www.microsoft.com/security/blog/2020/07/08/introducing-kernel-data-protection-a-new-platform-security-technology-for-preventing-data-corruption/) तंत्र के माध्यम से संरक्षित किया जा सकता है, जो Virtual Based Security पर निर्भर करता है, ताकि कर्नेल कॉलबैक सरणी को सही API को कॉल किए बिना अ-लिखने योग्य बनाया जा सके।
यही तर्क संवेदनशील ETW चर जैसे `ProviderEnableInfo` पर लागू हो सकता है, जिसका इस टूल द्वारा ETW Threat Intelligence ईवेंट जनरेशन को अक्षम करने के लिए दुरुपयोग किया जाता है।
### उपयोगकर्ता-मोड पहचान
पहला संकेतक कि एक प्रक्रिया सक्रिय रूप से उपयोगकर्ता-भूमि हुकिंग से बचने की कोशिश कर रही है, लोड किए गए मॉड्यूल के अनुरूप प्रत्येक DLL के लिए फ़ाइल एक्सेस है; सामान्य निष्पादन में, एक उपयोगकर्ता-भूमि प्रक्रिया को शायद ही कभी `LoadLibrary` कॉल के बाहर DLL फ़ाइलों को पढ़ने की आवश्यकता होती है, विशेष रूप से `ntdll.dll`।
API हुकिंग को बायपास होने से बचाने के लिए, EDR उत्पाद समय-समय पर जांच सकते हैं कि प्रत्येक निगरानी प्रक्रिया के अंदर मेमोरी में हुक बदले नहीं गए हैं।
अंत में, हुकिंग बायपास (ट्रम्पोलिन का दुरुपयोग, डायरेक्ट syscalls का उपयोग, आदि) का पता लगाने के लिए जिसमें हुक हटाना शामिल नहीं है, EDR उत्पाद संभावित रूप से दुरुपयोग किए गए syscalls से संबद्ध कर्नेल कॉलबैक पर भरोसा कर सकते हैं (जैसे `NtCreateProcess` syscall के लिए `PsCreateProcessNotifyRoutine`, `NtOpenProcess` syscall के लिए `ObRegisterCallbacks`, आदि), और यह निर्धारित करने के लिए उपयोगकर्ता-मोड कॉल-स्टैक विश्लेषण कर सकते हैं कि क्या syscall एक सामान्य पथ (`kernel32.dll` -> `ntdll.dll` -> syscall) या एक असामान्य पथ (जैसे `program.exe` -> डायरेक्ट syscall) से ट्रिगर हुआ था।
## स्वीकृतियाँ
- कर्नेल कॉलबैक गणना और निष्कासन:
https://github.com/br-sn/CheekyBlinder
- कमजोर `Micro-Star MSI Afterburner` ड्राइवर के माध्यम से कर्नेल मेमोरी रीड/राइट प्रिमिटिव:
https://github.com/Barakat/CVE-2019-16098/
- ETW Threat Intelligence प्रदाता को अक्षम करना:
https://public.cnotools.studio/bring-your-own-vulnerable-kernel-driver-byovkd/exploits/data-only-attack-neutralizing-etwti-provider
- ड्राइवर स्थापना/अनइंस्टॉल: https://github.com/gentilkiwi/mimikatz
- EDR ड्राइवर नामों की प्रारंभिक सूची:
https://github.com/SadProcessor/SomeStuff/blob/master/Invoke-EDRCheck.ps1
- `LSASS` मेमोरी पैचिंग के माध्यम से `Wdigest` को पुनः सक्षम करके क्रेडेंशियल गार्ड को बायपास करना:
https://teamhydra.blog/2020/08/25/bypassing-credential-guard/
## लेखक
[Thomas DIOT (Qazeer)](https://github.com/Qazeer/)
[Maxime MEIGNAN (themaks)](https://github.com/themaks)
## योगदानकर्ताओं का धन्यवाद
- [v1k1ngfr](https://github.com/v1k1ngfr): ड्राइवर सिग्नेचर एनफोर्समेंट बायपास (`g_CiOptions` पैचिंग के माध्यम से) और GDRV.sys ड्राइवर समर्थन के लिए
- [Windy Bug](https://github.com/0mWindyBug): KDP-संगत ड्राइवर सिग्नेचर एनफोर्समेंट बायपास (कॉलबैक स्वैपिंग के माध्यम से) और मिनीफिल्टर बायपास सुविधा में उनके प्रमुख योगदान के लिए
## लाइसेंस
CC BY 4.0 लाइसेंस - https://creativecommons.org/licenses/by/4.0/
| Supported driver | Download link | SHA256 |
|---|
GDRV.sys | LOLDrivers link | 31f4cfb4c71da44120752721103a16512444c13c2ac2d857a7e6f13cb679b427 |
RTCore64.sys | LOLDrivers link | 01aa278b07b58dc46c84bd0b1b5c8e9ee4e62ea0bf7a695862444af32e87f1fd |
DBUtil_2_3.sys | LOLDrivers link | 0296e2ce999e67c76352613a718e11516fe1b0efc3ffdb8918fc999dd76a73a5 |