
केवल NTAPI फ़ंक्शनों का उपयोग करके lsass को डंप करें, मिनीडंप फ़ाइलों को हाथ से तैयार करके (MiniDumpWriteDump के बिना!!!)
NativeDump केवल NTAPIs का उपयोग करके lsass प्रक्रिया को डंप करने की अनुमति देता है, जो केवल उन स्ट्रीम्स के साथ एक Minidump फ़ाइल उत्पन्न करता है जिन्हें Mimikatz या Pypykatz जैसे उपकरणों द्वारा पार्स करने की आवश्यकता होती है (SystemInfo, ModuleList और Memory64List स्ट्रीम्स)।

प्रोग्राम में आउटपुट फ़ाइल के लिए एक वैकल्पिक तर्क है, डिफ़ॉल्ट फ़ाइल नाम 'proc_<PID>.dmp' है:
NativeDump.exe [DUMP_FILE]

यह उपकरण नवीनतम Windows संस्करणों के विरुद्ध सबसे सामान्य सुरक्षा समाधानों (Microsoft Defender for Endpoints, CrowdStrike...) के साथ परीक्षण किया गया है और ठीक काम करता है, लेकिन चुपके आपके द्वारा चुने गए 'स्वाद' पर निर्भर करेगा: सर्वोत्तम परिणामों के लिए असामान्य भाषाओं का उपयोग करें और बाइनरी को अनुकूलित करें! हालाँकि, यह काम नहीं करता है यदि PPL सक्षम है या PEB संरचना पढ़ने योग्य नहीं है। अद्यतन: अब PEB को पढ़े बिना प्रोग्राम को निष्पादित करना संभव है, peb-unreadable शाखा देखें :)
इस तकनीक के कुछ लाभ हैं:
आप प्रोजेक्ट को विभिन्न 'स्वादों' (या भाषाओं) में पा सकते हैं:
main - .NET मूल कार्यान्वयन (यह शाखा)
python-flavour - Python कार्यान्वयन जिसमें 3 ntdll.dll ओवरराइट विधियाँ + रिमोट मशीन पर एक्सफ़िल्ट्रेट करना
golang-flavour - Golang कार्यान्वयन जिसमें 3 ntdll.dll ओवरराइट विधियाँ + रिमोट मशीन पर एक्सफ़िल्ट्रेट करना
c-flavour - C/C++ कार्यान्वयन जिसमें 3 ntdll.dll ओवरराइट विधियाँ
bof-flavour - BOF फ़ाइल जिसमें 3 ntdll.dll ओवरराइट विधियाँ
rust-flavour - Rust कार्यान्वयन @safedv द्वारा
crystal-flavour - Crystal कार्यान्वयन जिसमें ntdll.dll ओवरराइट क्षमताएँ
nim-flavour - Nim कार्यान्वयन जिसमें ntdll.dll ओवरराइट क्षमताएँ
.NET का उपयोग करने वाली अन्य दिलचस्प शाखाएँ:
remote - रिमोट मशीन पर एक्सफ़िल्ट्रेट करना + 3 ntdll.dll ओवरराइट विधियाँ + डायनामिक फ़ंक्शन रिज़ॉल्यूशन + स्ट्रिंग AES एन्क्रिप्शन + XOR-एन्कोडिंग Minidump सामग्री
all-modules - सभी मॉड्यूल के लिए जानकारी प्राप्त करें (केवल lsasrv.dll नहीं)
peb-unreadable - lsass की PEB संरचना को पढ़े बिना कार्यान्वयन + 3 ntdll.dll ओवरराइट विधियाँ
Minidump के अप्रलेखित संरचनाओं को पढ़ने के बाद, इसकी संरचना को इस प्रकार संक्षेपित किया जा सकता है:

