☰
WinRM远程管理全攻略:配置、批量运维与安全加固
2026/10/13 4:06:05 网站建设 项目流程

聊到WinRM,很多人脑海里蹦出来的第一个词可能是“横向移动”。这个标签在安全圈里很常见,但实际在日常运维中,WinRM(Windows Remote Management)是Windows内置的远程管理协议,它的价值远远不止于“攻击面”——它是我批量管理Windows服务器时的头号工具。今天这篇就围绕WinRM聊透:怎么配、怎么用、怎么避开那些坑,以及最关键的一环:怎么防止它被别有用心的人拿去做横向移动。

这篇文章适合三类人:一是每天要跟几十台Windows服务器打交道的运维,二是需要批量执行脚本、收集状态的自动化工程师,三是安全岗的同仁——理解了WinRM的工作机制,才能在攻防演练中做好检测和加固。我尽量用实操中的真实经验来讲,不绕弯子。

1. WinRM是什么?先搞清楚它在干什么

1.1 WinRM的底层逻辑

WinRM是微软基于WS-Management协议实现的远程管理服务,简单说就是让一台Windows机器可以通过网络对另一台Windows机器执行管理命令。它走的是HTTP或者HTTPS,默认端口分别是5985和5986,数据传输格式是SOAP XML。

你可以把它理解成Windows版的SSH。SSH让你能在远程Linux机器上敲命令,WinRM则让你能在远程Windows机器上跑PowerShell、获取系统信息、修改配置、部署软件,甚至可以建立交互式会话,就像坐在那台机器面前一样。

这里得强调一下,WinRM并不是什么偏门功能,它从Windows Server 2012开始就是服务器操作系统的标配服务,Windows 10/11桌面系统也内置了它。只是在桌面系统上默认没有启用,服务器系统上很多企业镜像会预开启,这就给运维和攻防都留下了操作空间。

1.2 为什么它会被盯上

从攻击者的视角看,WinRM是一个“自带遥控器”的通道。一旦拿到一台机器的管理员凭据,并且目标机器开了WinRM,那就可以横向操作内网其他机器——不需要再上传乱七八糟的工具,系统原生功能就够用了。

但从运维的视角看,WinRM的效率同样惊人。你不需要给每台服务器装Agent,不需要额外开共享端口,只用PowerShell一条命令就能同时操作一百台机器。这也是为什么我坚持要在所有生产环境里做WinRM安全加固——它太好用了,好用到让人容易忽略该上的锁。

2. 配置WinRM的完整实操

2.1 快速启用:一条命令的事

在目标机器上用管理员权限打开PowerShell,执行:

Enable-PSRemoting -Force

这个命令会做以下几件事:

  • 启动WinRM服务,并设置为自动启动;
  • 把本机所有IP地址都注册为WinRM监听地址;
  • 放行防火墙规则(5985/5986端口);
  • 设置LocalAccountTokenFilterPolicy,保证本地管理员能通过远程会话获得完整令牌。

如果只是想快速测试,也可以执行winrm quickconfig,效果类似。但注意,Enable-PSRemoting通常只对手动配置的机器生效。如果机器在域环境里,组策略可能会统一关掉它,这时候需要检查策略。

2.2 自定义监听地址和端口

默认配置下,WinRM监听本机所有IP的5985端口。但这在生产环境里太粗放了,我习惯把它绑到指定内网网卡上,避免暴露到不该暴露的网段。

先把默认监听器删掉:

winrm delete winrm/config/Listener?Address=*+Transport=HTTP

再添加一个指定IP的监听器:

winrm set winrm/config/service @{AllowUnencrypted="false"} winrm create winrm/config/Listener?Address=10.0.0.10+Transport=HTTP

如果要走HTTPS,得先给主机准备证书。这里有个常用命令:

New-SelfSignedCertificate -DnsName "winrm01.example.local" -CertStoreLocation "Cert:\LocalMachine\My"

拿到证书指纹后,创建一个HTTPS监听器:

winrm create winrm/config/Listener?Address=10.0.0.10+Transport=HTTPS @{Hostname="winrm01.example.local";CertificateThumbprint="THUMBPRINT_HERE"}

