跳转到帖子

授权内网测试中发现疑似横向移动,如何定位来源、确认权限边界并给出修复建议

精选回复

发布于

背景

最近在一次授权内网渗透测试复盘里,有同事问到一个比较典型的问题:测试过程中在一台业务服务器上发现异常登录痕迹,疑似存在横向移动,但不确定是测试人员操作、运维正常登录,还是历史遗留风险。这个问题比较适合放在问答中心讨论,因为它不只是“怎么打”,更关键是如何确认权限边界、留痕来源、影响范围和修复优先级。

场景如下:

  • 内网为 Windows 域环境,域控为 Windows Server 2019。
  • 业务服务器为 Windows Server 2016,加入域。
  • 授权测试范围包含指定网段和指定业务服务器,不允许对域控做破坏性操作。
  • 在业务服务器上发现管理员组成员异常、RDP 登录记录异常、部分共享目录访问异常。
下面内容以蓝队排查和授权测试验证为主,不涉及绕过、防杀、持久化等攻击实现细节。重点是:怎么确认问题、怎么取证、怎么修。

问题定位

遇到这类情况,先不要急着下结论。我的处理顺序一般是:

  • 确认时间线:异常行为发生在授权测试期间,还是测试之前已经存在。
  • 确认账号身份:是测试账号、运维账号、业务账号,还是疑似被盗用账号。
  • 确认登录类型:交互式登录、RDP、网络登录、计划任务、服务启动分别对应不同风险。
  • 确认来源 IP:是否来自测试机、堡垒机、运维跳板机,还是非授权终端。
  • 确认权限边界:该账号是否本应拥有本机管理员权限、域权限或共享访问权限。

Windows 日志里优先看几个事件 ID:

事件 ID含义关注点
4624登录成功Logon Type、Account Name、Source Network Address
4625登录失败爆破、口令喷洒、错误来源
4672特殊权限登录管理员权限账号登录
4720创建用户是否出现异常本地或域账号
4728/4732加入特权组Domain Admins、本地 Administrators
7045创建服务横向移动、远程执行常见痕迹
4698创建计划任务远程任务执行或持久化风险

技术分析

这里重点看 4624 登录事件中的 Logon Type。它能帮助判断行为类型:

  • Logon Type 2:本地交互式登录。
  • Logon Type 3:网络登录,常见于 SMB、远程管理、共享访问。
  • Logon Type 7:解锁登录。
  • Logon Type 10:RDP 远程交互式登录。
  • Logon Type 11:缓存凭据登录。

如果业务服务器上出现大量 Logon Type 3,并且来源 IP 不是堡垒机或测试机,需要重点排查 SMB 访问、远程服务创建、计划任务执行等行为。如果同时伴随 7045 或 4698,基本可以认为存在远程执行痕迹。

另一个关键点是权限边界。很多内网问题不是单个漏洞,而是权限配置过大导致的链路风险,例如:

  • 普通运维账号被加入多台服务器本地 Administrators。
  • 域用户拥有不必要的远程登录权限。
  • 共享目录对 Authenticated Users 开放写权限。
  • 服务账号长期使用固定弱口令,且可交互式登录。
  • 本地管理员密码多台机器复用。

操作步骤

建议按下面步骤排查,先保全日志,再做验证,避免覆盖现场。

  • 导出目标服务器安全日志、系统日志、PowerShell 日志。
  • 筛选授权测试时间窗口内的登录成功、登录失败和特权登录事件。
  • 关联来源 IP、账号、登录类型和主机名。
  • 检查本地管理员组成员变化。
  • 检查近期新增服务、计划任务、启动项。
  • 检查共享目录权限和访问日志。
  • 和授权测试人员操作记录、堡垒机记录、VPN 记录做时间线比对。

代码/命令示例

以下 PowerShell 命令适合在被授权的 Windows 服务器上做初步排查。建议以只读方式执行,并将结果导出保存。

# 查询最近 7 天内成功登录事件,重点关注账号、登录类型、来源 IP
$start = (Get-Date).AddDays(-7)
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624; StartTime=$start} | ForEach-Object {
    $xml = [xml]$_.ToXml()
    $data = @{}
    foreach ($d in $xml.Event.EventData.Data) {
        $data[$d.Name] = $d.'#text'
    }
    [PSCustomObject]@{
        TimeCreated   = $_.TimeCreated
        TargetUser    = $data['TargetUserName']
        TargetDomain  = $data['TargetDomainName']
        LogonType     = $data['LogonType']
        SourceIP      = $data['IpAddress']
        Workstation   = $data['WorkstationName']
        ProcessName   = $data['ProcessName']
    }
} | Where-Object {
    $_.TargetUser -notmatch '^(SYSTEM|LOCAL SERVICE|NETWORK SERVICE|ANONYMOUS LOGON)$'
} | Sort-Object TimeCreated | Export-Csv .\login_4624_last7days.csv -NoTypeInformation -Encoding UTF8

