系统极客一直在努力
专注操作系统及软件使用技能

查看 Windows 远程桌面连接历史,7 步构建安全审计时间线

Windows 11

只要通过 RDP 远程桌面协议连接 Windows 设备,就会在系统「事件日志」中留下诸多操作痕迹。安全审计真正的难点在于:如何把远程交互会话从本地控制台登录中剥离出来,再将散落在各处的「事件」串连成一条完整的时间线。

本文梳理了 RDP 连接的关键事件 ID、筛选规则和一整套简单好用的事件关联逻辑,并补充了客户端侧的痕迹排查技巧。整个流程共分为 7 步:定位事件源 → 拉取历史日志 → 关联会话 → 捕获失败与异常事件 → 补齐客户端痕迹 → 日志集中留存 → 输出审计结论。

查看 Windows 远程桌面连接历史

第 1 步:定位事件源

目标: 搞清楚有哪些 Windows 日志记录了身份认证事件,哪些专门承载 RDP 会话与连接上下文。

1Windows + R打开「运行」对话框,输入eventvwr.msc并回车,打开「事件查看器」。

2分别展开下列路径:

  • 「Windows 日志」>「安全」
  • 「应用程序和服务日志」>「Microsoft」>「Windows」>「TerminalServices-LocalSessionManager」>「Operational」
  • 「应用程序和服务日志」>「Microsoft」>「Windows」>「TerminalServices-RemoteConnectionManager」>「Operational」

3按场景筛选并记录以下核心事件 ID:

阶段事件来源关键事件 ID
身份验证安全日志4624登录成功、4625登录失败、4634注销、4647用户主动注销
RDP 连接(登录前的连接握手)RemoteConnectionManager1149用户通过远程桌面完成预认证
RDP 会话活动(登录后的会话生命周期)LocalSessionManager21登录、22Shell 启动,桌面真正可用、23注销、24断开连接、25重连

第 2 步:使用 PowerShell 批量拉取日志

目标:从多个日志批量导出 RDP 相关事件,用于后续分析或归档。

1右键点击「开始」菜单,选择「终端管理员」,以管理员权限打开 Windows 终端。

2Ctrl + Shift + 1快捷键,切换到 PowerShell 窗口。

3粘贴下列脚本并回车:

  • 把最近 7 天的登录成功/失败事件带上LogonType和源 IP 一并导出:
# 导出最近 7 天的安全日志(4624 成功、4625 失败),提取登录类型、用户名、来源 IP
Get-WinEvent -FilterHashtable @{
    LogName   = 'Security'
    Id        = 4624,4625
    StartTime = (Get-Date).AddDays(-7)
} | ForEach-Object {
    $xml = [xml]$_.ToXml()
    [PSCustomObject]@{
        TimeCreated = $_.TimeCreated
        EventID     = $_.Id
        LogonType   = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'LogonType' }).'#text'
        User        = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
        IpAddress   = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'IpAddress' }).'#text'
    }
} | Export-Csv C:\Logs\SecurityEvents.csv -NoTypeInformation -Encoding UTF8

先手动创建C:\Logs\目录或换个位置;如需拉取更长时间范围,就把AddDays(-7)中的参数改为对应天数;事件量对应了 CSV 大小。

  • 导出本地会话管理器(Local Session Manager, LSM)的完整操作日志:
# 导出 LSM 操作日志,包含会话启动、断开、注销等事件
Get-WinEvent -LogName "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational" |
    Export-Csv C:\Logs\LSM_Events.csv -NoTypeInformation -Encoding UTF8

第 3 步:关联事件,还原会话时间线

目标:通过匹配用户名、来源 IP 和时间戳等,拼接出完整的会话起止记录。

