在甲方做安全或者搞红队的人,对内网横向移动这个词应该都不陌生。你在防守侧部署了各种告警规则,结果攻击者通过 SMB 或 WMI 换了台机器继续跑,你这边毫无感知;你在攻击侧拿下一台跳板机,结果可能因为协议没选对,在目标机器上弹个 shell 弹了半天,最后还被杀了。SMB、WMI、PsExec 这三个协议是内网横向移动里最高频的三板斧,这篇文章我想从协议本身的机理讲起,把它们的异同、穿透逻辑和实际利用链条掰开揉碎说清楚,最后再从防御角度告诉你,到底该怎么看日志、怎么抓特征、怎么去阻断。
1. 内网横向移动的整体设计与思路拆解
1.1 内网横向移动的本质:从身份信任到通道复用
内网横向移动在整个攻击链条里其实扮演的是“转移阵地”的角色。初始立足点往往是一台中招的办公终端或者一台暴露在外的服务器,攻击者在这个点上拿到了不高不低的权限,但目标数据可能在另一台数据库服务器或者核心应用服务器上。横向移动解决的就是“从机器 A 到机器 B 到机器 C”的逐步渗透问题,本质是利用内网中已有的信任关系、凭据复用和协议本身的设计特性,在不触发新告警的情况下完成身份和通道的迁移。
在实际渗透中我见过很多新手一上来就搞 MS17-010,其实真正成熟的横向移动往往不依赖漏洞。SMB、WMI、PsExec 这三个协议走的是系统的正常功能,它们被设计和实现出来的初衷是给管理员做远程管理和文件共享,攻击者只不过是把这些合法协议当成了运输工具。这意味着,如果没有做好日志审计和流量基线分析,很多横向移动行为在安全设备眼里和日常运维行为长得几乎一模一样。
这里要特别强调“身份信任”这个概念。内网环境中域用户通常可以在多台机器上有相同口令的本地管理员权限,或者干脆就是域管账户在多台机器上跑服务。攻击者只要在一台机器上拿到这个账户,就能用同一组凭据横扫整个网段。SMB 和 WMI 的横向移动恰恰就是把这种隐形的信任关系暴露出来并加以利用的典型途径。
1.2 为什么偏偏是 SMB、WMI、PsExec 这三板斧
有人会问,横向移动的手段那么多,SSH、RDP、计划任务、PowerShell 远程会话都可以,为什么 SMB、WMI、PsExec 是出镜率最高的组合?
先看 SMB。SMB 是 Windows 环境下的基础网络协议,用于文件共享、打印机共享和其他 IPC 通信。域环境的组策略下发、文件访问、NetLogon 都需要 SMB 来承载。也就是说,只要 Windows 机器在跑,SMB 就是无法完全关停的常驻服务,而且 445 端口基本是敞开的。攻击者不需要额外开端口,不需要什么奇怪的协议,直接用 SMB 就能做账户枚举、共享枚举、远程文件写入。这和爆破 SSH 还是两回事——SMB 本身就有很多内建功能可以被利用来直接执行命令。
再看 WMI。WMI 的杀伤力在于它是 Windows 自带的管理框架,几乎所有 Windows 机器都开着对 WMI 的远程调用支持。WMI 走得是 RPC 动态端口,常驻端口 135,真正的数据通道是动态协商的端口。这意味着传统基于固定端口的防火墙策略很难做到精准管控,你允许 135 端口是业务所需,但动态开放的高位端口可能就成了后门通道。WMI 不仅能查系统信息,还能创建进程、修改服务、调用任意系统方法,完全具备远程命令执行的能力。
PsExec 则是微软官方提供的远程管理工具,属于 Sysinternals 套件。它的工作方式是把自己附带的二进制文件通过 SMB 的 ADMIN$ 或 C$ 共享上传到目标机器的特殊目录,然后创建对应的服务来执行命令。对安全团队来说,PsExec 最麻烦的一点是它带有微软签名,很多终端防护软件默认信任微软签名文件,导致 PsExec 的横向移动在很多环境下是被直接放行的。
这三者之间还存在着天然的互补关系。SMB 负责文件传输和通道建立,WMI 负责无文件式的远程调用,PsExec 负责服务安装与命令执行。攻击者可以先用 SMB 枚举找到可达主机,再用 WMI 做信息收集,最后用 PsExec 落地控制,整套流程行云流水,而且每一步都走了系统合法机制,这就是为什么这三板斧会频繁被组合使用。
2. 核心细节解析与实操要点
2.1 SMB 协议穿透的机理与利用边界
SMB 协议的核心特点是它承载了认证、文件访问、命名管道通信三大功能。攻击者在使用 SMB 做横向移动时,事实上是在利用它的认证机制和文件共享机制来建立初始通道。
先讲认证机制。SMB 使用的认证协议主要是 NTLM 认证,在域环境中也可能走 Kerberos。NTLM 认证有个著名的痛点叫做 Pass-the-Hash(哈希传递):只要攻击者拿到的是 NTLM 哈希而不是明文密码,就可以在不需要解密的情况下直接向目标机器发起认证。因为 NTLM 的认证响应本身就是基于哈希计算的,服务器端拿去验证的也是哈希,双方都不需要明文密码。很多没做过内网渗透的朋友第一次听到这个都会很震惊——密码学上密码哈希的意义是“服务器不存储明文,即使库泄露也不怕”,结果攻击者根本不需要明文,拿着哈希就能冒充用户登录。
这一特性直接把账号密码的安全层级拉到了“凭据保护”的高度。你在本机用 mimikatz 抓到一个本地管理员账户的 NTLM 哈希后,如果这个管理员账户在好几台机器上都有同样的口令,那攻击者直接拿着哈希去尝试连接这几台机器的 SMB 服务,就能批量获取远程命令执行能力。这就是为什么常听到“哈希传递只需要 445 通就行”的说法。
再说文件共享机制。SMB 的默认管理共享包括 ADMIN$、C$ 和 IPC$,其中 ADMIN$ 指向 Windows 系统目录,C$ 是整个 C 盘根目录,IPC$ 则用于进程间通信。攻击者可以通过 SMB 客户端直接访问这些共享来读写目标机器上的文件,也正因此,SMB 协议本身就是一个天然的文件落地通道。如果攻击者需要向目标机器投放一个 payload 或工具,不需要走 HTTP 或 HTTPS,直接 copy 过去就行。很多情况下攻击者就是通过 SMB 把一个小工具传到目标机器的临时目录,然后在后续步骤里用 WMI 或者计划任务去拉起它。
利用边界在哪里呢?SMB 横向移动的一个重要前提是目标机器开启了对管理共享的访问,同时本地安全策略允许远程访问。Windows 默认情况下管理员组的用户通过 SMB 访问管理共享是被允许的,但如果你看到目标机器的 445 端口开放,却连接共享时报“拒绝访问”,那多数是账号权限不够或者 UAC 远程限制生效了。Win10 和 Server 2016 之后,本地管理员账户通过 SMB 远程访问时默认会被 UAC 过滤,除非你在本地策略里把“本地账户的共享和安全模型”改成了“经典模式”。
SMB 这块我还想提一个很容易踩的坑。很多时候你在测试环境中,明明账号密码都正确,但用 SMB 连接对方共享时却报错,有时候是 SMB1 协议的问题,有时候是 NTLM 版本的问题。Windows Server 2019 之后的版本默认关闭了 SMB1,而很多老工具默认还在走 SMB1,导致连接失败。现在做渗透或加固时,都应该明确一个态度:SMB1 是一个应该彻底退役的旧协议,它的安全性已经远远落后于时代,无论是攻防哪一侧,都不建议再依赖它去完成核心任务。
2.2 WMI 的远程调用链与无文件优势
WMI 的全称是 Windows Management Instrumentation,它本质上是一个基于 Web-Based Enterprise Management 标准的管理框架。它提供了一整套访问 Windows 系统管理信息的接口,能够查询操作系统状态、修改系统设置、创建进程,甚至监听系统事件。
从横向移动的角度看,WMI 的远程执行优势有三点。第一,它不需要在目标机器上放置任何文件就能执行命令,属于典型的“无文件攻击”方式。第二,它走的标准 RPC 通道中,135 端口只是最开始的 endpoint mapper 端口,真正的 WMI 调用会协商出一个动态的高位端口来完成后续通信。这给防火墙策略的制定带来了极大挑战,如果你在边界防火墙上只开放了 135,那么 WMI 的实际数据通信仍然可能因为无法匹配到动态端口而失败或半通。第三,WMI 是系统自带框架,它不会引入额外的陌生进程,创建进程时父进程是 WmiPrvSE.exe,这个进程在正常 Windows 环境下本来就随系统启动常驻。
WMI 在横向移动里的典型用法是通过 WMIC 或者 PowerShell 的 Get-WmiObject 去远程连接目标机器,执行 WQL 查询或者调用类方法。WQL 是 WMI 的查询语言,类似 SQL,你可以用它查询目标系统的进程列表、服务列表、补丁信息、网络配置等,几乎覆盖了系统管理的方方面面。更重要的是,可以通过 Invoke-WmiMethod 调用 Win32_Process 类的 Create 方法,在远程目标机器上创建任意进程。这个能力就意味着,只要你能通过 WMI 认证,你就有能力直接在目标机器上执行命令。
它的坑在哪里呢?我实际操作中踩得最多的是权限配置和防火墙问题。远程调用 WMI 时,目标机器上不仅要放行 RPC 端口,还需要登录账号在目标机器的 WMI 控制命名空间里有执行权限。默认情况下,管理员组的成员是可以远程执行 WMI 方法的,但如果对方管理员手动修改了 WMI 安全设置,那即使你拿到了管理员账号密码,调用 WMI 时也可能会被拒绝访问。另外,某些安全防护软件会专门针对 WMI 远程调用做拦截,因为 WMI 在高危操作时产生的进程行为比较特殊,父进程和子进程的关系不符合常规程序启动的模式,容易被终端检测产品捕捉。
从穿戴角度来说,WMI 的横向移动日志通常记录在 Microsoft-Windows-WMI-Activity/Operational 日志中,事件 ID 为 5857 时通常是 WMI 活动。防守方如果开启了这块日志,会发现某个来源 IP 在短时间内大量调用 WMI,且调用的类集中在 Win32_Process 或 Win32_Service,这时候基本可以判定异常。
2.3 PsExec 的服务创建机制与对抗价值
PsExec 是微软 Sysinternals 套件里知名度最高的远程执行工具之一,其原理其实是把 C/S 模式落地成了一个非常巧妙的实现。当你在命令行执行psexec \\target -u username -p password cmd.exe时,工具的客户端部分会先通过 SMB 的 ADMIN$ 共享连接目标机器,将名为 PSEXESVC.exe 的服务器端二进制文件上传到目标机器的 Windows 系统目录中。
完成上传后,PsExec 客户端会通过 SCM(服务控制管理器)的远程接口在目标机器上创建一个名为 PSEXESVC 的服务,并将该服务设置为启动状态。当服务启动后,PSEXESVC.exe 开始监听命名管道,等待客户端命令。后续 PsExec 客户端就通过命名管道与目标机器上的服务端进行通信,把需要执行的命令发送过去,服务端进程执行后再把输出结果通过同一个命名管道返回给客户端,整个通信过程也是走了 SMB 的 IPC$ 通道。
PsExec 在横向移动里的价值不只是命令执行能力,更在于它天然解决了输出回显的问题。WMIC 远程执行命令后,在默认情况下你是看不到命令输出内容的,得靠额外的方式把结果传回来,而 PsExec 直接帮你把 stdout 和 stderr 重定向到了本地终端,这对攻击者来说非常友好。
从防御对抗角度看,PsExec 最严重的特征是它的服务名和可执行文件名几乎是固定的,PSEXESVC 这个名字在进程列表和注册表服务项里非常有辨识度。这也是 PsExec 最容易被检测的地方。很多安全团队会在终端侧专门写规则,发现系统目录下出现 PSEXESVC.exe 或者在服务列表里看到 PSEXESVC 这个服务时直接告警。
另一个对抗价值在于,PsExec 毕竟依赖管理员共享和 SCM 远程服务创建,这意味着它受限于账户权限和 SMB 服务的可用性。如果你拿到的账号不是管理员组,无法写入 ADMIN$ 共享,那么 PsExec 大概率失败。而且 PsExec 需要在目标机器上写文件,这违背了“无文件横向移动”的隐蔽性要求,所以在高对抗场景下,攻击者会更倾向于用 WMI 或远程 PowerShell 来做无文件落地的横向移动,PsExec 更适合在内网纵深足够、终端检测较弱的环境中快速建立控制。
PsExec 还有一个经常被忽略的点:它是可以在本地启动的。如果不指定远程主机,直接输入psexec -s就能在本地以 SYSTEM 权限启动一个命令行。这个功能在权限维护里很常用,因为它提供了一个快速提权到 SYSTEM 的路径。但如果你的终端上查出了有进程以 PSEXESVC 服务方式运行,那就需要警惕是否有人在利用 PsExec 做横向移动了。
3. 实操过程与核心环节实现
3.1 环境准备与基础工具选型
在讲具体步骤之前,有必要先把环境说清楚。横向移动的实验环境建议至少准备两台 Windows 机器,一台作为跳板机(已拿到本地管理员凭据),一台作为目标机(运行 Windows Server 或 Windows 10 均可)。两台机器需要在同一网段内可以互通 445 和 135 端口,最好是在一个域环境下测试,这样口令复用的效果更接近实战。
工具选型方面,我做这类复现时通常会准备三套。第一套是 Impacket 套件,它提供了 smbclient.py、wmiexec.py、psexec.py、atexec.py 等脚本,是目前红队与安全研究中最常用的协议级工具包。第二套是微软 Sysinternals 原生工具,包括 psexec.exe 本身和 PsExec64.exe,用于验证官方工具的行为特征。第三套是系统自带的命令行工具,比如 Windows 上的 wmic、PowerShell,以及 Linux 上的 smbclient 和 rpcclient。
Impacket 之所以适合做协议级研究和验证,是因为它完全在 Python 层实现了 SMB、RPC、WMI 等协议的客户端逻辑,不依赖 Windows 系统自带的客户端实现。这让它可以运行在 Linux 环境中,而且可以精确控制协议交互的每一个细节。在实际测试中,我发现 Impacket 脚本对 NTLM 哈希传递的支持非常完善,你用 mimikatz 或者 secretsdump 抓到的哈希可以直接通过-hashes参数输入给 Impacket 脚本,不用知道明文密码。这对理解哈希传递的机制和测试公司内部的 NTLM 防护策略都很有帮助。
还有一个容易踩坑的细节:如果你的目标机器是较新的 Windows Server 2022 或者 Windows 11,Impacket 的某些旧版本脚本可能会出现签名校验失败的问题。这是因为新版 Windows 默认启用了 SMB 签名,而旧版 Impacket 在实现 SMB 协议时不带签名协商或签名验证逻辑不完整。遇到这种情况,要么升级 Impacket 到最新版本,要么在目标机器上临时关闭 SMB 签名来做验证。但在真实环境中,我通常建议优先升级工具,而不是调整目标系统的安全策略,因为关闭 SMB 签名本身就带来了中间人攻击的风险。
3.2 SMB 枚举与共享访问的完整流程
横向移动第一步通常不是直接打命令,而是先摸清楚目标网络里有哪些主机可连、有哪些共享可见、有哪些账号能复用到其他机器。SMB 枚举就承担了这个侦察功能。
在 Linux 攻击机上,最基础的操作是用 smbclient 尝试匿名访问目标机器的共享列表。命令形如smbclient -L //192.168.1.100 -N。这个-N表示不提供密码,也就是匿名访问。如果目标机器允许匿名枚举共享,你会直接看到 ADMIN$、C$、IPC$ 以及业务共享的列表。很多安全基线整改之后会禁用匿名枚举,但实际内网里仍然有大量机器开着这个口子。匿名枚举的价值在于,攻击者不需要任何有效凭据就能开始收集信息,为后续口令爆破或凭据填充提供了目标基础。
拿到有效账号密码后,连接的复杂度就低很多了。直接在命令行执行smbclient //192.168.1.100/C$ -U corp\\admin,输入密码后就能像操作本地磁盘一样去浏览目标机器的 C 盘文件。这个过程有一个很重要的细节:SMB 共享访问的路径分隔符是反斜杠,在 Linux shell 下你需要加引号防止 shell 转义。另外,在域用户登录时,用户名要附带域名前缀,格式是域名\\用户名,不然系统会默认用工作站域名去解析,导致认证失败。
访问共享后要留意查看敏感文件的存放习惯。很多管理员的备份脚本会把一些脚本配置、明文口令文件或者数据库备份放在 C 盘根目录或其他共享目录里。攻击者通过 SMB 直接浏览这些目录时,往往会意外获取到大量敏感信息。我在实战中见过最夸张的一个案例是管理员把密码本放在 C:\temp\passwords.txt 里,然后共享目录直接暴露给了整个办公网。SMB 横向移动的威力不仅在于文件读写,更在于它让攻击者能以合法的方式把目标机器上的敏感资料拉回自己手里。
使用 Impacket 的 smbclient.py 和系统自带 smbclient 的差异主要集中在认证方式和更细粒度功能的支持。smbclient 对 WMI 相关的远程调用无能为力,但 Impacket 系列脚本是联合使用的,你用 smbclient.py 确认了凭据有效性之后,可以直接切到 wmiexec.py 去执行命令,整个流程没有断点。这也是为什么红队里 Impacket 套件如此受欢迎。
3.3 WMI 远程查询与命令执行的细节分析
WMI 的远程执行有两种常见路径:第一种是直接用系统内置命令行工具 wmic,第二种是用 PowerShell 的 WMI 客户端。在做横向移动复现时,我通常会分别演示这两种方式,因为它们产生的日志特征完全不同,防守方检测的思路也不一样。
先说 wmic 命令。wmic /node:192.168.1.100 /user:corp\\admin /password:xxx process list brief可以查看远程主机上的进程列表。这个命令最小化了输出,但已经能验证凭据的有效性。接下来要执行命令时,使用wmic /node:192.168.1.100 /user:corp\\admin /password:xxx process call create "cmd.exe /c whoami > C:\\windows\\temp\\out.txt"。注意,在用 WMI 创建进程时,命令输出不会直接返回到你的终端,你需要把输出重定向到目标机器上的某个文件里,然后用 SMB 共享再去读这个文件。这是 WMI 横向移动和 PsExec 最大的使用体验差异。
PowerShell 的方式更灵活一些。你可以用Invoke-WmiMethod -ComputerName 192.168.1.100 -Credential $cred -Class Win32_Process -Name Create -ArgumentList "cmd.exe /c whoami > C:\\windows\\temp\\out.txt"来实现同样的效果。PowerShell 的优势在于可以利用已有的凭据对象,不用把密码写在命令行上,而且支持管道和变量处理,方便后续的攻击编排。
Impacket 的 wmiexec.py 则是把上述过程集成体验做了优化。它使用 WMI 来执行命令,但通过 SMB 共享的方式自动读取输出文件,并在终端里直接显示命令结果。所以在实际使用中,python3 wmiexec.py corp/admin:password@192.168.1.100之后弹出的半交互式 shell 用起来非常像 PsExec,但它本质上没有用到任何服务创建过程,也没有向目标机器写入可执行文件,隐蔽性比 PsExec 好很多。
这里必须提醒一个非常关键的实际问题:WMI 远程命令执行经常被安全产品拦截,因为 WmiPrvSE.exe 创建 cmd.exe 或者 powershell.exe 这种子进程的行为特征太明显了。如果你在被 EDR 保护得比较好的环境里做测试,直接用 WMI 弹 cmd 大概率会触发告警。更隐蔽的方式是调用 WMI 去创建 Rundll32.exe 或者其他白进程来加载后续 payload,这属于免杀绕过的范畴,不在本文详细展开,但你需要清楚 WMI 作为执行引擎的上限和风险。
3.4 PsExec 的实际执行过程与命令场景解析
PsExec 的使用方式非常直观。在 Windows 本机上,命令为psexec \\\\192.168.1.100 -u corp\\admin -p password cmd.exe。正常情况下,你会看到 PsExec 连接远程主机、上传 PSEXESVC.exe、启动服务、建立命名管道通信、最后弹出一个远程主机的 cmd 窗口,你可以直接在这里执行命令。
Linux 侧使用 Impacket 的 psexec.py 也类似,python3 psexec.py corp/admin:password@192.168.1.100之后会进入一个远程 shell 会话。和 wmiexec.py 不同的是,psexec.py 会在目标机器上写入 PSEXESVC.exe 文件并注册服务,因此具备比较高的可检测性。但相应的,它执行的命令回显更加稳定,尤其是在目标机器防病毒策略较宽松的情况下,PsExec 模式的整体体验更接近原生 RDP。
PsExec 的参数里有几个值得仔细研究和实际操作中的变量。-s参数表示以 SYSTEM 权限运行远程进程,而不是以当前登录用户的身份。如果你拿到的只是域内普通管理员账号,在目标机器上只能以管理员权限运行,那执行某些需要 SYSTEM 的操作时会报错,这时候加上-s参数就能通过服务方式启动进程,服务本身就是以 SYSTEM 权限运行的。还有一个-d参数,表示不等远程进程执行完就直接返回,这样不会因为长时间阻塞导致连接挂死。
实际测试中,使用 PsExec 需要注意的一个坑是目标机器的 UAC 远程限制。如果你拿到的账号是目标机器的本地管理员,但不是内置 Administrator 账号,那默认情况下通过 PsExec 远程连接会被 UAC 拦截,提示“拒绝访问”。解决办法是在目标机器上修改注册表项 LocalAccountTokenFilterPolicy 的值为 1,或者直接使用内置的 Administrator 账号。这一点在渗透测试中经常被忽略,很多人以为账号密码正确就一定能连上,结果被 UAC 限制挡住了,半天找不到原因。
PsExec 的痕迹清除相对麻烦。因为 PSEXESVC.exe 文件会留在目标机器的 System32 目录下,服务注册表项也会留下记录。虽然你退出 PsExec 时它会自动停止并删除服务,但如果进程被强制杀掉或者网络中断,服务可能会残留。防守方在排查时,重点会找 PSEXESVC 服务和对应文件,所以在高隐蔽性要求的测试中应谨慎使用 PsExec,而在防御演练或安全评估中,PsExec 反而是很好的蓝队钓鱼测试工具,可以验证终端防护和日志审计的有效性。
3.5 哈希传递在三个协议上的落地验证
哈希传递不是一个独立的协议,而是攻击者拿到 NTLM 哈希后的一种认证方式。它可以在 SMB、WMI、PsExec 三条通道上分别落地,只是不同的工具和协议实现的细节略有差异。
在 SMB 层面,拿哈希直接连接远程共享的典型命令是 Impacket 的 smbclient.py 加-hashes参数,例如python3 smbclient.py -hashes :aad3b435b51404eeaad3b435b51404ee corpmachine。在 Windows 本机上,mimikatz 也支持sekurlsa::pth /user:admin /domain:corp /ntlm:哈希 /run:cmd.exe的方式,把哈希注入到当前进程中,之后打开的 cmd 里执行任何网络命令都会自动带上这个身份的认证。
哈希传递在 WMI 上的落地格式基本一样,wmiexec.py 的-hashes参数直接接受 NTLM 哈希。实际操作中,你抓到一个域管的 NTLM 哈希后,可以用 wmiexec.py 对域内所有存活主机做批量命令执行,这就是横向移动最高效的自动化方式之一。PsExec 也一样,psexec.py 同样支持-hashes参数,在拿到哈希时无需知道明文密码即可完成服务创建和命令执行。
哈希传递能不能成功,取决于几个关键前置条件。目标机器上登录的账户必须存在于本地管理员组(或域管组),同时该账户没有设置“拒绝从网络访问这台计算机”的安全策略。此外,如果目标机器开启了 Credential Guard,那么从内存中直接抓取 NTLM 哈希的某些方式可能会失效,但如果有明文密码或者其他凭据导出方式,不影响哈希传递。
4. 常见问题与排查技巧实录
4.1 SMB 连接失败的原因排查
SMB 连接失败是横向移动中最常见的技术卡点,我把可能的原因按出现频率排了个序。
第一是端口不通。你先用telnet 192.168.1.100 445或者Test-NetConnection确认 TCP 端口是否可达。很多云环境的安全组和本地防火墙会默认屏蔽 445 端口,这个问题在网络层就能定位。
第二是 SMB 版本和签名不匹配。客户端默认走高版本 SMB 协议,但目标机器如果只允许 SMB1 或启用了强制 SMB 签名,连接就会失败或报错。在 Linux 端你可以用smbclient -m SMB2来指定协议版本尝试连接,看看是否协议协商问题。Windows 端如果出现“无法连接到 MUP”等提示,大概率也是 SMB 协议栈问题,可以用Get-SmbConnection和Get-SmbServerConfiguration排查。
第三是认证问题。错误信息如果提示“用户名或密码错误”或者“拒绝访问”,那基本就是凭据不正确或者账号权限不够。注意在域环境中要带上域名前缀,本机账户要带主机名。还可能是目标机器开启了“仅来宾访问”策略,导致实际认证没有使用你提供的凭据。
第四是 UAC 远程限制。这个问题我在前面已经提过,目标机器上如果开启了这个限制,本地管理员账号的远程管理权限会被削弱。解决方案要么使用内置 Administrator 账号,要么修改注册表 LocalAccountTokenFilterPolicy。
第五是杀毒软件或 EDR 主动阻断。现在很多终端安全产品都会对 SMB 管理共享的远程访问做监控,一旦发现来自陌生 IP 的 ADMIN$ 或 C$ 访问请求,会直接阻止。这类问题在日志里比较难定位,因为系统层面看起来是连接被重置或超时。
4.2 WMI 调用失败的典型场景与处理
WMI 远程调用失败的报错常见有“RPC 服务器不可用”。这个问题往往是目标机器的 RPC 服务或者 WMI 服务(Winmgmt)没有正常启动。检查方式是确认目标机器的“Windows Management Instrumentation”服务是否处于运行状态,以及依赖的“Remote Procedure Call (RPC)”服务是否正常。
另一类是“拒绝访问”错误。可能原因包括:账号没有远程 WMI 权限;目标机器的 WMI 控制台里对特定命名空间的权限被修改过;或者是 DCOM 的远程启动/激活权限限制。在 Windows 上可以通过 dcomcnfg 打开组件服务,确认“我的电脑”属性中的 COM 安全设置是否允许远程启动和激活。
还有一个经常被忽略的点是 WMI 的异步调用容易被杀软拦截。如果你在脚本里用了 Invoke-WmiMethod 或者 wmic 命令直接调 Win32_Process.Create 方法,杀软可能直接拦截,但同一台机器上用 psexec 执行命令却能成功。这是因为 WMI 调用产生的父进程关系和远程进程创建模式过于明显,触发了终端侧的“异常父进程链”规则。
排查时建议优先启用 WMI 活动日志,在事件查看器的 Applications and Services Logs/Microsoft/Windows/WMI-Activity/Operational 路径下可以看到所有 WMI 请求。这个日志对判断是否有外部机器在恶意调用 WMI 非常有用。
4.3 PsExec 常见报错与注意事项
PsExec 最常见的报错是“找不到网络名”。这个报错看起来像是网络问题,实际上往往是目标机器的 IPC$ 共享不可用或者 SMB 签名策略不匹配。如果你在域环境中用域账户连接,但目标机器和当前机器不在同一个域,也会触发这个错误。
第二个高频问题是“拒绝访问”,这个大概率是前文提到的 UAC 远程限制或账号权限不足。PsExec 对本地管理员组有严格的要求,必须是内置 Administrator 或者本地管理员组且 UAC 配置允许远程管理才能正常执行。
第三个问题很有迷惑性:目标机器上杀毒软件会在 PSEXESVC.exe 上传时直接删除,导致服务创建后无法启动或启动即退出。这种情况下,PsExec 客户端往往显示“服务启动失败”或者直接退出,但你又找不到其他明显的异常。定位方式是去目标机器上查看 System32 下是否有 PSEXESVC.exe 文件残留,如果不存在,基本就是被杀软清理了。
使用 PsExec 时还有一些细节需要注意。目标机器的系统时间如果与服务端时间差太大,Kerberos 认证会失败,导致连接直接失败。你可以手动指定用 NTLM 认证(例如在 Impacket 中加-k参数来控制是否使用 Kerberos),或者先同步系统时间再测试。另外,PsExec 创建的远程进程在工作目录上默认是 System32,如果你的命令依赖相对路径去引用文件,极容易出错。建议所有被执行的程序都写绝对路径,并且提前通过 SMB 把需要的文件传到明确的位置。
4.4 防守侧如何发现与告警路径
从防守侧来看,这三个协议无论怎么组合利用,都会在特定层面留下痕迹,只是发现难度不同。
SMB 层面的横向移动可以利用 Windows 事件日志中的 4624(登录成功)、4625(登录失败)、4672(管理员登录)等事件来分析。重点关注登录类型为 3(网络登录),并且登录进程是 NtLmSsp 或 Kerberos 的日志。如果同一时间内一个源 IP 对多个目标 IP 产生了登录网络共享的 4624 事件,那就是典型的横向移动扫描或批量连接行为。
WMI 层面的横向移动则要看 WMI-Activity 日志。搜索所有包含 Win32_Process 类名的记录,特别是来自同一来源 IP 的大量 WMI Create 调用。还可以通过 Sysmon 事件 ID 1(进程创建)来查看 WmiPrvSE.exe 创建了哪些子进程,正常 WMI 调用很少会从 WmiPrvSE.exe 下生成 cmd 或 powershell 进程,出现即异常。
PsExec 层面的横向移动特征最明显。终端侧出现 PSEXESVC 服务事件,进程名单里出现 PSEXESVC.exe,注册表 RUN 或服务项里出现 PSEXESVC 关键字,或者 Sysmon 记录到 System32 目录下被写入名为 PSEXESVC.exe 的新文件。这些特征筛选起来非常容易,可以考虑直接在 EDR 里做事件联动告警。
实战中比较推荐的做法是把这三层日志统一汇总到 SIEM 平台,做关联分析。比如,一个源 IP 在 10 分钟内先出现了针对多个主机的 SMB 连接日志,随后出现了 WMI 活动日志,最后出现了服务创建日志,那么这个行为链就高度符合 SMB-WMI-PsExec 的典型横向移动路径。这比单个日志的阈值告警要准确得多,也能过滤掉大部分误报。
5. 延伸思考与后续扩展建议
写到这里,很多朋友可能会问:这三个协议这么容易被利用,防御方到底有没有办法彻底封堵?从我个人的从业经验看,彻底封堵是不太现实的,因为这些协议本身就是 Windows 管理和协作的基础组件。比较现实的策略是纵深防御加缩小攻击面:在不影响业务的前提下,关闭不必要的管理共享,启用 SMB 签名,对核心服务器做 ACL 限制,限制域管账号的登录范围,开启 Credential Guard,部署 EDR 并且把 WMI、PsExec 的调用行为纳入高敏监控。
后续还可以扩展的方向包括 Kerberos 委派攻击和基于证书的认证滥用。相比 SMB 和 WMI 这种传统的横向移动通道,Kerberos 相关的利用更隐蔽、更难发现,而且对域环境的安全性破坏是毁灭性的。如果你对内网横向移动感兴趣,可以在掌握了 SMB、WMI、PsExec 的基础上,再深入学一下 AS-REP Roasting、Kerberoasting 和基于资源的约束性委派,这套组合拳几乎可以打穿大多数未加固的域环境。
回到这篇文章的初衷,其实无论是攻击者视角还是防御者视角,最终拼的都是对 Windows 协议机理的理解深度。SMB 为什么能传文件,WMI 为什么能执行命令,PsExec 为什么要创建服务,这些底层机制搞清楚了,面对任何变种攻击方式,你都能快速地拆解出它的实质动作,进而找到对应的检测和封堵策略。这也是我每次排查内网安全事件时最先做的功课。