# 查询特殊权限登录事件
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4672; StartTime=$start} |
Select-Object TimeCreated, ProviderName, Id, Message |
Out-File .\privileged_logon_4672.txt -Encoding UTF8

# 查询近期新增服务痕迹
Get-WinEvent -FilterHashtable @{LogName='System'; Id=7045; StartTime=$start} |
Select-Object TimeCreated, Id, Message |
Out-File .\service_created_7045.txt -Encoding UTF8

# 查询本地管理员组成员
Get-LocalGroupMember -Group 'Administrators' |
Select-Object Name, ObjectClass, PrincipalSource |
Export-Csv .\local_admin_members.csv -NoTypeInformation -Encoding UTF8

# 查询计划任务,按更新时间排序
Get-ScheduledTask | ForEach-Object {
    $info = Get-ScheduledTaskInfo -TaskName $_.TaskName -TaskPath $_.TaskPath -ErrorAction SilentlyContinue
    [PSCustomObject]@{
        TaskName = $_.TaskName
        TaskPath = $_.TaskPath
        State = $_.State
        LastRunTime = $info.LastRunTime
        NextRunTime = $info.NextRunTime
        Author = $_.Author
    }
} | Sort-Object LastRunTime -Descending |
Export-Csv .\scheduled_tasks.csv -NoTypeInformation -Encoding UTF8

如果环境里部署了 Sysmon,可以进一步看远程执行、进程创建和网络连接。常见关注点:

  • Event ID 1:Process Create,关注异常父子进程关系。
  • Event ID 3:Network Connection,关注非常规外连。
  • Event ID 11:FileCreate,关注临时目录下异常可执行文件。
  • Event ID 13:Registry Value Set,关注启动项和策略变更。
# Sysmon 进程创建记录中筛选常见远程管理相关进程,仅用于排查定位
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Sysmon/Operational'; Id=1; StartTime=$start} |
Where-Object {
    $_.Message -match 'psexesvc|wmiprvse.exe|schtasks.exe|sc.exe|powershell.exe|cmd.exe'
} |
Select-Object TimeCreated, Message |
Out-File .\sysmon_process_suspect.txt -Encoding UTF8

判断示例

举一个比较常见的判断方式:

  • 10:21 出现账号 ops_backup 的 4624,Logon Type 3,来源 IP 为 10.10.8.23。
  • 10:21 同一账号出现 4672,说明该账号具备特权。
  • 10:22 系统日志出现 7045,创建了一个临时服务。
  • 10:23 Sysmon 记录显示服务进程启动 cmd.exe。
  • 10.10.8.23 不属于堡垒机、测试机或运维网段。

这种情况下,即使没有看到明显恶意文件,也应该按疑似横向移动处理。反过来,如果来源 IP 是授权测试机,时间线和测试记录一致,就可以归类为授权测试留痕,但仍需在报告中说明风险链路和修复建议。

风险与修复建议

修复时不要只删文件或清任务,重点是收敛权限和消除链路。

  • 收敛本地管理员组:只保留必要的运维组,移除个人域账号和长期不用的服务账号。
  • 启用 LAPS 或 Windows LAPS:避免本地管理员密码在多台主机复用。
  • 限制 RDP 登录:通过 GPO 限定允许远程登录的用户组,并限制来源网段。
  • 禁用服务账号交互式登录:服务账号只用于服务运行,不允许 RDP、控制台登录。
  • 清理共享权限:共享权限和 NTFS 权限都要检查,避免 Everyone 或 Authenticated Users 写权限。
  • 开启关键审计策略:登录事件、账号管理、对象访问、进程创建、PowerShell Script Block 日志。
  • 建立堡垒机闭环:运维操作必须经过堡垒机,并保留会话记录,减少来源 IP 不清的问题。
  • 做凭据轮换:涉及异常登录的账号应立即改密,服务账号改密前要评估业务依赖。

几个常用的 GPO 审计项可以参考:

计算机配置
  Windows 设置
    安全设置
      高级审核策略配置
        登录/注销
          审核登录:成功、失败
          审核特殊登录:成功
        帐户管理
          审核用户帐户管理:成功、失败
          审核安全组管理:成功、失败
        详细跟踪
          审核进程创建:成功

计算机配置
  管理模板
    系统
      审核进程创建
        在进程创建事件中加入命令行:启用

计算机配置
  管理模板
    Windows 组件
      Windows PowerShell
        Turn on PowerShell Script Block Logging:启用

总结

这类问题的核心不是单看某一条日志,而是把账号、来源 IP、登录类型、权限变化、服务/任务创建和测试授权记录串成时间线。授权测试中发现疑似横向移动时,建议先固定证据,再区分测试留痕、运维行为和真实风险。

最终报告里不要只写“存在横向移动风险”,最好明确写出:哪个账号、从哪个来源、在什么时间、通过什么登录类型、获得了什么权限、影响哪些主机,以及对应的权限收敛和审计加固方案。这样对甲方整改才有实际价值。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意

这类情况建议先按“时间线 + 身份链 + 网络链”三条线并行确认,不要一开始就只盯着某台被访问主机。尤其是在授权测试中,测试源地址、跳板机、代理和真实执行节点可能不是同一个。

1. 先固定证据和时间范围

以测试方提供的扫描/利用时间为起点,前后各保留至少 30 分钟日志。先不要急着重启、清理计划任务或删除账号,否则容易丢失登录来源和进程父子关系。

Windows 主机重点收集:

  • 4624:成功登录,重点看 LogonType、IpAddress、WorkstationName、TargetUserName。
  • 4625:失败登录,可判断是否存在撞库或权限探测。
  • 4648:使用显式凭据运行。
  • 4672:登录获得特殊权限。
  • 4688:进程创建,最好配合 Sysmon Event ID 1。
  • 5140/5145:SMB 共享访问。
  • 7045:服务安装,常见于远程服务型横向移动。
  • 4768/4769/4776:域认证、Kerberos 服务票据和 NTLM 校验。

例如先按账号、源地址和时间段导出登录事件:

Get-WinEvent -FilterHashtable @{
    LogName='Security'
    Id=4624,4625,4648,4672,4688,5140,5145,7045,4768,4769,4776
    StartTime=(Get-Date '2026-10-10 09:00')
    EndTime=(Get-Date '2026-10-10 10:00')
} | Export-Csv .\security-events.csv -NoTypeInformation -Encoding UTF8

Linux 主机则关注 /var/log/auth.log 或 /var/log/secure、journalctl、sudo 日志、auditd 和 EDR 进程树:

journalctl --since "2026-10-10 09:00" --until "2026-10-10 10:00" \
  | egrep -i 'sshd|sudo|su:|session opened|authentication failure|accepted'

grep -Ei 'Accepted|Failed password|sudo:|session opened|session closed' \
  /var/log/auth.log /var/log/secure 2>/dev/null

ausearch -ts 09:00:00 -te 10:00:00 -m USER_LOGIN,USER_START,EXECVE -i

2. 不要只看“来源 IP”,要重建完整跳转链

将以下字段按时间排序关联:

  • 源 IP、目标 IP、目标端口、NAT/代理前后的地址;
  • 登录账号、认证协议(Kerberos/NTLM/SSH)、LogonType;
  • 登录后 1~2 分钟内创建的进程、服务、计划任务和网络连接;
  • SMB、WinRM、RDP、SSH、WMI 等管理协议的连接记录;
  • 域控上的 4768/4769 与终端上的 4624 是否能按账号和时间对应。

例如,4624 中的 LogonType=3 通常是网络登录,10 是 RDP,9 常见于使用新凭据的网络访问。单独出现 4624 不能证明发生了横向移动,至少要和源地址、目标服务、后续进程或共享访问事件关联起来。

如果前端看到的源地址始终是跳板机或代理,不要据此认定跳板机上的人工操作。应进一步核对:

  • 跳板机 EDR 的进程树和命令行;
  • 代理软件访问日志、连接建立时间和目标列表;
  • DHCP、VPN、NAC、交换机或无线控制器记录;
  • 测试人员使用的账号、MFA 认证记录和工单时间。

3. 用“实际权限”确认边界,而不是只看用户名

Windows 重点确认三个边界:域权限、目标主机本地权限、资源级权限。建议在测试账号和疑似被使用账号的安全上下文中分别执行:

whoami /user
whoami /groups
whoami /priv
net user <username> /domain
net group "Domain Admins" /domain
net localgroup Administrators
gpresult /h C:\Temp\gp.html

如果存在域环境,还要检查该账号是否通过嵌套组、GPO Restricted Groups、登录脚本或本地组策略间接获得管理员权限。对服务器而言,能否访问 SMB 管理共享、通过 WinRM 登录、创建服务,分别代表不同的权限边界,不能笼统地归类为“有管理员权限”。

Linux 侧建议核对 sudo 规则、SSH 密钥、有效组和可执行文件权限:

id <user>
sudo -l -U <user>
getent group sudo
getent group wheel
find /etc/sudoers /etc/sudoers.d -type f -maxdepth 1 -exec grep -nEv '^\s*#|^\s*$' {} \;
find /home /root -path '*/.ssh/authorized_keys' -type f -ls

另外要单独核查服务账号、机器账号和委派配置。很多“横向移动”最后并不是普通用户越权,而是服务账号同时拥有多台服务器本地管理员权限,或存在不必要的 Kerberos 委派。

4. 修复建议应按确认结果分层

  • 账号层:立即禁用确认被滥用的账号,撤销活动会话和令牌,轮换密码、API 密钥、SSH 私钥及相关服务账号凭据。服务账号要确认密码轮换不会导致业务中断。
  • 权限层:移除普通账号的本地 Administrators、远程桌面和 WinRM 权限;使用组托管服务账号或等效机制,避免同一高权限账号复用到多台服务器。
  • 网络层:限制工作站到服务器之间的 SMB、WinRM、RDP、SSH 横向访问,只允许管理网段或明确的跳板机访问;不要仅依赖 VLAN,需配合东西向防火墙规则。
  • 认证层:优先使用 Kerberos 和强制 MFA,减少 NTLM,按兼容性逐步禁用 SMBv1;启用 LAPS/Windows LAPS 管理本地管理员密码,避免本地密码复用。
  • 审计层:启用进程创建命令行、PowerShell Script Block Logging、WinRM/SMB 审计、Sysmon 网络连接和服务创建事件,并将日志集中到不可被普通管理员删除的日志平台。
  • 持久化层:核查新建服务、计划任务、启动项、WMI Subscription、SSH authorized_keys、云平台访问密钥和 CI/CD 凭据。确认后再清理,并保留清理前的取证副本。

最终报告最好明确写出:入口主机、每一次跳转的源/目标、使用的账号和认证方式、当时的有效权限、访问的资源、是否突破了原定授权范围,以及每条结论对应的日志证据。这样才能区分“测试工具正常触达”“凭据复用导致的横向访问”和“实际权限提升”,也方便后续验证修复是否真正生效。

补充一个容易被忽略的点:横向移动来源不一定是 4624 里的 `IpAddress` 直接指向的那台机器,尤其是 SMB、WinRM、WMI、PSRemoting、远程服务创建混在一起时,建议把“认证来源”和“执行来源”拆开看。 可以按下面几个方向补齐证据链。

1. 先判断横向方式,别只看登录事件

如果怀疑是远程服务执行,重点看目标机: - `7045`:是否创建过临时服务 - `4697`:服务安装,部分系统才有 - `4688 / Sysmon 1`:`services.exe` 拉起了什么 - `5140/5145`:是否访问了 `ADMIN$`、`C$`、`IPC$` 常见父子关系类似:
services.exe
  └── cmd.exe /c ...
  └── powershell.exe ...
  └── rundll32.exe ...
可以在目标机上先查服务安装事件:
Get-WinEvent -FilterHashtable @{
  LogName='System'
  Id=7045
  StartTime=(Get-Date).AddHours(-6)
} | Select-Object TimeCreated,
    @{n='ServiceName';e={$_.Properties[0].Value}},
    @{n='ImagePath';e={$_.Properties[1].Value}},
    @{n='ServiceType';e={$_.Properties[2].Value}},
    @{n='Account';e={$_.Properties[4].Value}} |
  Format-List
如果 `ImagePath` 指向 `ADMIN$`、`Temp`、随机文件名,或者是 `cmd /c`、`powershell -enc`,基本就要继续往前追源主机。

2. 用 5145 反推 SMB 写入来源

