跳转到帖子

授权内网测试中如何验证 Windows 服务目录权限是否可导致越权?

精选回复

发布于

问题背景

在一次已授权的 Windows 内网渗透测试中,当前仅获得普通域用户或本地低权限会话。枚举服务时发现某个服务以 LocalSystem 启动,但仅凭“高权限服务”不能直接判定存在提权漏洞。真正需要确认的是:低权限主体能否修改服务配置、可执行文件、其父目录,或者可执行文件加载的依赖。

本文采用非破坏性验证:只检查权限并创建测试标记文件,不替换服务程序、不重启业务服务,也不投放可执行载荷。

问题定位

建议先回答以下几个问题:

  • 服务实际运行身份是什么,是否为 LocalSystem、LocalService 或高权限域账号?
  • 服务配置的修改权限是否错误授予普通用户?
  • ImagePath 指向的程序或其父目录是否允许 Users、Authenticated Users、Everyone 写入?
  • 路径包含空格时是否正确使用引号?
  • 可写目录是否真的位于服务加载链路中,而不是无关的日志或缓存目录?

风险成立通常需要同时具备“高权限执行上下文”和“低权限用户可影响执行内容”两项条件。只发现其中一项,应记录为待确认项,不能直接报告为可提权。

第一步:确认当前权限边界

whoami
whoami /groups
whoami /priv
whoami /user

:: 查看本机管理员组,但不要仅凭组名判断令牌是否已提升
net localgroup Administrators

重点记录当前用户 SID、所属组以及令牌中的特权状态。域环境中还要注意嵌套组关系;权限检查结果应以当前访问令牌为准,而不是仅看账号所属 OU 或显示名称。

第二步:枚举服务账号与启动路径

Get-CimInstance Win32_Service |
  Select-Object Name,StartName,State,StartMode,PathName |
  Sort-Object StartName,Name

# 针对可疑服务复核配置
sc.exe qc "ExampleService"
reg.exe query "HKLM\SYSTEM\CurrentControlSet\Services\ExampleService" /v ImagePath

Win32_Service.PathName 可能包含参数,不能直接将整段字符串当作文件路径。还应检查注册表中的原始 ImagePath,确认引号位置、环境变量和参数边界。

第三步:检查服务对象与文件系统权限

服务对象权限和文件权限是两套独立边界。即使二进制文件不可写,普通用户若拥有 SERVICE_CHANGE_CONFIG 等权限,也可能修改启动配置。反过来,服务配置不可改,但可执行文件或目录可写,同样存在风险。

:: 查看服务对象安全描述符
sc.exe sdshow "ExampleService"

:: 查看程序及父目录 ACL
icacls "C:\Program Files\Example\service.exe"
icacls "C:\Program Files\Example"

:: PowerShell 查看继承来源和具体权限
Get-Acl "C:\Program Files\Example\service.exe" |
  Format-List Owner,AccessToString
Get-Acl "C:\Program Files\Example" |
  Select-Object -ExpandProperty Access |
  Format-Table IdentityReference,FileSystemRights,AccessControlType,IsInherited

需要重点关注 Users、Authenticated Users、Everyone 以及业务自定义普通用户组。高风险权限包括 Write、Modify、FullControl、WriteData、CreateFiles、Delete,以及目录上的可继承写权限。仅有 ReadAndExecute 通常不足以影响服务程序。

解析 sc.exe sdshow 输出时,不要只搜索用户名称。ACE 可能以 SID 或组 SID 表示,还要结合 whoami /groups 判断当前令牌是否命中对应 ACE。服务对象中若向低权限主体授予 RP、WP、DC、WD 或过宽的通用权限,应进一步人工解释其具体含义。

第四步:用非破坏方式验证目录是否真实可写

ACL 看起来可写时,应使用当前低权限会话创建并删除普通文本标记文件。不要替换 service.exe,也不要借测试触发服务重启。

$dir = 'C:\Program Files\Example'
$marker = Join-Path $dir ('.perm_test_' + [guid]::NewGuid().ToString('N') + '.txt')

