跳转到帖子

授权内网测试中如何验证 Windows 服务弱权限,并区分误报与真实提权风险?

精选回复

发布于

问题背景

在一次已授权的 Windows 内网渗透测试中,低权限账号发现某个第三方服务以 LocalSystem 身份运行。扫描器同时报告“服务目录可写”和“未引用服务路径”,但客户要求不得替换程序、不得重启生产服务。此时应如何完成无破坏验证,并判断它究竟是误报、条件性风险,还是真实的本地提权路径?

验证目标不是取得 SYSTEM 会话,而是证明低权限主体是否能够控制高权限服务下一次启动时加载的可执行文件、参数或 DLL。以下操作应在明确授权范围内进行,不修改服务配置、不覆盖文件,也不触发服务重启。

问题定位

先固定测试身份、主机和服务对象。不要仅凭扫描器的“目录可写”结论定级,因为服务提权通常要求多个条件同时成立。

检查项需要确认的事实常见误判
运行身份服务是否使用 LocalSystem、LocalService 或高权限域账号服务实际使用普通受限账号
服务控制权限低权限用户能否修改 binPath、启动账号或服务 DACL只能查询或启动服务,不能改配置
文件系统权限是否能写入实际 EXE、其父目录或 DLL 搜索目录只对日志、缓存子目录可写
路径解析未加引号路径是否存在可被创建的候选文件候选目录不可写,或路径本身已正确引用
触发条件攻击者是否有权重启服务,或服务是否会随系统启动无法触发且系统无计划重启

技术分析

需要把三类问题分开验证。

  • 服务对象权限:服务控制管理器中的服务对象有独立 DACL。关键权限包括 SERVICE_CHANGE_CONFIG、WRITE_DAC 和 WRITE_OWNER。拥有其中任一高危权限,可能绕过文件系统限制。

  • 二进制及目录权限:应检查服务实际加载的可执行文件,而不是只检查展示名称。对目录具有 CreateFiles 或 Modify 权限,通常比仅有 ReadAndExecute 更危险。

  • 路径与加载行为:未引用路径只有在 Windows 路径解析产生的候选位置可由低权限用户创建文件时才可利用。服务目录可写也不必然等于可控主程序,还要继续检查 DLL、配置文件和插件目录。

操作步骤

以下示例服务名为 VendorAgent。先使用当前低权限测试账号执行身份确认和只读查询。

whoami /all
sc.exe qc VendorAgent
sc.exe qfailure VendorAgent
sc.exe queryex VendorAgent
reg.exe query "HKLM\SYSTEM\CurrentControlSet\Services\VendorAgent" /v ImagePath

重点记录 SERVICE_START_NAME、BINARY_PATH_NAME、START_TYPE 和失败恢复动作。ImagePath 同时从 sc.exe 与注册表读取,是为了识别环境变量、参数以及扫描器解析差异。不要执行 sc config、reg add 或服务重启命令。

随后检查服务对象安全描述符。sc.exe sdshow 返回 SDDL,其中 RP、WP、DC 等权限必须结合服务对象 ACE 解释;不要看到某个 WD 就直接判为完全可写。

sc.exe sdshow VendorAgent

:: 如果测试环境允许使用 Sysinternals AccessChk,可直接查看当前用户权限
accesschk.exe -nobanner -accepteula -c -v VendorAgent

:: 枚举当前用户可修改配置的服务,结果仍需逐项人工复核
accesschk.exe -nobanner -accepteula -uwcqv "%USERNAME%" *

接着提取可执行文件路径并检查逐级 ACL。假设配置为 C:\Program Files\Vendor Agent\agent.exe -service:

icacls "C:\Program Files\Vendor Agent\agent.exe"
icacls "C:\Program Files\Vendor Agent"
icacls "C:\Program Files"

:: 查看是否存在显式拒绝、继承或所有者异常
powershell.exe -NoProfile -Command "$p='C:\Program Files\Vendor Agent\agent.exe'; Get-Acl -LiteralPath $p | Format-List Owner,AccessToString,Sddl"

:: 仅做访问检查,不创建或覆盖文件
powershell.exe -NoProfile -Command "$p='C:\Program Files\Vendor Agent\agent.exe'; $a=Get-Acl -LiteralPath $p; $a.Access | Format-Table IdentityReference,FileSystemRights,AccessControlType,IsInherited -Auto"

ACL 判断时不能只看 Users 是否出现。需要区分 Write、Modify、FullControl、CreateFiles、CreateDirectories 与 WriteAttributes。WriteAttributes 一般不能直接替换程序;目录上的 CreateFiles 则可能允许创建未引用路径候选文件或投放缺失 DLL。

