跳转到帖子

授权内网测试中如何验证 Windows 服务账号的权限边界并保留审计证据

精选回复

发布于

问题背景

在一次已授权的内网渗透测试中,发现某台 Windows Server 上的 IIS 应用池账号同时具备本地管理员权限,主机还开放了 WinRM。此时应如何确认这是可利用的权限边界问题,而不是仅凭组成员关系下结论?验证过程中又该如何避免获取真实凭据、修改服务或影响业务,并为后续复测保留证据?

以下操作默认已取得主机检查和日志读取授权。涉及远程登录、服务重启、创建计划任务等动作,应单独确认测试窗口。生产环境不建议通过替换服务文件或执行横向移动来证明风险。

问题定位

这类问题通常需要拆成四个条件验证:

  • 账号当前实际获得了哪些令牌权限,是否只是配置残留。
  • 账号是否存在可用的登录路径,例如 WinRM、RDP、服务登录或批处理登录。
  • 其权限是否能够影响高权限服务、计划任务、敏感目录或安全配置。
  • 系统是否记录了登录、进程创建和权限变更,证据能否关联到测试时间与账号。

只有“账号属于 Administrators 组”并不足以完整说明攻击链。还应确认登录权、UAC 远程限制、服务文件 ACL、远程管理监听范围及审计策略。

第一步:确认账号和访问令牌

在目标账号已有合法会话的前提下,先采集身份、组和特权信息,不要急于执行高权限操作:

whoami
whoami /groups
whoami /priv
whoami /all

net localgroup Administrators
Get-LocalGroupMember -Group 'Administrators' | Format-Table Name,ObjectClass,PrincipalSource

重点观察以下内容:

  • 是否直接或间接属于本地 Administrators。
  • 管理员组 SID 的状态是 Enabled,还是被 UAC 过滤后的 deny-only。
  • 是否出现 SeImpersonatePrivilege、SeDebugPrivilege、SeBackupPrivilege 等高影响特权。
  • 账号是本地账号、域账号、托管服务账号,还是虚拟应用池身份。

如果测试账号是本地管理员,从网络进行远程管理时还要检查 UAC 远程令牌过滤。不要为了验证而直接修改该配置:

reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy

该值不存在或为 0 时,本地管理员通过部分网络登录方式获得的令牌可能被过滤;域账号和内置 Administrator 的行为可能不同。报告中应记录实际账号类型,避免把“组成员关系”误写成“已获得完整远程管理员令牌”。

第二步:检查远程登录路径

确认 WinRM 是否真的可达、使用何种认证方式以及监听在哪些地址。仅查看配置,不建立到其他主机的会话:

Get-Service WinRM
Get-NetTCPConnection -State Listen -LocalPort 5985,5986 -ErrorAction SilentlyContinue
winrm enumerate winrm/config/listener
winrm get winrm/config/service
Get-PSSessionConfiguration | Select-Object Name,Permission

# 查看防火墙规则及生效范围
Get-NetFirewallRule -DisplayGroup 'Windows Remote Management' |
  Get-NetFirewallAddressFilter |
  Format-Table Name,RemoteAddress

需要关注:

  • 5985 是否使用 HTTP,5986 是否配置有效的 HTTPS 证书。
  • 防火墙 RemoteAddress 是否为 Any,而不是管理网段或堡垒机地址。
  • Basic 或 AllowUnencrypted 是否被启用。
  • PowerShell 会话配置的权限描述符是否允许非预期账号访问。
  • 账号是否被拒绝“从网络访问此计算机”,或仅被授予服务登录权。

可读取本地安全策略进行交叉检查:

secedit /export /cfg C:\Windows\Temp\local-policy-review.inf /quiet
findstr /i "SeNetworkLogonRight SeDenyNetworkLogonRight SeRemoteInteractiveLogonRight SeServiceLogonRight" C:\Windows\Temp\local-policy-review.inf

导出文件包含安全策略信息,取证完成后应按测试约定删除。域环境下本地策略可能被 GPO 覆盖,可用以下命令确认最终应用来源:

gpresult /scope computer /h C:\Windows\Temp\gp-computer.html
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\WinRM /s

第三步:验证是否能够影响高权限服务

服务账号成为本地管理员后,通常已经构成明显的权限边界失效。但报告最好补充一个无破坏性的影响面验证,例如检查高权限服务的可执行文件及目录是否可写。不要替换二进制文件,也不要重启生产服务。

Get-CimInstance Win32_Service |
  Where-Object {$_.StartName -match 'LocalSystem|LocalService|NetworkService'} |
  Select-Object Name,StartName,State,PathName

# 针对选定服务检查配置和文件 ACL
sc.exe qc ExampleService
icacls "C:\Program Files\Example\service.exe"
icacls "C:\Program Files\Example"

