
تفريغ lsass باستخدام وظائف NTAPI فقط عن طريق صياغة ملفات Minidump يدويًا (بدون MiniDumpWriteDump!!!)
تتيح أداة NativeDump تفريغ عملية lsass باستخدام NTAPIs فقط، منتجة ملف Minidump يحتوي فقط على التدفقات اللازمة لتحليلها بواسطة أدوات مثل Mimikatz أو Pypykatz (تدفقات SystemInfo و ModuleList و Memory64List).

يحتوي البرنامج على وسيط اختياري لملف الإخراج، واسم الملف الافتراضي هو "proc_.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 + تشفير محتوى Minidump بـ XOR
all-modules - الحصول على معلومات جميع الوحدات (وليس فقط lsasrv.dll)
peb-unreadable - تنفيذ دون قراءة بنية PEB لعملية lsass + 3 طرق لاستبدال ntdll.dll
بعد قراءة هياكل Minidump غير الموثقة، يمكن تلخيص هيكلها إلى:

لقد قمت بإنشاء أداة تحليل قد تكون مفيدة: MinidumpParser. سنركز على إنشاء ملف صالح يحتوي فقط على القيم الضرورية للرأس ودليل التدفقات والتدفقات الثلاثة الوحيدة اللازمة لملف Minidump لكي يتم تحليله بواسطة Mimikatz/Pypykatz: تدفقات SystemInfo و ModuleList و Memory64List.
الرأس هو هيكل بحجم 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 Stream) بالمعرف 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 Stream) بالمعرف 4. يقع عند الإزاحة 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;
}
القيم المطلوبة هي:
التدفق الثالث هو تدفق قائمة الذاكرة 64 (Memory64List Stream) بالمعرف 9. يقع عند الإزاحة 298 (0x12A)، بعد تدفق قائمة الوحدات وسلسلة Unicode، ويعتمد حجمه على عدد الوحدات.
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 فقط:
بهذا يمكن اجتياز ذاكرة العملية عن طريق استدعاء:
بعد الخطوات السابقة، لدينا كل ما هو ضروري لإنشاء ملف 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 |