跳转到帖子

授权内网测试发现 WinRM 横向痕迹,如何还原账号、源主机与执行链路?

精选回复

发布于

问题背景

在一次已授权的 Windows 域内网渗透测试中,测试人员使用普通域账号从工作站访问成员服务器的 WinRM 服务。服务器随后出现异常 PowerShell 进程,但现有报告只能证明“远程管理发生过”,无法准确回答以下问题:

  • 是哪一个账号完成了远程登录?
  • 连接来自哪台主机、哪个源地址?
  • 远程会话执行了哪些命令?
  • 是否发生了显式凭据使用、权限提升或日志清理?
  • 当前日志配置能否形成完整证据链?

这类问题不能只查单个事件 ID。比较可靠的做法是按“网络连接、身份认证、会话建立、进程执行、PowerShell 内容、权限变化”六个环节关联时间线。

问题定位

先确认调查范围和时间基准。域控、源工作站、目标服务器可能使用不同的时区展示格式,事件日志内部时间则以 UTC 保存。建议记录测试开始与结束时间,并将检索窗口向前后各扩展 10 至 15 分钟。

证据位置重点日志主要用途
目标服务器Security、WinRM Operational、PowerShell Operational确认登录、会话及命令执行
域控制器Security确认 Kerberos 或 NTLM 认证
源工作站Security、PowerShell、进程创建日志定位发起端账号及客户端进程
网络设备或 EDR流量、进程树、网络连接补足源地址、目标端口和父子进程关系

WinRM 默认使用 TCP 5985,HTTPS 监听通常使用 TCP 5986。端口开放只能证明服务可达,不能单独证明远程命令执行成功。

技术分析

目标服务器上的 Security 事件 4624 是登录成功的核心证据。远程管理常见登录类型为 3,但登录类型 3 也可能来自 SMB、计划任务或其他网络访问,因此必须结合源地址、认证包、WinRM 日志与进程创建事件判断。

  • 4624:关注 TargetUserName、TargetDomainName、LogonType、IpAddress、AuthenticationPackageName、LogonId。
  • 4625:用于识别失败尝试,重点查看 Status、SubStatus、IpAddress。
  • 4648:表示某进程尝试使用显式凭据,适合排查 runas、脚本传入凭据等情况,但并非所有远程访问都会产生该事件。
  • 4672:高权限账号登录后被分配敏感权限。应通过 SubjectLogonId 与 4624 的 LogonId 关联。
  • 4688:进程创建。启用命令行审计后,可看到 NewProcessName、ParentProcessName 和 ProcessCommandLine。
  • 4768、4769:域控上的 Kerberos 票据申请。4769 可用于确认目标服务票据和客户端地址。
  • 4776:域控或本地系统验证 NTLM 凭据时常见,可辅助识别 Kerberos 降级或 NTLM 使用。
  • 1102:Security 日志被清除,应作为高优先级告警处理。

WinRM 远程 PowerShell 的典型进程链可能包含 svchost.exe、wsmprovhost.exe 与 powershell.exe。实际父子关系受系统版本、PowerShell 版本和 EDR 展示方式影响,不应只依赖进程名定性。应同时关联登录标识、时间、网络连接和脚本块日志。

关键点:4624 中的 LogonId、4672 中的 SubjectLogonId,以及 4688 中的 TargetLogonId 是串联身份与进程的重要字段。日志采集平台应保留这些原始十六进制值,避免字段归一化时丢失。

操作步骤

第一步,在目标服务器确认 WinRM 监听器、服务状态和允许的认证方式。以下命令只用于授权环境中的核查,不建议为了测试临时放宽认证策略。

Get-Service WinRM
winrm enumerate winrm/config/listener
winrm get winrm/config/service
Get-NetTCPConnection -State Listen | Where-Object {
    $_.LocalPort -in 5985,5986
} | Format-Table LocalAddress,LocalPort,OwningProcess

重点检查 AllowUnencrypted 是否被错误开启、Basic 认证是否非必要启用,以及 HTTPS 监听器证书是否有效。域环境通常优先使用 Kerberos;跨域、IP 直连或名称解析异常时,认证方式可能发生变化。

第二步,从目标服务器导出调查时间段内的关键事件。导出原始 EVTX 比复制事件文本更可靠,因为原始文件保留完整 XML 字段和签名信息。