# 检查服务对象的安全描述符
sc.exe sdshow ExampleService

分析时应区分三种权限:

  • 文件写权限:可修改服务可执行文件、DLL 或配置文件。
  • 目录写权限:即使现有文件不可写,也可能通过删除、重建或 DLL 搜索路径影响服务。
  • 服务控制权限:SERVICE_CHANGE_CONFIG、SERVICE_START、WRITE_DAC 等权限可能允许改变服务行为。

仅凭 icacls 输出中的 Users、Authenticated Users 或某个业务组拥有 M、F、W 权限,就可以形成可复核证据。若必须证明账号具备实际写入能力,应在变更许可范围内创建普通标记文件,且不要使用服务二进制名称:

$marker = 'C:\Program Files\Example\pentest_write_check.txt'
'authorized validation - no executable content' | Set-Content $marker
Get-Item $marker | Select-Object FullName,Length,CreationTimeUtc
Remove-Item $marker

如果目录承载生产程序,创建文件也可能触发监控或完整性校验,应事先获得明确许可。无法获得变更许可时,ACL 证据加服务运行身份通常已经足够。

第四步:核对日志留痕能力

先检查审计策略,而不是假设系统一定记录了行为:

auditpol /get /category:*
wevtutil gl Security
wevtutil gl Microsoft-Windows-PowerShell/Operational
wevtutil gl Microsoft-Windows-WinRM/Operational

# 查询最近的关键安全事件
$start = (Get-Date).AddHours(-2)
Get-WinEvent -FilterHashtable @{
  LogName='Security'
  Id=4624,4672,4688,4697
  StartTime=$start
} | Select-Object TimeCreated,Id,RecordId,Message

Get-WinEvent -FilterHashtable @{
  LogName='System'
  Id=7045
  StartTime=$start
} | Select-Object TimeCreated,Id,RecordId,Message

常见事件含义如下:

  • 4624:成功登录。网络登录通常关注 Logon Type 3,远程交互登录常见 Type 10。
  • 4672:新登录被分配敏感特权,可用于辅助判断管理员令牌。
  • 4688:进程创建,需要启用相应高级审核策略;命令行记录还依赖额外策略。
  • 4697 和 System 7045:服务安装。验证期间不应产生此类事件,若出现应立即核对。
  • PowerShell 4104:启用脚本块日志后可记录脚本内容。

日志证据至少应保存事件时间、EventRecordID、账号、源地址、Logon ID 和测试工单编号。不要只截取一段 Message 文本,因为不同语言系统的格式可能不同,且难以做关联分析。

建议的最小验证流程

  • 记录授权范围、测试账号、目标主机和统一时间基准。
  • 通过 whoami 和本地组成员确认令牌及组关系。
  • 读取 WinRM、登录权和防火墙配置,确认是否存在实际入口。
  • 选择一个高权限服务,检查服务身份、文件 ACL、目录 ACL 和服务对象权限。
  • 在许可范围内执行一次无害登录或标记文件测试,不获取凭据、不建立持久化。
  • 从 Security、System、PowerShell 和 WinRM 日志中回查对应记录。
  • 删除临时文件,记录未恢复项,并将命令输出与事件 RecordID 一并归档。

风险判断

可以按证据强度分级:

  • 仅发现账号在管理员组,但无可用登录路径,属于高风险错误配置,需结合账号使用方式说明限制条件。
  • 账号可通过 WinRM 或 RDP 登录并获得完整管理员令牌,说明权限边界已实际失效。
  • 账号还能修改 LocalSystem 服务文件、服务配置或安全策略,风险通常应评为高危。
  • 同时缺少 4688、PowerShell 或远程管理日志时,应单独记录为检测与追溯能力不足,而不是把它与权限问题合并成一个结论。

修复建议

  • 将 IIS 应用池账号移出本地 Administrators,只授予应用目录、证书私钥、注册表项或数据库所需的最小权限。
  • 优先使用虚拟账号或组托管服务账号,避免普通域用户作为长期服务身份。
  • 不需要 WinRM 时关闭服务及防火墙规则;需要时只允许管理网段或堡垒机访问,并优先使用 HTTPS、Kerberos 或证书认证。
  • 复核服务目录 ACL,移除 Users、Authenticated Users 和非必要业务组的写入、修改及更改权限。
  • 通过 GPO 管理登录权,避免业务服务账号获得远程交互登录权限。
  • 启用登录、特权使用和进程创建审核,并将日志转发到集中平台,防止主机失陷后本地日志被清除。

移除本地管理员权限前,应先确认应用的真实依赖。可以通过进程监控、失败审计和测试环境回归定位所需资源,再对单个目录或对象授权,不要用“重新加入管理员组”代替问题分析。

复测要点