很多横向移动会先通过 SMB 写文件,再远程创建服务。目标机的安全日志里可以看 `5145`,重点字段: - `ShareName` - `RelativeTargetName` - `AccessMask` - `SubjectUserName` - `IpAddress` 示例过滤 `ADMIN$`、`C$` 相关访问:
Get-WinEvent -FilterHashtable @{
  LogName='Security'
  Id=5145
  StartTime=(Get-Date).AddHours(-6)
} | Where-Object {
  $_.Message -match 'ADMIN\$|C\$|IPC\$'
} | Select-Object TimeCreated, Message |
  Format-List
这里如果看到某账号从 A 机器访问 B 机器的 `ADMIN$`,并且紧接着 B 机器出现 7045,那 A 机器比单纯的登录源更值得优先排查。

3. WinRM / PowerShell 远程执行要看专门日志

如果没有 7045,但存在远程命令痕迹,建议看 WinRM 和 PowerShell 日志: 目标机:
Get-WinEvent -LogName 'Microsoft-Windows-WinRM/Operational' |
  Where-Object {$_.TimeCreated -gt (Get-Date).AddHours(-6)} |
  Select-Object TimeCreated, Id, ProviderName, Message |
  Format-List
PowerShell:
Get-WinEvent -LogName 'Microsoft-Windows-PowerShell/Operational' |
  Where-Object {$_.TimeCreated -gt (Get-Date).AddHours(-6)} |
  Select-Object TimeCreated, Id, Message |
  Format-List
重点关注: - `4103`:模块日志 - `4104`:脚本块日志 - `400/403/600`:PowerShell 启停和 Provider 加载 如果看到 `Invoke-Command`、`Enter-PSSession`、`New-PSSession`、`EncodedCommand`,基本能确认是 PowerShell 远程路径。

4. 域控上确认“账号是否被滥用”

权限边界不要只在单机上看,要回到域控确认这个账号到底拿到了哪些票据、访问了哪些服务。 域控上查 4769,重点看: - `Account Name` - `Service Name` - `Client Address` - `Ticket Encryption Type` 比如查某账号的服务票据申请:
Get-WinEvent -FilterHashtable @{
  LogName='Security'
  Id=4769
  StartTime=(Get-Date).AddHours(-6)
} | Where-Object {
  $_.Message -match '目标账号名'
} | Select-Object TimeCreated, Message |
  Format-List
如果同一账号短时间内从异常主机申请了大量 `cifs/hostname`、`host/hostname`、`wsman/hostname`,说明它很可能被用于横向访问。 另外,`4672` 只能说明登录时拿到了特权,不代表一定越权。要结合这个账号本来是否属于: - Domain Admins - Enterprise Admins - Administrators - Remote Management Users - Backup Operators - Account Operators - 本地管理员组 检查某台目标机本地管理员组:
Get-LocalGroupMember -Group Administrators
域内批量可以用 GPO、EDR 或远程执行查,但注意别在事件现场制造更多噪音。

5. 区分“测试行为”还是“真实风险”

授权测试场景里,建议让测试方补齐这几个信息,不是为了甩锅,而是为了缩小时间线: - 测试源 IP、跳板 IP、代理 IP - 使用过的测试账号 - 使用过的协议:SMB / WMI / WinRM / RDP / LDAP / Kerberos - 是否执行过远程服务创建、文件投递、凭据验证 - 是否有自动化工具,工具的并发和时间窗口 如果测试方给出的源地址和日志里的源地址不一致,不要马上判断为异常,先确认有没有代理、VPN、云桌面、跳板机或 SOCKS 转发。

6. 修复建议要按边界收敛

确认后建议不要只删一个临时文件,至少做这些收敛:
  • 重置被使用账号密码,优先处理有本地管理员、域管、服务账号权限的账号。
  • 检查该账号是否存在不必要的本地管理员权限。
  • 取消普通域用户对服务器的 RDP / WinRM / SMB 管理权限。
  • 限制 ADMIN$、C$ 的远程管理访问来源,只允许管理网段或堡垒机。
  • 对高权限账号启用分层管理,不要在普通终端登录域管账号。
  • 服务账号改为 gMSA 或最小权限,不要长期使用域管跑服务。
  • 打开 PowerShell Script Block Logging、Module Logging、Process Creation 命令行审计。
  • 开启并保留 Sysmon,重点收集进程、网络连接、文件创建、服务创建。
如果最后确认是测试导致的,也建议输出一份边界说明:哪个账号、从哪台机器、通过什么协议、访问了哪些主机、获得了什么权限。这样后面修复时能直接对应到权限收敛,而不是笼统写“存在横向移动风险”。

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

最近浏览 0

  • 没有会员查看此页面。