注意证书的主机名必须和客户端连接时用的主机名一致,否则客户端会报信任错误。

2.3 认证方式与权限策略

WinRM支持多种认证方式,包括Kerberos、Negotiate(NTLM)、Basic和Certificate。运维中最常用的是Kerberos和Negotiate,因为它们能传递当前用户的凭据,不需要明文密码。

但在工作组环境下,经常遇到双跳问题(从机器A连到B,再在B上连到C)。这时候需要配置CredSSP:

Enable-WSManCredSSP -Role Client -DelegateComputer "*.example.local" Enable-WSManCredSSP -Role Server -Force

不过CredSSP有安全隐患,因为它会把凭据转发给目标机器。我用它只限于受控的内网测试环境,生产环境一律走Kerberos。

权限策略方面,普通用户连接到远程机器后默认只是标准用户权限,要执行管理员操作需要目标机器上配置LocalAccountTokenFilterPolicy为1。这个值默认是0,也就是说即使你本地是管理员,远程连接后也会被降权。很多新手在这里踩坑。可以通过:

New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -Name LocalAccountTokenFilterPolicy -PropertyType DWord -Value 1

来放开,但放开意味着更强的风险,建议只在确实需要远程管理的管理员机器上设置,普通服务器不要开。

3. 基于WinRM的批量管理与自动化

3.1 一条命令应对一百台机器

WinRM最爽的地方在Invoke-Command。我可以把服务器列表放在一个文本文件里,再用一条命令并行执行任务。比如查看所有机器的系统启动时间:

$servers = Get-Content "serverlist.txt" Invoke-Command -ComputerName $servers -ScriptBlock { (Get-CimInstance Win32_OperatingSystem).LastBootUpTime } -ThrottleLimit 20

-ThrottleLimit是并发数。我实测下来,批量执行时并发调到20左右比较稳,太高容易把目标机器资源吃满,太低效率不明显。

如果需要在远程机器上运行一段较长的脚本,可以先把脚本文件保存为.ps1,然后:

Invoke-Command -ComputerName $servers -FilePath "C:\scripts\deploy.ps1" -ArgumentList "param1","param2"

3.2 交互式会话:像坐在这台机器面前

单台机器调试时,Enter-PSSession能直接进入一个交互式PowerShell会话,相当于给你“坐”到远程机器跟前。

Enter-PSSession -ComputerName "server-01" -Credential (Get-Credential)

进入后,当前提示符会变成[server-01]: PS C:\>,此时你敲的所有命令都在远程机器上执行。这个功能在排查问题时特别好用,省掉了远程桌面的开销,哪怕带宽再小也能顺畅操作。

但要注意,Enter-PSSession默认不加载远程机器上的模块配置,有些自定义函数和模块需要先Import-Module。所以我一般会在进入会话后先加一行:

Set-Item WSMan:\localhost\Client\TrustedHosts -Value "server-01" -Concatenate

这是针对工作组环境的,域环境用Kerberos就不会有这个问题。

3.3 和自动化配置管理工具结合

如果你在运维中用了Ansible,那WinRM几乎是Windows节点认证的必备通道。Ansible通过ansible_connection: winrm连接目标机器,然后在上面执行Ansible模块。

一段典型的Ansible主机清单配置:

[windows] win-web01 ansible_host=10.0.0.21 ansible_user=admin@example.local ansible_password=xxxx ansible_connection=winrm ansible_winrm_server_cert_validation=ignore

这里的ansible_winrm_server_cert_validation=ignore表示跳过证书校验,只适合测试环境。生产环境一定要配好证书,并设置传输协议为HTTPS。

实际项目中,我用WinRM配合Ansible批量完成了上千台Windows安全补丁的推送。整个过程不需要在服务器上安装额外Agent,只要WinRM服务正常,Ansible就能像SSH操作Linux一样操作Windows,效率非常高。

3.4 一个完整的批量部署案例

假设我要给50台Web服务器更新一个IIS配置节的参数。传统做法是远程桌面一台台改,而用WinRM只需要以下几行:

$servers = Get-Content "webservers.txt" Invoke-Command -ComputerName $servers -ScriptBlock { param($siteName) Set-WebConfigurationProperty -Filter "//system.webServer/security/authentication/anonymousAuthentication" ` -Name enabled -Value $true -PSPath "IIS:\Sites\$siteName" } -ArgumentList "defaultweb"

这样在几分钟内就完成了全量更新,而且每台机器的执行结果都会返回到本机控制台,方便记录和审计。

注意Set-WebConfigurationProperty是IIS自带的PowerShell模块,远程机器需要安装有IIS管理模块,否则会报命令缺失错误。因此在批量执行前,最好先在一台机器上测试脚本兼容性。

4. 安全风险与防线:别让招牌服务变成突破口

4.1 为什么WinRM会成为“横向移动”代名词

所谓横向移动,指攻击者拿到一台内网机器权限后,试图借助各类远程管理通道访问其他机器。WinRM之所以经常被提及,原因有三:

  1. 默认端口开放:很多企业服务器为了运维方便,直接开启了5985端口但没有限制来源IP,等于把门敞开;
  2. 凭据复用:管理员往往在多台机器上用同一套账号密码,攻下一台就等于拿到整个内网的管理员密码;
  3. 原生态原生:WinRM是基于系统的合法协议,流量和行为看起来非常正常,很多安全设备默认不拦截。

我在一次内部红队演练中就见过,攻击者用一套窃取到的本地管理员账号,通过WinRM在两分钟内拿下了整个网段的服务器。所以安全防御的核心不是禁用WinRM,而是把它锁到合理的范围内。

4.2 攻击者常走的三条路

描述攻击方式不是为了教人攻击,而是为了帮防守方建立正确的检测点。

第一,用Invoke-Command执行PowerShell命令。这不会在目标机器上落盘文件,纯内存操作。检测端要重点关注5985端口上出现过哪些不寻常的PowerShell连接。

第二,利用WinRM配合工具获取凭据。比如使用Mimikatz获取内存里的明文密码,然后通过WinRM继续连下一台机器。这时候事件日志里会出现多处登录记录。

第三,滥用Kerberos委派。如果域环境配置不当,攻击者可以借用WinRM请求携带着高权限票据访问其他服务。

4.3 检测方案:我能看到什么

Windows的WinRM服务会记录日志,位置在“应用程序和服务日志/Windows/Windows Remote Management”。重点关注以下事件ID:

事件ID 6:WinRM服务初始化失败; 事件ID 101:客户端连接建立; 事件ID 142:客户端认证成功; 事件ID 150:客户端命令执行。

另外,PowerShell日志中,Event ID 4104(脚本块日志)和4103(模块日志)能记录远程执行的PowerShell命令。若看到来源为WSMan的PowerShell连接记录,就需要留意。

我在日常巡检时,会定期用Sysmon或者安全设备抓5985端口的连接元数据。如果发现非工作时间、非运维人员IP段大规模连接,基本可以判定异常。

4.4 加固清单:照着做就能消掉大部分风险

这里是我在生产环境中实际用过的加固方案,每一条都亲测有效:

加固项操作建议备注
启用HTTPS禁用HTTP监听,使用证书配置5986避免明文凭据传输
限制来源IP防火墙仅允许运维IP或者跳板机IP访问5985/5986最小化暴露面
关闭不必要的认证方式禁用Basic认证,保留KerberosBasic会把用户名密码明文发送
配置JEA (Just Enough Administration)为远程管理用户配置受限的PowerShell端点避免管理员权限过大
设置MaxShells和MaxProcessesWinRM服务级并发限制防止资源耗尽和暴力枚举
启用审计日志开启PowerShell脚本块日志和转录方便事后回溯
对异常登录做告警结合SIEM监控4624、4625事件勒索攻击前往往有大量登录尝试

还有一个容易被忽视的坑:不要把WinRM端口映射到外网。有人图方便在防火墙上做端口转发,结果直接把内网管理端口暴露到公网。一旦被扫描到,暴力破解几乎是迟早的事。

5. 常见问题与排查技巧实录

5.1 连接超时

我早期配置WinRM时遇到最多的问题就是“连接超时”。排查思路很固定:

先确认目标机器WinRM服务是否启动:

Get-Service WinRM

再确认防火墙规则:

Get-NetFirewallRule -Name "WINRM*" | Select-Object Name,Enabled,Direction

最后测试端口连通性:

Test-NetConnection -ComputerName "server-01" -Port 5985

如果结果是TcpTestSucceeded : False,仔细查看防火墙是否放行了局域网配置文件对应的端口。记住:Windows防火墙默认有“域、专用、公用”三种配置文件,WinRM默认只在“域”配置中放行。如果你的机器放在“专用”网络里,记得手动放行。

5.2 认证失败,用户名密码都是对的

这个坑十有八九是TrustedHosts没配置。在工作组环境,或者目标机器没有做域名接入时,WinRM客户端默认只允许来自受信任主机的连接。查看当前受信任主机:

Get-Item WSMan:\localhost\Client\TrustedHosts

如果为空,添加:

Set-Item WSMan:\localhost\Client\TrustedHosts -Value "server-01" -Concatenate

注意-Concatenate表示追加,如果不加会把原有内容覆盖掉。更宽泛的做法是设置星号*,表示信任所有主机,但这样等于丧失了来源限制,强烈不建议。

5.3 连接成功但提示拒绝访问

这通常是因为目标机器上的WinRM服务运行正常,但用户权限不足。在域环境里需要确保当前登录用户是目标机的本地管理员组成员,或者域管理员组里有权限。在纯工作组环境,则需要检查LocalAccountTokenFilterPolicy是否设置,前面已经讲过。

5.4 PowerShell模块无法加载

远程执行时如果要用到特定模块,比如IIS管理、AD管理,需要目标机器上安装对应的RSAT工具或者角色模块。很多时候不是代码的问题,是目标机器缺少模块。解决方案是把模块路径加入远程会话的环境变量:

Invoke-Command -ComputerName server-01 -ScriptBlock { Import-Module ActiveDirectory -ErrorAction Stop Get-ADUser -Filter * }

如果目标机器确实没有AD模块,就会报Import-Module : Could not load file or assembly,这种情况建议先在目标机器预装模块再执行。

5.5 双跳问题

所谓双跳,就是你从A机器连到B机器,在B机器上执行命令时,命令里需要再连接C机器(比如B上执行Get-ADUser要连接域控)。默认情况下,B上的第二次连接不会带上你的身份认证,这就导致失败。

解决方案有三个:

  • 使用CredSSP,前面已经提过;
  • 把需要远程访问的脚本文件放在目标机器本地,在B上使用计划任务执行;
  • 在B机器上配置Kerberos约束委派。

第三种最安全,但配置相对复杂。我的建议是:能不用CredSSP就不用,毕竟它会把凭据明文暴露给目标机器。

6. 最后提醒几个值得养成的习惯

用WinRM时间长了,我总结出三个必须刻进肌肉记忆的要点。

第一,每次连接前先确认目标机器是否在运维白名单里。不是技术问题,而是习惯问题。你永远不知道哪台机器因为某个历史原因开着WinRM,如果恰好是DMZ区的机器,连上去可能就是一次安全事故。

第二,所有生产环境的WinRM一律走HTTPS。即便内网有防火墙,明文传输这种风险也不值得冒。证书可以用内部CA统一签发,别用自签名证书糊弄,不然客户端报错排查起来更烦。

第三,批量执行时永远先跑一小批测试。我习惯先对一台机器跑通脚本,确认无异常再扩展到全部。批量操作最怕的不是脚本本身有问题,而是脚本在100台机器上产生了意料之外的副作用,等反应过来已经晚了。

最后再分享一个小技巧:如果觉得Invoke-Command的返回值解析起来麻烦,可以在命令里直接指定输出格式为ConvertTo-Json,这样每条结果都是结构化数据,方便存到日志系统里:

Invoke-Command -ComputerName $servers -ScriptBlock { Get-Process | Select-Object Name,Id,CPU } | ConvertTo-Json -Depth 3 | Out-File "process_report.json"

WinRM是一把双刃剑。用得好,它是大规模Windows运维的利器;用不好,它就是内网中一把敞开的门。这篇就是把这把剑的剑柄和剑刃都掰开给你看,怎么握住它,就看你自己的选择了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询