$start = (Get-Date).AddHours(-2)
$end = Get-Date

$ids = 4624,4625,4648,4672,4688,1102
Get-WinEvent -FilterHashtable @{
    LogName   = 'Security'
    Id        = $ids
    StartTime = $start
    EndTime   = $end
} | Select-Object TimeCreated,Id,RecordId,MachineName,Message |
    Export-Csv C:\IR\security_timeline.csv -NoTypeInformation -Encoding UTF8

wevtutil epl Security C:\IR\Security.evtx
wevtutil epl 'Microsoft-Windows-WinRM/Operational' C:\IR\WinRM-Operational.evtx
wevtutil epl 'Microsoft-Windows-PowerShell/Operational' C:\IR\PowerShell-Operational.evtx

第三步,使用事件 XML 而不是本地化后的 Message 文本提取字段。不同语言系统中的事件描述不同,按字段名解析更适合自动化关联。

$events = Get-WinEvent -FilterHashtable @{
    LogName   = 'Security'
    Id        = 4624
    StartTime = $start
    EndTime   = $end
}

$events | ForEach-Object {
    $xml = [xml]$_.ToXml()
    $data = @{}
    foreach ($item in $xml.Event.EventData.Data) {
        $data[$item.Name] = [string]$item.'#text'
    }
    [pscustomobject]@{
        TimeCreated = $_.TimeCreated
        RecordId    = $_.RecordId
        User         = $data.TargetUserName
        Domain       = $data.TargetDomainName
        LogonType    = $data.LogonType
        LogonId      = $data.TargetLogonId
        SourceIP     = $data.IpAddress
        SourcePort   = $data.IpPort
        AuthPackage  = $data.AuthenticationPackageName
        Workstation  = $data.WorkstationName
    }
} | Where-Object {
    $_.LogonType -eq '3' -and $_.SourceIP -notin '-', '127.0.0.1', '::1'
} | Sort-Object TimeCreated | Format-Table -AutoSize

第四步,在域控检索同一账号和源地址对应的 4768、4769 或 4776。若目标服务器的 4624 显示 Kerberos,应重点核对 4769 的 ClientAddress、ServiceName 和账号;若显示 NTLM,则检查 4776,并调查是否存在 IP 直连、SPN 缺失、DNS 异常或跨信任边界等原因。

第五步,关联进程与 PowerShell 日志。4688 中如果出现 wsmprovhost.exe 及其后续解释器进程,应检查相邻时间的 PowerShell Operational 事件。启用脚本块日志后,4104 可提供执行内容;4103 可记录模块级调用。单独出现 4104 不等于恶意行为,需要结合账号、主机、脚本内容和测试时间判断。

Get-WinEvent -FilterHashtable @{
    LogName   = 'Microsoft-Windows-PowerShell/Operational'
    Id        = 4103,4104
    StartTime = $start
    EndTime   = $end
} | Select-Object TimeCreated,Id,RecordId,Message |
    Sort-Object TimeCreated |
    Export-Csv C:\IR\powershell_events.csv -NoTypeInformation -Encoding UTF8

如何判断证据链是否成立

一个较完整的 WinRM 横向验证链路至少应满足以下条件:

  • 网络或主机日志证明源地址连接目标 5985 或 5986。
  • 目标服务器出现对应账号、源地址和时间的 4624。
  • 域控存在相邻时间的 Kerberos 或 NTLM 认证记录。
  • WinRM Operational 日志显示会话活动。
  • 目标服务器出现与远程会话时间一致的进程创建记录。
  • PowerShell 日志或 EDR 遥测能够说明执行内容。

如果只有 4624,没有 WinRM 会话和进程证据,结论应写成“发现网络登录”,而不是直接写成“已通过 WinRM 执行命令”。如果只有 4688,而没有对应账号和登录标识,应继续从 EDR 进程树、计划任务日志、服务创建记录等方向排查。

常见缺口与补充配置

最常见的问题是 4688 已启用,但未记录命令行。可通过组策略启用“审核进程创建”,同时启用“在进程创建事件中包括命令行”。命令行可能包含口令、令牌或业务参数,集中采集前应设置访问控制和脱敏规则。

auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable

gpresult /h C:\IR\gpresult.html

auditpol /get /category:*