复测不应只确认账号已从 Administrators 中删除,还要重新检查令牌、WinRM 会话权限、服务目录 ACL 和最终生效的 GPO。理想结果是:业务功能正常,账号无法远程交互登录,不能修改高权限服务资源,同时授权管理员的正常操作仍能产生完整审计记录。

总结

验证服务账号权限边界时,建议形成“身份与令牌、登录入口、可影响对象、日志证据”四段式证据链。这样既能说明风险是否真实可达,也能控制测试动作,避免通过替换服务、抓取凭据或横向移动来证明一个本可通过配置和审计数据确认的问题。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意
日志取证与事件时间线示意图
日志证据、时间线与事件还原示意

建议把验证拆成“服务实际令牌”和“资源访问路径”两部分,不要只看服务配置里显示的账号。重点确认服务进程是否获得了本不应有的组成员、特权或可写路径。

先记录服务配置、运行身份和进程 PID:

sc.exe qc <服务名>
sc.exe queryex <服务名>

Get-CimInstance Win32_Service -Filter "Name='服务名'" |
    Select-Object Name, StartName, State, ProcessId, PathName

Get-Process -Id <PID> -IncludeUserName |
    Select-Object Id, ProcessName, UserName, Path

在授权窗口内,建议让该服务执行一个只读的诊断动作,或临时启动一个经过审批的诊断实例,再从对应进程确认令牌,而不是用管理员 PowerShell 代替服务账号测试。可使用 Sysinternals PsExec 的日志方式启动一次非破坏性命令:

psexec.exe -accepteula -u "DOMAIN\svc_app" -p * -i cmd.exe /c ^
  "whoami /user & whoami /groups & whoami /priv & set"

如果账号是 LocalSystem、NetworkService 或 gMSA,应分别记录其实际 SID、组和特权;尤其关注 SeImpersonatePrivilege、SeAssignPrimaryTokenPrivilege、SeDebugPrivilege 等是否被授予。权限存在不等于一定可利用,但应与业务需求逐项核对。

资源边界建议覆盖以下几类:服务二进制及父目录、配置文件、日志目录、服务使用的计划任务或脚本、注册表配置项,以及服务可访问的共享目录。用只读方式导出 ACL,并检查服务账号是否具备不必要的写入、修改服务或修改目录继承权限:

$paths = @(
  'C:\Program Files\Vendor\App',
  'C:\ProgramData\Vendor\App',
  'C:\Windows\System32\某服务.exe'
)

foreach ($p in $paths) {
    "`n=== $p ==="
    icacls.exe $p
}

# 注册表服务配置权限
Get-Acl 'HKLM:\SYSTEM\CurrentControlSet\Services\某服务' |
    Format-List Owner,Access

如果允许使用 Sysinternals,可用 accesschk 聚焦服务账号的有效权限:

accesschk.exe -accepteula -uwcqv "DOMAIN\svc_app" "C:\ProgramData\Vendor\App"
accesschk.exe -accepteula -uwcqv "DOMAIN\svc_app" "HKLM\SYSTEM\CurrentControlSet\Services\某服务"

审计证据不要只截屏。建议开启或确认以下日志策略,并在测试前后记录时间、主机名、服务名、测试账号和变更单号:

  • 安全日志:4624(登录)、4634/4647(注销)、4672(特殊权限登录)、4688(进程创建)、4697(服务安装)。
  • 系统日志:Service Control Manager,常见事件 ID 为 7036(服务状态变化)和 7045(新服务安装)。
  • 对象访问审计:仅对目标目录或注册表项配置 SACL,避免全盘开启造成噪声;成功/失败访问分别记录。
# 导出指定时间窗口内的相关事件
$start = (Get-Date).AddMinutes(-15)
$end   = Get-Date

Get-WinEvent -FilterHashtable @{
    LogName   = 'Security'
    Id        = 4624,4634,4672,4688,4697
    StartTime = $start
    EndTime   = $end
} | Export-Clixml .\security-events.xml

Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    ProviderName = 'Service Control Manager'
    Id        = 7036,7045
    StartTime = $start
    EndTime   = $end
} | Export-Clixml .\scm-events.xml

证据目录中同时保存 sc qc、ACL 导出、进程 PID、事件日志原始导出和测试命令清单,并计算哈希:

Get-ChildItem .\evidence -File -Recurse |
    Get-FileHash -Algorithm SHA256 |
    Export-Csv .\evidence-sha256.csv -NoTypeInformation

最后应做一次回滚核对:停止诊断实例、撤销临时审计策略、删除测试文件、确认服务配置和 ACL 未改变。报告中把“账号能做什么”与“验证过程中实际做了什么”分开描述,这样既能证明权限边界,也能避免把测试动作误认为生产行为。

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

最近浏览 0

  • 没有会员查看此页面。