如何验证未引用服务路径

若 BINARY_PATH_NAME 为 C:\Program Files\Vendor Agent\agent.exe -service 且没有双引号,Windows 可能依次尝试类似 C:\Program.exe、C:\Program Files\Vendor.exe,最后才是完整路径。验证时只检查候选位置的存在性和父目录 ACL,不要创建 Program.exe 或 Vendor.exe。

powershell.exe -NoProfile -Command "$c=@('C:\Program.exe','C:\Program Files\Vendor.exe'); foreach($p in $c){$parent=Split-Path $p; [pscustomobject]@{Candidate=$p; Exists=Test-Path -LiteralPath $p; Parent=$parent}; icacls $parent}"

:: 确认原始命令行,避免把带参数的路径截断后误判
wmic.exe service where "Name='VendorAgent'" get Name,StartName,PathName,StartMode /format:list

如果所有候选父目录均不可由普通用户写入,未引用路径通常只能记为配置缺陷或低风险加固项。若候选目录可写,还应确认服务会由高权限身份启动,以及低权限用户是否具备重启服务的权限;没有可控触发条件时,应在报告中明确依赖系统或管理员后续重启。

非破坏性验证标准

满足下列证据链即可证明风险,不需要真正执行载荷:

  • 服务以 LocalSystem 或等效高权限账号运行。

  • 低权限测试主体对服务对象具有 SERVICE_CHANGE_CONFIG,或对实际加载文件、候选文件父目录具有可利用的写权限。

  • 通过 sc.exe、icacls、AccessChk 和 SDDL 留存可复核输出。

  • 存在可说明的触发方式,例如用户能够启动或重启服务,或服务在系统启动时自动运行。

  • 排除了显式 Deny、仅写日志目录、受保护安装器所有权以及 EDR 阻断等反证。

在隔离测试机确需做动态复现时,应先取得单独批准,并使用无网络、无持久化的标记程序,例如仅向指定测试目录写入时间戳和当前身份。生产环境不建议通过替换 EXE、投放 DLL 或修改 binPath 来“证明”漏洞。

日志留痕与排查

防守侧可从服务配置变更、进程创建和文件变更三个方向核验。Windows System 日志中的 7045 常用于发现新服务安装;Security 日志中的 4697 取决于审核策略。服务配置被修改时,还应结合 System 日志、EDR 遥测和注册表审计判断。

wevtutil.exe qe System /q:"*[System[(EventID=7045 or EventID=7036 or EventID=7040)]]" /f:text /c:30
wevtutil.exe qe Security /q:"*[System[(EventID=4697 or EventID=4688)]]" /f:text /c:30

:: 检查服务注册表项最近写入时间
powershell.exe -NoProfile -Command "Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Services\VendorAgent' | Select-Object Name,LastWriteTime"

7040 主要反映启动类型变化,不等同于所有服务配置修改;4688 只有在启用进程创建审核后才会出现,命令行字段还依赖“在进程创建事件中包括命令行”策略。若要监控服务 ImagePath,应为对应注册表键配置对象访问审核,或使用 EDR、Sysmon 的注册表事件能力。

风险分级建议

  • 高风险:普通用户可修改高权限服务 binPath,且可自行重启服务。

  • 高风险:普通用户可覆盖服务主程序或关键 DLL,服务会自动或可控启动。

  • 中风险:写入条件成立,但只能等待管理员或系统重启触发。

  • 低风险或加固项:路径未引用,但所有候选位置均不可写。

  • 误报:可写位置仅为日志、临时数据目录,且无法影响服务加载链路。

修复建议

  • 将包含空格的服务可执行文件路径用双引号完整包裹,参数置于结束引号之后。

  • 移除 Users、Authenticated Users 或业务普通账号对服务目录的 Modify、Write 和 CreateFiles 权限,仅保留读取与执行。

  • 收紧服务对象 DACL,避免非管理员主体获得 SERVICE_CHANGE_CONFIG、WRITE_DAC 或 WRITE_OWNER。

  • 把日志、缓存和更新包放到独立数据目录,不要让服务程序目录承担运行时写入需求。

  • 服务确需自更新时,使用独立更新服务、签名校验和受限 IPC,不要直接授予普通用户对安装目录的修改权。

  • 修复后使用原低权限账号复测 sc.exe sdshow、AccessChk 和 icacls,并确认业务服务能够正常启动。

总结