PowerShell 日志建议通过域组策略统一启用脚本块日志和模块日志,并将日志转发到独立采集端。对于高敏感终端,可评估启用转录日志,但必须限制目录权限,防止转录内容被普通用户读取。

Windows 事件转发环境应重点核查订阅是否覆盖 Security、WinRM Operational 和 PowerShell Operational,客户端积压是否异常,以及收集器是否因容量不足覆盖旧日志。日志保存周期应大于常规调查发现周期。

风险与修复建议

  • 限制 WinRM 暴露面:通过主机防火墙仅允许管理网段和指定运维跳板机访问 5985、5986,避免全网段开放。
  • 优先 Kerberos:修复 DNS、SPN 和时间同步问题,减少不必要的 NTLM 使用;不要通过扩大 TrustedHosts 范围规避认证问题。
  • 使用 HTTPS 时校验证书:证书主题、用途和信任链应与管理入口一致,禁止为省事跳过校验。
  • 落实管理分层:高权限账号不应登录普通办公终端,域管理操作应从受控管理主机发起。
  • 减少长期高权限:采用即时授权、受限端点或 JEA,避免普通远程会话直接获得完整管理员能力。
  • 建立检测关联:对非管理网段访问 WinRM、异常账号的 4624 类型 3、显式凭据事件、wsmprovhost.exe 异常子进程和日志清除建立联合告警。
  • 保护日志:将关键事件实时转发到权限隔离的日志平台,本地日志只能作为证据源之一。

总结

WinRM 横向行为的排查重点不是找到某一个“万能事件 ID”,而是把源地址、账号、认证方式、LogonId、进程树和 PowerShell 内容放进同一时间线。授权测试报告也应区分“端口可达”“认证成功”“会话建立”和“命令执行”四个结论层级。证据不足时明确写出日志缺口,并给出具体审计策略和采集范围,比仅凭现象推断攻击链更可靠。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意
网络流量与边界分析示意图
网络请求、日志与边界流量分析示意

这类痕迹建议按“目标机登录会话 → WinRM Shell → 子进程 → 源端发起记录”四段还原,不要只看某一条 4624。先保全日志并统一时区;如果日志有轮转,优先导出原始 EVTX,避免后续查询继续覆盖。

1. 在目标机锁定账号和源地址

先查 Security/4624,WinRM 通常对应网络登录 LogonType=3。重点记录:

  • TargetUserName、TargetDomainName
  • IpAddress、WorkstationName
  • TargetLogonId
  • AuthenticationPackageName:Kerberos 或 NTLM
wevtutil epl Security C:\IR\Security.evtx
wevtutil epl Microsoft-Windows-WinRM/Operational C:\IR\WinRM-Operational.evtx
wevtutil epl Microsoft-Windows-PowerShell/Operational C:\IR\PowerShell-Operational.evtx

Get-WinEvent -FilterHashtable @{
    LogName='Security'
    Id=4624,4625,4634,4648,4672,4688
    StartTime=(Get-Date).AddDays(-7)
} | Sort-Object TimeCreated |
Select-Object TimeCreated,Id,RecordId,Message |
Out-File C:\IR\Security-events.txt -Width 500

4624 中的源 IP 是目标机实际看到的连接端,若经过跳板、NAT 或端口转发,它未必是最初操作终端。若地址显示为 ::1、127.0.0.1 或本机地址,要继续排查本机代理、计划任务和二次跳转。

同一时间附近的 4648 表示显式凭据使用,常见于 runas /netonly、显式传入凭据或二跳场景;4672 可辅助确认该登录会话是否获得管理员特权。关联时使用 TargetLogonId/SubjectLogonId,注意事件 XML 中通常以十六进制显示。

2. 用 WinRM Operational 日志确认会话

检查 Microsoft-Windows-WinRM/Operational,围绕可疑时间查连接、认证、Shell 创建和关闭记录。不同系统版本的事件 ID、字段略有差异,建议直接解析 XML,不要只依赖事件查看器的摘要文本。