मैंने एक पार्सिंग टूल बनाया है जो सहायक हो सकता है: MinidumpParser। हम एक वैध फ़ाइल बनाने पर ध्यान केंद्रित करेंगे जिसमें हेडर, स्ट्रीम निर्देशिका और Minidump फ़ाइल के लिए आवश्यक केवल 3 स्ट्रीम (SystemInfo, ModuleList और Memory64List स्ट्रीम्स) के आवश्यक मान हों, ताकि Mimikatz/Pypykatz द्वारा पार्स किया जा सके।
हेडर एक 32-बाइट्स संरचना है जिसे C# में इस प्रकार परिभाषित किया जा सकता है:
public struct MinidumpHeader
{
public uint Signature;
public ushort Version;
public ushort ImplementationVersion;
public ushort NumberOfStreams;
public uint StreamDirectoryRva;
public uint CheckSum;
public IntPtr TimeDateStamp;
}
आवश्यक मान हैं:
स्ट्रीम निर्देशिका में प्रत्येक प्रविष्टि एक 12-बाइट्स संरचना है, इसलिए 3 प्रविष्टियाँ होने पर आकार 36 बाइट्स है। एक प्रविष्टि के लिए C# स्ट्रक्ट परिभाषा है:
public struct MinidumpStreamDirectoryEntry
{
public uint StreamType;
public uint Size;
public uint Location;
}
क्षेत्र 'StreamType' स्ट्रीम के प्रकार को एक पूर्णांक या आईडी के रूप में दर्शाता है, कुछ सबसे प्रासंगिक हैं:
पहली स्ट्रीम SystemInformation स्ट्रीम है, जिसका आईडी 7 है। इसका आकार 56 बाइट्स है और यह स्ट्रीम निर्देशिका के बाद ऑफ़सेट 68 (0x44) पर स्थित होगी। इसकी C# परिभाषा है:
public struct SystemInformationStream
{
public ushort ProcessorArchitecture;
public ushort ProcessorLevel;
public ushort ProcessorRevision;
public byte NumberOfProcessors;
public byte ProductType;
public uint MajorVersion;
public uint MinorVersion;
public uint BuildNumber;
public uint PlatformId;
public uint UnknownField1;
public uint UnknownField2;
public IntPtr ProcessorFeatures;
public IntPtr ProcessorFeatures2;
public uint UnknownField3;
public ushort UnknownField14;
public byte UnknownField15;
}
आवश्यक मान हैं:
दूसरी स्ट्रीम ModuleList स्ट्रीम है, जिसका आईडी 4 है। यह SystemInformation स्ट्रीम के बाद ऑफ़सेट 124 (0x7C) पर स्थित है और इसका आकार भी निश्चित 112 बाइट्स होगा, क्योंकि इसमें केवल एक मॉड्यूल की प्रविष्टि होगी, जो पार्स को सही होने के लिए आवश्यक है: 'lsasrv.dll'।
इस स्ट्रीम के लिए सामान्य संरचना एक 4-बाइट मान है जिसमें प्रविष्टियों की संख्या होती है, उसके बाद प्रत्येक मॉड्यूल के लिए 108-बाइट प्रविष्टियाँ होती हैं:
public struct ModuleListStream
{
public uint NumberOfModules;
public ModuleInfo[] Modules;
}
चूंकि केवल एक है, यह सरल हो जाता है:
public struct ModuleListStream
{
public uint NumberOfModules;
public IntPtr BaseAddress;
public uint Size;
public uint UnknownField1;
public uint Timestamp;
public uint PointerName;
public IntPtr UnknownField2;
public IntPtr UnknownField3;
public IntPtr UnknownField4;
public IntPtr UnknownField5;
public IntPtr UnknownField6;
public IntPtr UnknownField7;
public IntPtr UnknownField8;
public IntPtr UnknownField9;
public IntPtr UnknownField10;
public IntPtr UnknownField11;
}
आवश्यक मान हैं:
तीसरी स्ट्रीम Memory64List स्ट्रीम है, जिसका आईडी 9 है। यह ModuleList स्ट्रीम और यूनिकोड स्ट्रिंग के बाद ऑफ़सेट 298 (0x12A) पर स्थित है, और इसका आकार मॉड्यूल की संख्या पर निर्भर करता है।
public struct Memory64ListStream
{
public ulong NumberOfEntries;
public uint MemoryRegionsBaseAddress;
public Memory64Info[] MemoryInfoEntries;
}
प्रत्येक मॉड्यूल प्रविष्टि एक 16-बाइट्स संरचना है:
public struct Memory64Info
{
public IntPtr Address;
public IntPtr Size;
}
आवश्यक मान हैं:
lsass.exe प्रक्रिया के मेमोरी क्षेत्रों को लूप करने के लिए पूर्वापेक्षाएँ हैं जिन्हें केवल NTAPIs का उपयोग करके हल किया जा सकता है:
'SeDebugPrivilege' अनुमति प्राप्त करें। सामान्य Advapi!OpenProcessToken, Advapi!LookupPrivilegeValue और Advapi!AdjustTokenPrivilege के बजाय, हम ntdll!NtOpenProcessToken, ntdll!NtAdjustPrivilegesToken और Luid के लिए 20 का हार्डकोडेड मान (जो सभी नवीनतम Windows संस्करणों में स्थिर है) का उपयोग करेंगे
प्रक्रिया आईडी प्राप्त करें। उदाहरण के लिए, ntdll!NtGetNextProcess का उपयोग करके सभी प्रक्रियाओं को लूप करें, ntdll!NtQueryInformationProcess के साथ PEB पता प्राप्त करें और ProcessParameters के अंदर ImagePathName फ़ील्ड को पढ़ने के लिए ntdll!NtReadVirtualMemory का उपयोग करें। PoC को अत्यधिक जटिल बनाने से बचने के लिए, हम .NET के Process.GetProcessesByName(<PROCESS_NAME>) का उपयोग करेंगे
एक प्रक्रिया हैंडल खोलें। प्रक्रिया जानकारी प्राप्त करने के लिए PROCESS_QUERY_INFORMATION (0x0400) और मेमोरी बाइट्स पढ़ने के लिए PROCESS_VM_READ (0x0010) अनुमतियों के साथ ntdll!OpenProcess का उपयोग करें
इससे निम्नलिखित को कॉल करके प्रक्रिया मेमोरी को ट्रैवर्स करना संभव है:
पिछले चरणों के बाद हमारे पास Minidump फ़ाइल बनाने के लिए आवश्यक सब कुछ है। हम स्थानीय रूप से एक फ़ाइल बना सकते हैं या बाइट्स को पहले एन्कोड या एन्क्रिप्ट करने की संभावना के साथ एक रिमोट मशीन पर भेज सकते हैं। इनमें से कुछ संभावनाएं delegates शाखा में कोडित हैं, जहां स्थानीय रूप से बनाई गई फ़ाइल को XOR के साथ एन्कोड किया जा सकता है, और remote शाखा में, जहां रिमोट मशीन पर भेजने से पहले फ़ाइल को XOR के साथ एन्कोड किया जा सकता है।
Minidump फ़ाइल बनाने से बचने वाले वैकल्पिक दृष्टिकोण के लिए, TrickDump देखें: यह तीन JSON फ़ाइलें और एक ZIP संग्रह उत्पन्न करता है, और Minidump को हमलावर की मशीन पर पुनर्निर्मित किया जाता है। यह उन सुरक्षा समाधानों से बचने में मदद कर सकता है जो Minidump निर्माण या एक्सफ़िल्ट्रेशन की निगरानी करते हैं।
| आईडी | स्ट्रीम प्रकार |
|---|
| 0x00 | UnusedStream |
| 0x01 | ReservedStream0 |
| 0x02 | ReservedStream1 |
| 0x03 | ThreadListStream |
| 0x04 | ModuleListStream |
| 0x05 | MemoryListStream |
| 0x06 | ExceptionStream |
| 0x07 | SystemInfoStream |
| 0x08 | ThreadExListStream |
| 0x09 | Memory64ListStream |
| 0x0A | CommentStreamA |
| 0x0B | CommentStreamW |
| 0x0C | HandleDataStream |
| 0x0D | FunctionTableStream |
| 0x0E | UnloadedModuleListStream |
| 0x0F | MiscInfoStream |
| 0x10 | MemoryInfoListStream |
| 0x11 | ThreadInfoListStream |
| 0x12 | HandleOperationListStream |
| 0x13 | TokenStream |
| 0x16 | HandleOperationListStream |