这类问题的关键是建立“高权限服务身份、低权限可控对象、可触发加载行为”三段式证据链。扫描器发现未引用路径或可写目录只能作为线索,最终结论必须落到具体 ACE、具体文件路径和具体触发条件。授权测试中优先采用只读命令完成验证,既能给出可复核证据,也能避免为了证明提权而引入生产中断。

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

这类告警建议拆成“服务对象权限、配置引用路径权限、触发条件”三部分验证。扫描器只看到某个 ACL 可写就报高危,实际不一定能形成提权链。

1. 先确认服务身份和启动配置

sc.exe qc "ServiceName"
sc.exe queryex "ServiceName"
reg.exe query "HKLM\SYSTEM\CurrentControlSet\Services\ServiceName" /s

重点记录 SERVICE_START_NAME、START_TYPE、BINARY_PATH_NAME。只有服务运行在 LocalSystem、LocalService、NetworkService 或其他高权限账号下时,弱权限才可能构成本地提权;普通低权限服务账号通常只能算配置缺陷。

2. 区分“能读到配置”和“能修改服务对象”

sc.exe sdshow "ServiceName"

检查当前低权限主体是否拥有以下关键权限:

  • DC:修改服务配置(对应 SERVICE_CHANGE_CONFIG);
  • WD/WO:改 DACL 或所有者,通常可进一步取得控制权;
  • RP/WP:启动、停止服务,本身不等于可提权,但会影响可利用性;

如果环境允许使用 Sysinternals,可直接按测试账号过滤有效权限:

accesschk.exe -accepteula -uwcqv DOMAIN\TestUser "ServiceName"
accesschk.exe -accepteula -uwcqv "BUILTIN\Users" *

注意不要只看 SDDL 中出现了 BU 或 AU,还要看 ACE 类型、继承关系及实际授予的权限位。拒绝 ACE、受限令牌和组成员关系都可能使扫描结果失真。

3. 检查二进制、脚本及其父目录是否真正可写

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

如果 ImagePath 指向批处理、PowerShell 脚本、DLL 或配置文件,也要逐个检查。文件本身只读并不足以排除风险:父目录具有 (M)、(W)、(F),可能允许删除后重建或替换同名文件。反过来,只有 (RX)、创建子目录权限,或者写权限仅授予服务自身 SID,通常不能直接认定为可利用。

可在测试账号上下文中做无破坏验证,创建临时文件后立即删除,不要替换真实程序:

whoami /all
echo acl-test>"C:\Program Files\Vendor\App\.__acl_test"
del "C:\Program Files\Vendor\App\.__acl_test"

4. 未加引号路径要验证“候选文件可创建”,不能只看路径中有空格

例如:

C:\Program Files\Vendor App\service.exe -k run

需结合 Windows 的路径解析,检查对应候选位置及其父目录 ACL。若普通用户无法在候选位置创建文件,或者 ImagePath 已正确加引号,则不能仅凭“路径含空格”定为真实风险。

reg.exe query "HKLM\SYSTEM\CurrentControlSet\Services\ServiceName" /v ImagePath
icacls "C:\"
icacls "C:\Program Files"
icacls "C:\Program Files\Vendor App"

5. 最后确认是否存在可控触发条件

  • 测试账号能否停止、启动或重启该服务;
  • 服务是否会在系统启动时自动运行;
  • 修改后是否必须依赖管理员重启主机;
  • 服务当前是否处于禁用状态,或因依赖项、签名校验、应用控制策略而无法加载修改内容;
  • EDR、WDAC、AppLocker 是否会阻止目标路径中的文件执行。
sc.exe query "ServiceName"
sc.exe enumdepend "ServiceName"
sc.exe qc "ServiceName"

实际报告中可以按下面标准归类:

  • 真实高风险:低权限用户可修改高权限服务的启动配置,且可自行触发服务重启;或可替换其可执行内容并触发加载。
  • 条件性风险:可修改配置或文件,但只能等待管理员/系统重启;应写清前置条件,通常不宜描述为“立即提权”。
  • 误报或低风险:仅目录可读、仅能启动服务、路径虽未加引号但候选位置不可写、服务使用低权限账号,或 ACL 只对不相关主体开放。

验证阶段建议保留 sc qc、sc sdshow、icacls、whoami /all 的原始输出,并使用临时文件证明“有效写入”,不要通过替换服务程序来证明问题。这样既能区分扫描器误报,也能把权限、执行身份和触发方式组成完整证据链。

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

最近浏览 0

  • 没有会员查看此页面。