try {
    'authorized permission validation' | Set-Content -LiteralPath $marker -Encoding ASCII -ErrorAction Stop
    Get-Item -LiteralPath $marker | Select-Object FullName,Length,CreationTimeUtc
    Remove-Item -LiteralPath $marker -Force -ErrorAction Stop
    'RESULT: directory is writable by the current token'
}
catch {
    'RESULT: write validation failed: ' + $_.Exception.Message
}

如果文件创建成功,可证明当前令牌对该目录具有实际写入能力,但还不能单独证明可提权。下一步应确认该目录内的文件是否会被高权限服务加载,并结合变更窗口、服务恢复策略和业务影响决定是否需要进一步验证。多数生产环境到此即可形成可靠证据链。

第五步:排查未加引号路径

当 ImagePath 类似 C:\Program Files\Vendor App\service.exe -k run 且可执行路径未被双引号包裹时,Windows 的路径解析可能尝试多个候选位置。但是否可利用仍取决于候选目录是否允许当前用户创建对应文件。

# 仅筛选疑似未加引号且包含空格的服务路径
Get-CimInstance Win32_Service |
  Where-Object {
    $_.PathName -match '\s' -and
    $_.PathName -notmatch '^\s*"' -and
    $_.PathName -match '\.exe'
  } |
  Select-Object Name,StartName,PathName

注意:筛选结果存在误报。系统组件、环境变量、特殊参数格式都可能影响解析。报告中必须同时提供原始 ImagePath、候选路径 ACL 和当前用户写入验证结果,不能只依据扫描器标签定级。

证据与日志留痕

授权测试应保留命令时间、执行账号、目标主机、服务名称、原始 ACL 和测试文件路径。常见审计点包括:

  • 安全日志 4688:进程创建,需要启用相应审核策略。
  • 系统日志 7036:服务状态变化。
  • 系统日志 7045:新服务安装。
  • 安全日志 4697:服务安装审核。
  • Sysmon 1:进程创建。
  • Sysmon 11:文件创建,可用于定位权限验证标记文件。
  • Sysmon 13:注册表值修改,可覆盖服务 ImagePath 变更。

本验证流程不需要安装服务,也不需要修改 ImagePath。如果出现 7045、4697 或服务注册表变更记录,说明测试动作已经超出单纯权限验证,应立即复核授权范围。

如何形成有效结论

  • 高风险:服务以 LocalSystem 或等价高权限身份运行,当前低权限令牌可修改服务配置,或可修改其实际加载的可执行文件。
  • 中风险:高权限服务目录可写,但尚未证明可写文件会进入加载链路;需要结合 DLL 搜索、配置文件解析方式进一步确认。
  • 低风险或误报:只存在未加引号路径,但所有候选位置均不可写;或可写目录与服务加载无关。

报告证据至少应包含 sc.exe qc 输出、ImagePath 原始值、服务运行账号、icacls 或 Get-Acl 结果、当前用户 SID,以及非破坏性写入测试结果。

修复建议

  • 将服务程序部署到受保护目录,普通用户仅保留读取和执行权限。
  • 删除 Users、Authenticated Users、Everyone 对服务目录不必要的 Modify、Write 和 FullControl 权限。
  • 服务对象 ACL 只向受控管理员组授予配置修改权限。
  • 为包含空格的 ImagePath 正确添加引号,并在变更后复核服务参数是否保持不变。
  • 避免使用高权限域账号运行普通业务服务;优先采用专用低权限服务账号或 gMSA。
  • 对服务目录启用文件完整性监控,对 ImagePath 和服务安全描述符建立基线。
:: 以下命令仅为修复示例,执行前应导出 ACL 并在测试环境验证
icacls "C:\Program Files\Example" /inheritance:r
icacls "C:\Program Files\Example" /grant:r "SYSTEM:(OI)(CI)F" "Administrators:(OI)(CI)F" "Users:(OI)(CI)RX"

:: 修复后重新核验
icacls "C:\Program Files\Example"
sc.exe qc "ExampleService"

不建议在不了解继承关系时直接照搬 ACL。目录中若还包含需要由服务账号写入的日志或数据,应拆分到独立数据目录,并只给服务账号授予最小写权限,避免为了业务写入重新放宽整个程序目录。

总结