3.1 方法论

  • 匹配1149事件(RCM 预认证)与4624事件(LogonType = ID,即远程交互式登录)。关联字段为:用户名 + 时间戳(误差 ± 1 分钟)。
    LogonType ID含义类型
    2本地控制台登录(直接坐在机器前登录)本地登录
    7解锁屏幕(含 RDP 会话建立时的伴生解锁事件)本地登录
    3NLA 模式下的 RDP 远程登录(Windows 默认配置)RDP 登录
    10标准 RDP 远程登录(未开启 NLA 时)RDP 登录

    配置 Windows 11 远程桌面连接时,系统通常会默认启用「使用网络级别身份验证」,即 NLA 模式。

    • 补充 LSM 的22事件,确认桌面 Shell 已启动、远程桌面会话真正进入可用状态。
    • 以 LSM 的23事件(注销)或24事件(断开连接但未注销)标定会话结束时间。
    • 会话时长 = 结束时间 – 1149事件的时间戳,就能得到完整的会话时长。

      之所以这么拼接操作是因为:

      • 安全日志中的4624事件包含了用户名和来源 IP,但无法区分登录渠道;
      • 1149事件明确标识了 RDP 连接请求,但却发生在认证流程完成前。

      两者交叉验证,才能准确定位 RDP 会话并获取完整的来源信息,具体如何组合,需要你自由发挥,可以将 CSV 导入到 Excel 进行综合分析。

      3.2 具体示例

      例如,只需要简单识别出哪个用户、在哪个时间、从哪个 IP,远程登录了这台机器,会话时长是多少,就可以组合出以下 PowerShell 脚本:

      查看 Windows 远程桌面连接历史
      查看 Windows 远程桌面连接历史
      #Requires -RunAsAdministrator
      # RDP Login Audit | 需管理员权限运行
      # 用法:.\RDP_Simple.ps1 [-DaysBack 30] [-OutputPath "D:\Audit\rdp.csv"]
      
      param(
          [int]    $DaysBack   = 7,
          [string] $OutputPath = "C:\Logs\RDP_Simple.csv"
      )
      
      $OutputDir = Split-Path $OutputPath
      if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir | Out-Null }
      
      # 1. 登录事件:LogonType 3(NLA 模式)和 10(标准 RDP),排除本机 IP
      $logins = Get-WinEvent -FilterHashtable @{
          LogName   = 'Security'
          Id        = 4624
          StartTime = (Get-Date).AddDays(-$DaysBack)
      } -ErrorAction SilentlyContinue | ForEach-Object {
          $xml = [xml]$_.ToXml()
          $ns  = $xml.Event.EventData.Data
          $lt  = ($ns | Where-Object Name -eq 'LogonType').'#text'
          $ip  = ($ns | Where-Object Name -eq 'IpAddress').'#text'
          if ($lt -in @('3', '10') -and $ip -and $ip -notmatch '^(::1|127\.|-)') {
              [PSCustomObject]@{
                  LoginTime = $_.TimeCreated
                  UserName  = ($ns | Where-Object Name -eq 'TargetUserName').'#text'
                  SourceIP  = $ip
                  LogonType = $lt
                  LogonID   = ($ns | Where-Object Name -eq 'TargetLogonId').'#text'
              }
          }
      } | Where-Object { $_.UserName -and $_.UserName -ne '-' }
      
      # 2. 去重:同用户同 IP 5 秒内只保留第一条(每次连接会触发多条重复事件)
      $script:lastEvent = $null
      $deduped = $logins | Sort-Object LoginTime | ForEach-Object {
          $cur = $_
          if (-not $script:lastEvent -or
              $cur.UserName -ne $script:lastEvent.UserName -or
              $cur.SourceIP -ne $script:lastEvent.SourceIP -or
              ($cur.LoginTime - $script:lastEvent.LoginTime).TotalSeconds -gt 5) {
              $script:lastEvent = $cur
              $cur
          }
      }
      
      # 3. 登出事件:4634 系统注销/4647 用户主动注销
      $logoffs = Get-WinEvent -FilterHashtable @{
          LogName   = 'Security'
          Id        = 4634, 4647
          StartTime = (Get-Date).AddDays(-$DaysBack)
      } -ErrorAction SilentlyContinue | ForEach-Object {
          $xml = [xml]$_.ToXml()
          $ns  = $xml.Event.EventData.Data
          [PSCustomObject]@{
              LogoffTime = $_.TimeCreated
              LogonID    = ($ns | Where-Object Name -eq 'TargetLogonId').'#text'
          }
      } | Where-Object { $_.LogonID }
      
      # 4. 用 LogonID 关联登出,计算时长
      $result = foreach ($login in $deduped) {
          $logoff = $logoffs |
              Where-Object {
                  $_.LogonID    -eq $login.LogonID -and
                  $_.LogoffTime -gt $login.LoginTime
              } |
              Sort-Object LogoffTime |
              Select-Object -First 1
      
          $duration = if ($logoff) {
              $span = $logoff.LogoffTime - $login.LoginTime
              '{0:D2}:{1:D2}:{2:D2}' -f [int]$span.TotalHours, $span.Minutes, $span.Seconds
          } else { '进行中' }
      
          [PSCustomObject]@{
              登录时间 = $login.LoginTime
              用户名   = $login.UserName
              来源IP   = $login.SourceIP
              登录类型 = if ($login.LogonType -eq '10') { 'RDP 直连' } else { 'RDP (NLA)' }
              会话时长 = $duration
          }
      }
      
      # 5. 导出并预览最近 10 条
      $result | Sort-Object 登录时间 |
          Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
      
      Write-Host "✅ 完成,共 $($result.Count) 条记录 → $OutputPath" -ForegroundColor Green
      $result | Sort-Object 登录时间 -Descending | Select-Object -First 10 | Format-Table -AutoSize
      

      第 4 步:捕获失败事件与异常行为

      目标:识别暴力破解(枚举密码反复尝试登录)、撞库(用同一密码横扫多个账户)或越权使用等异常行为。

      1Windows + R打开「运行」对话框,输入eventvwr.msc并回车,打开「事件查看器」。

      2展开「Windows 日志」>「安全」。

      3在右侧「操作」面板中点击「筛选当前日志…」。

      4在「事件 ID」中填入4625,点击「确定」。

      5在筛选结果的「常规」或「详细信息」选项卡中,重点关注以下字段:

      TargetUserName被攻击的目标账户
      IpAddress攻击来源 IP
      Status/SubStatus失败原因码,例如0xC000006A表示密码错误,0xC0000234表示账户被锁定
      筛选并查看 EventID 4625
      筛选并查看 EventID 4625

      第 5 步:补齐客户端侧痕迹

      目标:当服务器端日志缺失时,从发起端工作站反查连接目标。

      5.1 查找注册表 MRU 记录

      1Windows + R快捷键打开「运行」对话框,执行regedit打开注册表编辑器。

      2导航到以下路径:

      HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default
      

      3右侧会以MRU0MRU1MRU2等条目,列出最近连接过的 RDP 服务器名或 IP 地址。

      通过注册表查看最近连接过的 RDP 服务器
      通过注册表查看最近连接过的 RDP 服务器

      该注册表项仅在使用原生mstsc.exe客户端连接时,才会生成记录。如果用户从未发起过 RDP 连接,或使用第三方远程桌面工具,此处可能为空。

      5.2 查找跳转列表文件

      「跳转列表」(Jump List)缓存文件本质上是:某个程序最近打开过的文件、目标、连接记录:

      1Windows + E 快捷键打开「文件资源管理器」,在地址栏访问:

      %AppData%\Microsoft\Windows\Recent\AutomaticDestinations\
      

      2按「修改日期」排序,重点关注体积较大或近期改动过的文件。

      列出 Jump List 缓存文件
      列出 Jump List 缓存文件

      <hash>.automaticDestinations-ms文件可以通过 JumpListExplorer 等工具深度解析出:最近连接的服务器、访问时间使用的应用(比如mstsc.exe)。即便不解析,文件的存在性与修改时间戳本身也是审计依据。

      5.3 查找保存的 .rdp 连接文件

      1在「文件资源管理器」中进入以下路径:

      C:\Users\<username>\Documents\
      

      2搜索扩展名为.rdp的文件,并记录文件名与修改日期。

      .rdp文件属于可选痕迹,只在用户主动保存连接配置时才会生成。找不到不代表没用过 远程桌面。

      优化运维与安全审计

      第 6 步:日志大小与长期保存

      目标:构建持续可见性能力,防止日志滚动覆盖关键审计事件。

      6.1 调大日志存储上限

      1打开「事件查看器」,进入「Windows 日志」。

      2右键点击「安全」,选择「属性」。

      3把「最大日志大小」调整为更大的值。

      4选择「按需要覆盖事件」或「日志满时将其存档,不覆盖事件」,确认并保存。

      安全日志没有放之四海皆准的推荐容量,通常按「预期日均事件量 × 期望保留周期」反推出所需容量。高活跃服务器建议 1GB 起步。

      6.2 手动导出日志备份

      在「事件查看器」中依次对以下 3 项日志执行「右键」>「将所有事件另存为」操作,保存到可靠位置,并在文件名中添加导出日期:

      • 「Windows 日志」>「安全」
      • 「应用程序和服务日志」>「Microsoft」>「Windows」>「TerminalServices-LocalSessionManager」>「Operational」
      • 「应用程序和服务日志」>「Microsoft」>「Windows」>「TerminalServices-RemoteConnectionManager」>「Operational」

      第 7 步:输出结论,把数据变成运维动作

      目标:让审计结果真正落地,而不是躺在 CSV 里吃灰。

      1. 针对重复性失败登录、未知来源 IP 访问、日志覆盖断档等问题,建立运维工单跟进。
      2. 将完整的会话时间线附入事件复盘报告和服务评审材料。
      3. 定期复核会话记录覆盖范围与访问例外清单。

      RDP 连接历史审计最佳实践

      下表汇总了日常审计中可以落地的经验:

      做法目的实际价值
      同时采集安全日志、LSM、RCM 三类日志扩大审计覆盖面排查效率更高,判断依据更充分
      LogonType = ID与事件 ID 组合筛选精准分类事件清晰区分 RDP 登录与本地控制台登录
      关联预认证事件与认证完成事件准确来源归因实现用户身份与访问 IP 的一一映射
      统一导出为 CSV 或 JSON 格式标准化数据源支持重复审计与业务复盘场景
      集中转发并长期留存日志提升数据可靠性可随时调取完整的历史会话时间线

      常见问题解答

      如何快速区分到底是 RDP 还是本地控制台登录?

      查看安全日志4624事件中的LogonType字段即可快速判定:10代表标准 RDP 远程交互登录,3代表 NLA 模式下的 RDP 登录,7为解锁屏幕,2为本地控制台登录。只要筛选出LogonType等于3和10的记录,就能得到所有 RDP 登录事件。

      登录失败事件 4625 里常见的 Status 报错码怎么解读?

      赞(1)
      分享到

      评论 抢沙发