檢測Cobalt Strike只使用40行代碼
無文件落地的木馬主要是一段可以自定位的shellcode組成,特點是沒有文件,可以附加到任何進程里面執行。一旦特征碼被捕獲甚至是只需要xor一次就能改變特征碼,由于傳統安全軟件是基于文件檢測的,對目前越來越多的無文件落地木馬檢查效果差。
基于內存行為特征的檢測方式,可以通過檢測執行代碼是否在正常文件鏡像區段內去識別是否是無文件木馬.由于cobaltstrike等無文件木馬區段所在的是private內存,所以在執行loadimage回調的時候可以通過堆棧回溯快速確認是否是無文件木馬。
檢測只需要40行代碼:
- 在loadimagecallback上做堆棧回溯
- 發現是private區域的內存并且是excute權限的code在加載dll,極有可能,非常有可能是無文件木馬或者是shellcode在運行:
- void LoadImageNotify(PUNICODE_STRING pFullImageName, HANDLE pProcessId, PIMAGE_INFO pImageInfo)
- {
- UNREFERENCED_PARAMETER(pFullImageName);
- UNREFERENCED_PARAMETER(pProcessId);
- UNREFERENCED_PARAMETER(pImageInfo);
- if (KeGetCurrentIrql() != PASSIVE_LEVEL)
- return;
- if (PsGetCurrentProcessId() != (HANDLE)4 && PsGetCurrentProcessId() != (HANDLE)0) {
- if (WalkStack(10) == false) {
- DebugPrint("[!!!] CobaltStrike Shellcode Detected Process Name: %s\n", PsGetProcessImageFileName(PsGetCurrentProcess()));
- ZwTerminateProcess(NtCurrentProcess(), 0);
- return;
- }
- }
- return;
- }
堆棧回溯:
- bool WalkStack(int pHeight)
- {
- bool bResult = true;
- PVOID dwStackWalkAddress[STACK_WALK_WEIGHT] = { 0 };
- unsigned __int64 iWalkChainCount = RtlWalkFrameChain(dwStackWalkAddress, STACK_WALK_WEIGHT, 1);
- int iWalkLimit = 0;
- for (unsigned __int64 i = iWalkChainCount; i > 0; i--)
- {
- if (iWalkLimit > pHeight)
- break;
- iWalkLimit++;
- if (CheckStackVAD((PVOID)dwStackWalkAddress[i])) {
- DebugPrint("height: %d address %p \n", i, dwStackWalkAddress[i]);
- bResult = false;
- break;
- }
- }
- return bResult;
- }
使用:
編譯好驅動,加載驅動,之后運行測試看看:
普通生成(x32與x64)測試:
基于VirtualAlloc的C代碼測試:
測試結果:
基于powershell的測試:
基于python的測試:
測試結果:
弊端:
目前已知的ngentask.exe、sdiagnhost.exe服務會觸發這個檢測規則(看樣子是為了執行一些更新服務從微軟服務端下載了一些shellcode之類的去運行).如果后續優化則需要做一個數字簽名校驗等給這些特殊的進程進行加白操作.這是工程問題,不是這個demo的問題
一如既往的 github:https://github.com/huoji120/CobaltStrikeDetected



