Windows 服务权限问题的判断核心不是“发现 LocalSystem 服务”,而是证明低权限令牌能够影响高权限服务的执行内容。按当前令牌、服务对象权限、文件 ACL、加载链路、非破坏性验证和日志证据逐层确认,既能减少扫描器误报,也能避免在授权测试中因替换程序或重启服务造成不必要的业务影响。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意
红队攻防路径编排示意图
侦察、入口、横向移动与权限路径梳理示意

这类问题建议拆成三个条件验证:低权限用户确实能修改加载内容、服务以高权限运行、存在可触发的重新加载路径。只看到目录有写权限,还不能直接判定可越权。

先确认服务实际配置,注意 PathName 里可能包含参数、环境变量或 svchost.exe:

sc.exe qc 服务名
sc.exe sdshow 服务名

powershell -NoProfile -Command ^
  "Get-CimInstance Win32_Service -Filter ""Name='服务名'"" |
   Select-Object Name,StartName,State,StartMode,PathName"

重点看 StartName 是否为 LocalSystem、LocalService、NetworkService 或其他高权限账号。若是 svchost.exe 托管服务,还应继续查对应的 ServiceDll,不能把系统目录中的 svchost 当成目标文件:

reg query "HKLM\SYSTEM\CurrentControlSet\Services\服务名" /s

然后用待验证的低权限账号执行 ACL 检查,不要只以管理员视角查看:

icacls "C:\Program Files\Vendor\App"
icacls "C:\Program Files\Vendor\App\service.exe"

whoami /user
whoami /groups

accesschk.exe -nobanner -uwd "C:\Program Files\Vendor\App"
accesschk.exe -nobanner -uvw "C:\Program Files\Vendor\App\service.exe"
accesschk.exe -nobanner -ucqv 服务名

目录权限里需要关注的不只是 F/M/W,还包括“创建文件”“删除子项”和继承关系。常见误判是目录可创建新文件,但现有服务程序本身不可修改,也不能删除或重命名,此时未必能替换它。反过来,父目录具有 DELETE_CHILD 时,即使文件 ACL 看起来较严,也可能仍可完成替换。建议用有效权限页或 AccessChk 结合实际低权限令牌确认。

生产环境不建议直接覆盖服务程序。可以先做无破坏验证:

echo acl-canary>"C:\Program Files\Vendor\App\acl-test-%USERNAME%.txt"
ren "C:\Program Files\Vendor\App\acl-test-%USERNAME%.txt" acl-test-renamed.txt
del "C:\Program Files\Vendor\App\acl-test-renamed.txt"

上述测试只能证明目录具备创建、重命名或删除能力,不能单独证明可劫持服务。还要分别确认:

  • 服务实际加载的 EXE、DLL、脚本或配置文件是否位于该目录;
  • 目标文件能否被低权限账号修改、删除或替换;
  • 服务是否会以高权限重新加载该内容;
  • 低权限账号能否停止、启动服务,或是否存在计划任务、故障恢复、系统重启等可预期触发点。

服务控制权限可用下面的命令辅助判断,重点关注非管理员主体是否拥有 SERVICE_STOP、SERVICE_START、SERVICE_CHANGE_CONFIG:

accesschk.exe -nobanner -ucqv 服务名
sc.exe qfailure 服务名

若只能在重启后触发,也应记录为“潜在本地提权条件”,但风险描述中要明确普通用户当前无法自主触发,避免把可利用性写高。

最终证据链建议保留:服务配置、运行账号、目录与目标文件 ACL、低权限令牌信息、实际创建/重命名测试结果、服务控制权限和触发条件。若必须做完整 PoC,最好在克隆环境或维护窗口内使用经过审批的无害程序,仅写入指定事件日志或测试文件,测试前备份原文件及 ACL,结束后校验哈希并恢复。

修复时不要只给目标 EXE 加拒绝项,优先从父目录移除普通用户或业务用户组的写入、修改、删除子项权限,并检查继承:

icacls "C:\Program Files\Vendor\App" /inheritance:r
icacls "C:\Program Files\Vendor\App" /grant:r ^
  "SYSTEM:(OI)(CI)F" ^
  "Administrators:(OI)(CI)F" ^
  "Users:(OI)(CI)RX"

实际执行前应先导出 ACL,并根据服务更新机制保留安装器或专用服务账号所需权限,避免直接套用导致升级失败。

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

最近浏览 0

  • 没有会员查看此页面。