首先我们来看下进程程注入的核心逻辑(不考虑寻找目标进程、不考虑注入内容的执行)
/*
注入恶意Payload:
OpenProcess 可以打开目标进程
VirtualAllocEx 在目标进程中分配一块内存区域
WriteProcessMemory 在刚刚分配的内存区域中写入恶意的Payload
以上3个函数可以实现Payload的注入
*/
举一个具体的反射性DLL的例子
/*
#1 使用RWX权限打开目标进程(OpenProcess),并为该DLL分配足够大的内存(VirtualAllocEx)。
#2 将DLL复制到分配的内存空间(WriteProcessMemory)。
#3 计算DLL中用于执行反射加载的导出的内存偏移量(GetReflectiveLoaderOffset)。
#4 调用CreateRemoteThread(或类似的未公开的API函数RtlCreateUserThread)在远程进程中开始执行,使用反射加载函数的偏移地址作为入口点。
#5 反射加载函数使用适当的CPU寄存器查找目标进程的进程环境块(PEB),并使用它查找内存中的地址kernel32.dll以及任何其他所需的库。
#6 解析的KERNEL32出口目录中找到所需的API功能,如内存地址LoadLibraryA,GetProcAddress和VirtualAlloc。
#7 使用这些函数,然后正确加载DLL(本身)到内存中,并调用它的入口点,DllMain。
*/
总结:我们可以看到此类注入基本需要WriteProcessMemory函数的,也就是说必须有目标进程内存读写权限,当我们没有进程内存读写权限的时候这个思路就行不通了,那我们该怎么呢?
我们可以不具备目标进程的读写权限,但是我们至少需要具备以下三种权限
/*
(1) PROCESS_CREATE_THREAD
(2) PROCESS_CREATE_PROESS
(3) PROCESS_QUERY_LIMITED_INFORMATION
*/
因为经典的VirtualAllocEx、WriteProcessMemory、CreateRemoteThread的步骤不再适用(我们没有读写权限),我们就必须找到合适的新方法来运行我们的盲注的Code,最简单的方法就是
system("path_to_script");
因此,我们得找到两个东西,我们需要用到这两个东西去生成一个线程,尽管现在有ASLR,但是还是有很大的接近100%的概率在2个不同的用户会话进程中得到同样的系统调用地址。
/*
#1 Windows中我们拥有权限的一个指向某个位置的路径字符串
#2 我们的系统调用(例如,msvcrt.dll的_wsystem函数是一个好选择)
*/
void *StartAddress = (void *)GetProcAddress(LoadLibrary("msvcrt.dll"),"_wsystem");
/*
C:\Users\Default
%temp%
%appdata%
...
*/
strings -eb shell32.dll | grep -P "^(\\\\[a-zA-Z0-9]{3,20}){2}^"
net user /add adminuser adminpassword
net localgroup administrators adminuser /add