$start = Get-Date '2025-01-01 10:00:00'
$end   = Get-Date '2025-01-01 11:00:00'

Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-WinRM/Operational'
    StartTime=$start
    EndTime=$end
} | ForEach-Object {
    [xml]$x = $_.ToXml()
    [pscustomobject]@{
        Time     = $_.TimeCreated
        Id       = $_.Id
        RecordId = $_.RecordId
        Data     = (($x.Event.EventData.Data | ForEach-Object {
                    "$($_.Name)=$($_.'#text')"
                   }) -join '; ')
        Message  = $_.Message
    }
} | Format-List

这里重点找 ShellId、RunspaceId、用户名、认证方式和客户端地址,再以时间窗口回查 Security 日志。仅凭 WinRM 服务启动事件只能证明服务可用,不能证明发生了远程命令执行。

3. 还原目标机执行链

典型 WinRM 链路会出现:

svchost.exe -k NetworkService ... WinRM
  └─ wsmprovhost.exe
       ├─ powershell.exe / pwsh.exe
       ├─ cmd.exe
       └─ 被执行的工具或脚本

如果已启用进程创建审计,用 4688 追踪 NewProcessId 与 CreatorProcessId。PID 在事件中可能是十六进制,转换后再关联;同时要考虑 PID 重用,因此必须叠加时间条件。

Get-WinEvent -FilterHashtable @{
    LogName='Security'
    Id=4688
    StartTime=$start
    EndTime=$end
} | Where-Object {
    $_.Message -match 'wsmprovhost\.exe|powershell\.exe|pwsh\.exe|cmd\.exe'
} | Select-Object TimeCreated,RecordId,Message |
Format-List

若有 Sysmon,优先看事件 1,字段更适合构建父子关系:

Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-Sysmon/Operational'
    Id=1,3
    StartTime=$start
    EndTime=$end
} | Where-Object {
    $_.Message -match 'wsmprovhost\.exe|DestinationPort:\s+(5985|5986)'
} | Select-Object TimeCreated,Id,RecordId,Message |
Format-List

PowerShell Remoting 还应关联 PowerShell/Operational 的 4103、4104,以及 Windows PowerShell 日志中的引擎、提供程序和远程运行空间记录。4104 若存在,通常能直接恢复脚本块;若只有编码参数,可从 4688 命令行提取后再离线解码。没有 4688 命令行或 4104 时,不建议仅根据 wsmprovhost.exe 推断具体命令。

4. 反查源主机,区分“源地址”和“实际操作者”

在 4624 得到候选 IP 后,到该主机查询同一时间段:

  • PowerShell 4103/4104、控制台历史,是否出现 Enter-PSSession、Invoke-Command、New-PSSession;
  • Security 4688,是否启动 powershell.exe、winrs.exe 或相关管理程序;
  • Security 4648,显式使用的是哪个目标账号、目标服务器;
  • Sysmon 3、EDR 网络遥测或防火墙日志,是否向目标机 5985/5986 建连;
  • 若使用域账号,结合域控上的 4768、4769、4776 判断 Kerberos/NTLM 认证来源。
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-PowerShell/Operational'
    Id=4103,4104
    StartTime=$start
    EndTime=$end
} | Where-Object {
    $_.Message -match 'Enter-PSSession|Invoke-Command|New-PSSession|ComputerName|SessionOption'
} | Select-Object TimeCreated,Id,RecordId,Message |
Format-List

Kerberos 场景可在域控重点查目标服务票据,例如 HTTP/目标主机;WinRM 默认使用 HTTP SPN,即使传输层没有配置 HTTPS,也不代表认证一定是明文。NTLM 场景则结合 4776、目标机 4624 和网络设备日志,可信度会更高。

5. 最终时间线建议

整理时至少保留以下字段,避免只写结论:

时间(UTC 与本地)
目标主机
源 IP / 源主机名
账号 / 域
认证包
4624 LogonId
WinRM ShellId / RunspaceId
wsmprovhost PID
子进程 PID、父 PID、命令行
PowerShell ScriptBlockId
相关事件 RecordId
日志来源与原始 EVTX 哈希

比较可靠的闭环应当是:目标机 4624 的源 IP 和账号,与 WinRM Shell 时间一致;随后出现归属于该会话时间窗的 wsmprovhost.exe 及子进程;源机同时存在到目标 5985/5986 的连接或 Remoting 命令;域控认证记录再提供账号与服务票据旁证。若只能满足其中一两项,应标注为“疑似”,尤其不能把 4624 中的跳板地址直接写成实际操作者主机。


			

			
		

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。