Windows 提权这四个字,做安全的人几乎都听过,但真要把链条讲明白,绕不开两个视角:攻击者怎么想、防守方怎么看。我这次只站在防守方这一侧写。原因很简单,我见过太多团队在授权演练里被打穿之后,第一反应是"我们补丁都打了啊",结果一翻日志才发现,对方根本没用上什么高深的漏洞,只拿到一个域内普通账号,靠本机一个配置有问题的服务,两分钟内就把权限抬到了系统级,留下的痕迹少得可怜。这类事不是个例,也不是什么高级技巧,纯粹是配置债。
这篇文章要解决三件事:Windows 主机上哪些位置容易让人把权限抬上去、在授权范围内怎么把这些点一个个翻出来、翻出来之后怎么堵、堵完之后靠什么日志证明真的堵住了。适合企业里的安全运维、系统管理员、做蓝队分析和内网应急的同学,也适合刚入行、想把权限提升这件事真正搞清楚的新人。阅读门槛不高,但得动手,排查和加固这两件事,光看是学不会的。
1. 先把位置摆正:权限提升在整个攻防链条里算什么
1.1 一次内部授权演练里看到的真实节奏
我参与过的几次内部演练里,节奏高度相似:拿到一个低权限账号,先做本机信息收集,然后提权,再横向或者建立控制通道。很多同学以为提权是终点,其实它是中间那段桥。桥搭好了,后面才有条件做更多事。
关键在于,攻击者主动做提权的动力,往往来自一个很现实的约束:初始拿到的凭据权限太低。低权限账号能做的事非常有限——读不到其他用户目录、改不了系统配置、装不了服务、连很多注册表键都写不进去。所以从低权限往高权限爬,是做后续动作的前置条件。理解了这一点,防守方向就清楚了:只要让低权限账号在本机"爬不上去",攻击链条就会在这里断掉,后面的横向和持久化也就无从谈起。
还有个容易被忽略的事实:提权动作本身通常很短,几秒到几分钟。但提权成功之后要维持访问,就得留下持久化动作,比如装服务、建计划任务、改注册表启动项。持久化动作的生命周期长得多,也更容易被日志和终端检测抓到。所以对防守方来说,提权环节的价值不只是"堵住",还在于"这是个高价值的告警点"。
1.2 攻击者真正盯上的是三类软柿子
把所有公开的权限提升路径归归类,本质就三类,摸清这三类,排查清单也就出来了。
第一类是配置类缺陷。服务、计划任务、注册表键、目录权限,只要这些对象的访问控制列表里出现了不该出现的低权限主体,就存在被利用的空间。这类问题最要命的地方在于:它不是漏洞,是配置,补丁打再多也修不掉。我见过一台打了最新累积更新的服务器,因为某个第三方软件在C:\ProgramData下建了个 Everyone 可写目录,整台机器的权限边界就形同虚设。
第二类是凭据类问题。本地管理员账号在多台机器上共用同一个密码、安装脚本里留了明文密码、浏览器和远程桌面客户端保存了凭据、服务账号密码长期不轮换。这类问题不需要任何技术手段就能扩大战果——拿到一台机器就等于拿到一批机器。
第三类是补丁和版本类。缺失的安全更新、长期无人维护的老组件、随软件一起装进来的旧版运行库。这一类是传统认知里的"提权漏洞",排查相对标准化,但也最容易被"反正打了补丁"这句话糊弄过去——很多团队只关心操作系统补丁,第三方组件的更新根本没人管。
1.3 提权之后的那一步,反而最容易暴露
从防守方的性价比看,提权成功之后的动作比提权本身更好抓。为什么?因为不管用什么方式提权成功,接下来总要做几件事:建立一条能持续通信的通道、在系统里留下一个能自动恢复的入口、想办法把凭据捞出来。
这三件事都会留下痕迹。持续通信意味着周期性的外连请求,流量侧能看到规律性的心跳;自动恢复入口意味着服务被安装、计划任务被创建、注册表 Run 键被写入;凭据捞取意味着对lsass进程的异常访问和内存读取操作。这些动作的时间跨度比提权长,产生的日志量也大得多。
我个人在实战分析里的经验是:把检测重心放在"提权后的 30 分钟内发生了什么",比死磕"他是怎么提权的"更容易出成果。因为提权手法可能很隐蔽,但后续的持久化动作很难做到完全无痕。
2. Windows 权限模型:内核到底按什么规则放行
2.1 访问令牌、SID 与完整性级别是怎么配合的
要判断一个操作会不会被拒绝,得看清楚 Windows 的判定逻辑。每个进程都挂着一个访问令牌,令牌里装着这个进程的身份信息:用户 SID、所属组的 SID 列表、持有的特权列表。当这个进程去访问某个对象时,内核会拿令牌里的身份去比对对象上的访问控制列表,逐条判定允许还是拒绝。
这里有个细节值得注意:令牌分主令牌和模拟令牌。服务进程可以用模拟令牌临时"借用"调用者的身份,这个机制本身是为了安全,但如果实现不当,反而会被当成提权通道。这也是为什么服务类问题排在第一优先级。
另一层是完整性级别。从低到高大致是低、中、高、系统四级。普通用户启动的进程跑在中等级别,以管理员身份运行的程序跑在高等级别。低完整性级别的进程即使拿到了高权限令牌,也无法写入高完整性级别的对象。这个机制能挡掉一部分越权写入,但它不是万能的——很多系统目录的权限设置并不完全依赖完整性级别。
理解这套模型的实战意义在于:排查的时候你要问的不是"这个账号是不是管理员",而是"这个账号对这个对象有没有写权限"。很多提权路径根本不需要管理员身份,只需要对某个特定对象有修改权限。
2.2 服务、计划任务、注册表:三个最容易出事的地方
为什么是这三个?因为它们都有共同特征:以高权限运行,配置信息以低权限用户可读甚至可写的形式存放在系统里。
服务的问题集中在配置文件的权限上。服务的可执行文件路径、服务对应的注册表键、服务所在目录,这三处的 ACL 只要对普通用户开放了写权限,就存在被替换或被修改配置的空间。尤其是路径中带空格且没有加引号的情况,这是微软官方文档里明确提到过的加固项,检查方式是读取服务的可执行路径,如果路径含空格且整个字符串没有被双引号包裹,就应该修正。修正方法有两种:重新配置服务路径加上引号,或者把路径所在目录的写权限收掉。
计划任务的问题在于任务定义文件的可写性。任务以什么身份运行、运行什么程序、什么时候触发,这些信息都在任务定义里。如果普通用户能修改任务定义,就等于能间接以高权限身份执行任意程序。排查方式是遍历所有以最高权限运行的任务,逐个检查任务文件所在目录的 ACL。
注册表的风险点主要在两处:系统服务的配置键,以及自启动项。前者关系到服务怎么加载,后者关系到持久化。还有一个经常被忽略的地方是某些组件的 COM 注册信息,改掉之后可能改变程序的加载行为。
注意:服务路径引号这件事,修正之前一定要确认服务当前是否在运行、路径是否被其他脚本依赖。我遇到过一次,运维直接给路径加引号,结果某个老版本监控代理的启动参数被截断,服务起不来了。
2.3 UAC 不是安全边界,别把它当成防线
这是我想反复强调的一点。很多人的心理模型是"我们有 UAC,普通用户弹窗之后也做不了什么"。这个理解是错的。
UAC 的设计目标是提醒用户,让用户在知情的情况下授权,它是一个可用性机制,不是隔离机制。开启 UAC 之后,管理员账号在登录时会拿到两个令牌,一个高完整性、一个中完整性,默认用中完整性的那个跑进程,需要提权时弹窗切换。对于本来就是管理员的账号,绕过 UAC 提示在技术上是有办法的。
真正的边界是什么?是这个账号是不是管理员组的成员。只要账号在管理员组里,UAC 挡不住有意为之的攻击者,只能挡住无意中的误操作。所以加固的重点应该放在"谁在管理员组里",而不是"UAC 开没开"。
我的做法是把本机管理员组成员收敛到最小集合,日常运维使用独立的管理账号,普通用户账号一律不进管理员组。这样即使某台机器被拿到低权限账号,也不会因为"账号本身就是管理员只是被 UAC 拦了一下"而迅速失守。
3. 授权范围内的排查清单:从手工到脚本化
3.1 第一批要看的本机信息
拿到一台机器的排查权限后,我习惯按固定顺序过一遍基础信息,这一步不需要任何第三方工具,系统自带的命令就够。
# 当前身份与持有的特权 whoami /all # 本地管理员组成员 Get-LocalGroupMember -Group Administrators # 所有服务及其运行账户、可执行路径 Get-CimInstance Win32_Service | Select-Object Name, State, StartMode, StartName, PathName # 以最高权限运行的计划任务 Get-ScheduledTask | Where-Object { $_.Principal.RunLevel -eq 'Highest' } | Select-Object TaskName, TaskPath, State, @{n='RunAs';e={$_.Principal.UserId}} # 已安装的更新列表,用于核对补丁基线 Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 20whoami /all的输出里有个部分特别值得看:特权列表。如果一个普通用户账号的令牌里出现了SeDebugPrivilege、SeBackupPrivilege、SeImpersonatePrivilege这类高价值特权,就要重点关注。这些特权本身是给特定场景设计的,比如备份软件需要备份特权,但如果被分配给不该有的主体,风险就上来了。
服务列表要重点看两列:StartName和PathName。StartName是 LocalSystem 或 NetworkService 的服务是高价值目标,PathName则用来找路径引号问题和目录权限问题。我一般会把服务列表导出成 CSV,再用脚本批量检查每个服务目录的 ACL。
3.2 用 Sysinternals 把 ACL 视角补齐
系统自带工具能覆盖大部分场景,但要看清楚对象权限,微软官方那套 Sysinternals 工具还是最顺手的,而且它是官方出品,在授权环境里用完全没有问题。
AccessChk是核心,专门用来查对象的访问权限。它的用法很直接:告诉它查什么类型的对象、查哪个账号、看什么权限。
# 查看所有服务中,普通用户可修改配置的 accesschk.exe -uwcqv "Users" * /accepteula # 查看某个目录下,普通用户有写权限的子目录 accesschk.exe -uwd "C:\Program Files" /accepteula # 查看注册表某个键的权限 accesschk.exe -uwk "HKLM\SYSTEM\CurrentControlSet\Services" /accepteulaAutoruns用来梳理自启动项,它能把服务、驱动、计划任务、登录脚本、浏览器插件这些入口一次性列全,而且会标注每个条目的签名状态和文件路径。我做持久化排查的时候,Autoruns 是第一步,先看有没有签名异常或者路径可疑的条目。
Process Explorer主要用来确认进程的令牌信息。选中一个进程,看它的 Security 标签页,能看到这个进程跑在什么身份下、有没有开启某些特权。这个功能在判断"某个服务是不是以高权限在跑"的时候非常直观。
Sigcheck用来批量核对文件签名和版本信息,适合在排查后期做一次全面体检,看看系统目录里有没有被替换过的可执行文件。
提示:AccessChk 的输出量很大,命令行里加上
-q可以去掉横幅信息,配合findstr或者输出到文件再分析,效率会高很多。我一般会把结果导成文本,再用 PowerShell 做二次筛选。
3.3 一份可以复用的 PowerShell 体检脚本
手工敲命令适合单台机器,超过五台就得脚本化。下面这个脚本我用了挺久,覆盖了服务路径、目录权限、计划任务、管理员组这几个核心检查点,输出是一张统一的表格,方便批量比对。
# WinAudit.ps1 - Windows 权限提升风险本机体检 # 仅用于授权范围内的安全自查 $report = @() # --- 检查一:服务可执行路径未加引号 --- Get-CimInstance Win32_Service | ForEach-Object { $path = $_.PathName if ($path -and $path -notmatch '^"') { # 路径含空格且首字符不是引号 $exePart = ($path -split '\.exe')[0] + '.exe' if ($exePart -match '\s') { $report += [PSCustomObject]@{ 类别 = '服务路径引号' 对象 = $_.Name 详情 = $path 风险 = '中' } } } } # --- 检查二:高权限目录对普通用户开放写权限 --- $watchPaths = @('C:\Program Files', 'C:\Program Files (x86)', 'C:\ProgramData', 'C:\Windows\Temp') $badRights = 'Write|Modify|FullControl|TakeOwnership|ChangePermissions' $badUsers = 'BUILTIN\\Users|Everyone|Authenticated Users|INTERACTIVE' foreach ($p in $watchPaths) { if (Test-Path $p) { (Get-Acl $p).Access | Where-Object { $_.IdentityReference -match $badUsers -and $_.FileSystemRights -match $badRights -and $_.AccessControlType -eq 'Allow' } | ForEach-Object { $report += [PSCustomObject]@{ 类别 = '目录权限过宽' 对象 = $p 详情 = "$($_.IdentityReference) => $($_.FileSystemRights)" 风险 = '高' } } } } # --- 检查三:以最高权限运行的计划任务 --- Get-ScheduledTask | Where-Object { $_.Principal.RunLevel -eq 'Highest' } | ForEach-Object { $report += [PSCustomObject]@{ 类别 = '高权限计划任务' 对象 = "$($_.TaskPath)$($_.TaskName)" 详情 = "RunAs=$($_.Principal.UserId) State=$($_.State)" 风险 = '中' } } # --- 检查四:当前账号持有的高价值特权 --- $highValue = 'SeDebugPrivilege', 'SeBackupPrivilege', 'SeRestorePrivilege', 'SeTakeOwnershipPrivilege', 'SeImpersonatePrivilege', 'SeLoadDriverPrivilege' $whoami = whoami /priv foreach ($p in $highValue) { if ($whoami -match $p -and $whoami -notmatch "$p\s+Disabled") { $report += [PSCustomObject]@{ 类别 = '高价值特权启用' 对象 = $env:USERNAME 详情 = $p 风险 = '高' } } } $report | Sort-Object 风险, 类别 | Format-Table -AutoSize $report | Export-Csv -Path ".\WinAudit_$(Get-Date -f yyyyMMdd).csv" -NoTypeInformation -Encoding UTF8这个脚本有几个设计上的取舍值得说明。
第一,它做的是发现,不是利用。所有检查项都只读取配置信息和权限列表,不会去尝试调动任何东西。这是排查脚本该有的边界,越界了就不叫自查了。
第二,风险等级是我按经验划的。目录权限过宽和高价值特权启用标成高,是因为这两类直接构成可利用空间;服务路径引号和计划任务标成中,是因为还需要额外的条件才能形成完整的利用路径。
第三,输出成 CSV 是为了批量比对。单台机器看表格,几十台机器就得靠 CSV 做聚合,一眼能看出哪些问题是普遍存在的配置基线缺陷。
4. 日志与检测:让提权动作留下证据
4.1 审计策略该开哪些
日志能不能用,取决于审计策略开没开。很多环境默认只开了登录审计,进程创建、对象访问、服务安装这些全都没记录,出事之后查不到东西。
我建议至少开启以下几项:
| 审计类别 | 子类别 | 实际作用 |
|---|---|---|
| 登录/注销 | 登录、特殊登录 | 记录成功登录与高权限登录分配 |
| 详细跟踪 | 进程创建 | 留下命令行参数,这是取证的核心 |
| 对象访问 | 审核文件系统、审核注册表 | 记录对敏感对象的写操作 |
| 策略更改 | 审核策略更改 | 发现审计策略被人为关闭 |
| 系统 | 安全系统扩展 | 记录服务安装、驱动加载 |
| 账户管理 | 安全组管理、用户账户管理 | 发现账号被加入高权限组 |
命令行审计这一项要单独确认。进程创建事件里如果不带命令行参数,日志的价值会下降一大截——你知道有个进程起来了,但不知道它带了什么参数,看不到攻击者的实际动作。
配置可以用auditpol完成:
# 开启进程创建审计,并启用命令行记录 auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" ` /v ProcessCreationIncludeCmdLine_Enabled /t REG_DWORD /d 1 /f第二条注册表项是关键,不加它的话,命令行字段是空的。我见过不少环境的日志里有 4688 事件,但命令行那一栏是空的,等于白开。
4.2 关键事件 ID 判读表
系统安全日志和 Sysmon 日志里,和提权相关的核心事件就那么几个,记住了判读速度会快很多。
| 事件 ID | 来源 | 判读要点 |
|---|---|---|
| 4672 | Security | 高权限登录,登录类型结合 4624 一起看 |
| 4688 | Security | 进程创建,重点看父进程与命令行 |
| 4697 | Security | 服务安装,注意服务路径和运行账户 |
| 7045 | System | 服务安装,比 4697 更直接,含完整路径 |
| 4673 | Security | 调用特权服务,看是哪个进程调用的 |
| 4698/4702 | Security | 计划任务创建与更新,重点看运行身份 |
| 4732/4728 | Security | 账号被加入本地或全局组 |
| 4907 | Security | 对象审计策略变更,可能是在关日志 |
判读的时候有个方法我自己一直在用:按进程树看,不要按事件 ID 看。先找出一个可疑的父进程,然后顺着它的子进程一路往下,看它在短时间内启动了哪些东西。正常的运维操作和攻击行为的区别,往往不在单个事件上,而在整个进程树的形态上——比如一个办公软件突然拉起来一个命令行解释器,再往下拉起来一个网络工具,这个形态就很不对劲。
4.3 控制通道建立的流量与进程侧特征
提权成功之后要建立持续通道,这一步的特征相对明显。
进程侧,注意几个现象:一个没有数字签名的可执行文件从临时目录启动;某个进程的网络连接数长期保持不变但持续存在;进程的内存占用很小却一直不退出;父进程已经退出但子进程还在跑。这些都是我在实际分析里频繁遇到的形态。
流量侧,规律性的心跳是最典型的特征。固定间隔、数据量小、目标地址很少变化,这三个特征凑在一起就值得深挖。DNS 层面的异常查询也值得关注,比如某个内部主机开始对一批看起来随机生成的域名做查询。
桌面环境里还有一个容易漏的点:定时唤醒与远程控制类进程。有些远控类工具为了稳定性会注册定时任务做自我恢复,这类任务在 4698 事件里会留下记录,运行身份通常是最高的。排查的时候,把"高权限 + 高频触发 + 路径在用户目录"这三条同时命中的任务单独拎出来看。
5. 加固落地:把能提权的口子一个个焊死
5.1 服务与计划任务的 ACL 基线
服务这一块,我推的做法是把基线写死,然后定期比对。
第一,服务可执行文件所在目录的 ACL 必须收紧,只允许 SYSTEM、Administrators 和一个专用的服务账户写入。C:\Program Files下的子目录尤其要注意,很多安装程序会把目录权限设成 Everyone 可写,装完之后没人改回来。
第二,服务配置键的权限要检查。注册表里服务对应的键位于HKLM\SYSTEM\CurrentControlSet\Services下,这个位置默认权限通常是合理的,但第三方软件安装过程中可能会改动。
第三,服务路径统一加引号。这是成本最低、收益最明确的一条,批量处理可以用脚本:
Get-CimInstance Win32_Service | Where-Object { $_.PathName -and $_.PathName -notmatch '^"' -and ($_.PathName -split '\.exe')[0] -match '\s' } | ForEach-Object { $fixed = '"' + ($_.PathName -replace '^(.*?\.exe)(.*)$', '$1') + '"' ` + ($_.PathName -replace '^.*?\.exe', '') Write-Host "建议修改: $($_.Name)" Write-Host " 原路径: $($_.PathName)" Write-Host " 新路径: $fixed" # 确认无误后手动执行: sc.exe config "$($_.Name)" binPath= $fixed }注意脚本里注释掉的那行是故意不自动执行的。路径改写会影响服务启动,必须逐个确认。我踩过一次坑,一个服务原本的路径后带了多个空格和换行,脚本一处理就变成了合法但错误的路径,服务直接起不来。所以这类改动我坚持先输出建议、人工确认、分批执行。
计划任务这一块,基线原则是:能用专用账号跑的,不要用 SYSTEM。只有当任务确实需要系统级操作时才用最高权限。任务定义文件所在的目录(C:\Windows\System32\Tasks)权限保持默认,不要为了"方便运维"把它放开。
5.2 凭据保护相关的关键设置
凭据类问题的加固,重点不在技术,在流程。
本地管理员账号的密码必须每台机器不同。这件事现在有成熟的做法,用本地管理员密码解决方案做到自动轮换,不需要人工维护。我在没有这套方案的环境里,至少会做到按批次分组,同批次的机器共用一个密码,批次之间不重复。
服务账号的密码要定期轮换,而且不能用同一套凭据跑多个服务。我见过一个特别典型的场景:某企业内部好几个业务系统都用同一个域账号跑服务,这个账号被写在一个共享配置文件里,权限还是域管理员。这台机器出问题,等于整个域出问题。
还有几个系统级的设置值得检查:
- 凭据保护:开启之后,凭据不会被明文缓存到内存里,能显著降低内存抓取类攻击的收益。开启前要确认硬件和驱动支持。
- 远程桌面连接时的凭据委派:默认设置可能允许凭据被带到远程主机,运维场景下要按实际需要收紧。
- 缓存凭据数量:域环境下,本机缓存的登录凭据数量默认为 10,可以下调到 0 或 1,代价是断网时无法登录。
提示:这些设置的改动对用户有可感知的影响,尤其是缓存凭据数量改成 0 之后,笔记本用户断网就没法登录了。上线前一定要和业务方确认,别自作主张。
5.3 补丁、版本与最小权限的日常运营
补丁管理这件事,坑主要在覆盖面。操作系统的更新有统一的推送机制,第三方组件的更新往往没人管。我的做法是建一份资产清单,把所有装了第三方运行库、办公插件、远程管理工具的机器列出来,按厂商的更新节奏单独跟。
最小权限的落地,我总结成三条具体动作。
第一,本机管理员组只保留必要成员。除了内置管理员账号和一个专用的运维账号,其他一律移出。域管理员组更严格,只保留极少数专用账号。
第二,服务账户不进管理员组。如果某个服务确实需要高权限,用专门的系统账户跑,或者给它单独的服务 SID,而不是直接塞进管理员组。
第三,用户日常使用的账号,不做任何特权操作。需要提权的场景,走独立的管理账号,配合审批流程。这一步很多人觉得麻烦,但它是最有效的一条——普通账号提不了权,攻击者拿到它也只能停在那里。
6. 实操踩坑与排错速查
6.1 排查阶段最容易误判的几种情况
误判一:把正常的运维脚本当成异常。我做过一次应急,看到一个凌晨三点启动的命令行进程,吓了一跳,结果一问是运维团队备份脚本。所以排查结论必须和运维记录对齐,看日志之前先拿到变更窗口和定时任务清单。
误判二:只关注 Bad 的目录,忽略了子目录。很多时候主目录权限是正常的,问题出在下三层的某个子目录上。检查一定要递归,而且要考虑继承权限的影响——父目录收紧之后,子目录的显式权限可能还是放开的。
误判三:把访问被拒绝当成不存在的路径。排查的时候如果是用低权限账号跑的脚本,很多路径会因为权限不足读不到,脚本里如果没做异常处理,就会静默跳过。这些"看不见"的路径恰恰可能是高风险点。所以体检脚本必须用管理员权限跑,而且对读取失败要有记录。
误判四:把服务停用当成风险消除。一个服务被停用了,但它的目录权限和配置键权限还在。哪天有人为了临时需求又把它启动起来,风险立刻回来了。
误判五:忽略凭据复用。在单台机器上看,什么都正常;放到整个域里看,同一个管理员密码出现在三十台机器上,这就是最大的风险点。排查必须做横向比对,不能只看单机。
6.2 加固上线后常见的翻车点
| 现象 | 常见原因 | 处理思路 |
|---|---|---|
| 服务无法启动 | 路径改写后参数被截断,或目录权限收紧过度 | 先回滚,逐条比对原路径字符串,权限收紧要保留服务账户的读取和执行权限 |
| 计划任务执行失败 | 运行账户缺少必要权限,或密码已过期 | 用任务历史记录确认失败原因,不要直接改回 SYSTEM |
| 用户反馈无法登录 | 缓存凭据数改为 0 且网络中断 | 保留至少 1 个缓存凭据,或提前通知用户 |
| 业务系统报错 | 凭据保护开启后,依赖明文凭据的旧系统无法工作 | 先在测试环境验证,再分批上线 |
| 备份任务中断 | 备份账号被移出管理员组 | 改用独立服务账户并授予备份相关特权 |
这张表里每一条我都真实遇到过。最需要提醒的是第一条:目录权限收紧是加固里最容易出事的操作,因为很多服务的运行账户在安装时就设置好了,你收权限的时候如果没把那个账户保留进去,服务就起不来了。改权限之前,一定先把当前的 ACL 完整导出留档。
7. 演练边界:把合规这件事做在前面
7.1 授权、范围和留痕
不管你是做内部演练还是外部评估,动手之前必须有三样东西:书面授权、明确的范围清单、以及过程留痕的约定。
授权文件里要写清楚目标资产范围、允许的时间窗口、允许使用的技术手段、以及明确禁止的操作。我一般会在授权里单独列一条禁止项清单,把可能影响业务连续性的操作排除在外,比如不重启生产设备、不做拒绝服务测试、不在非授权时间触碰业务系统。
范围清单要具体到 IP 和主机名,不能写"内网所有资产"这种模糊表述。范围之外的东西,哪怕顺手就能看到,也不碰。
过程留痕这件事很多人会偷懒。我的做法是全程终端录屏加操作日志,脚本每一步的执行结果都落盘保存。这不只是为了交付报告,更重要的是万一业务侧出现异常,能第一时间证明和测试动作无关。
7.2 数据与结果的处理
演练过程中拿到的东西,处理方式要提前约定好。凭据类信息、敏感配置、业务数据,这些都不能在报告里原文呈现。报告里应该描述的是风险类型、影响范围、修复建议,而不是实际抓到的密码明文。
测试结束之后,所有测试过程中创建的账号、服务、计划任务、文件,都要按清单逐个清理干净,并且让业务方确认。我见过演练结束后半年,测试用的账号还躺在域管理员组里,这比原本的风险还要严重。
还有一点是我个人的坚持:发现的高风险问题,不管演不演练,都要在最短时间内告知责任方。有些问题等报告出来再整改,中间的时间窗口就是实打实的暴露面。真正做安全的人,不会把发现的问题拿来做筹码。
最后分享一个我一直在用的习惯:给每一台服务器建一份"权限变更台账",记录这台机器上管理员组成员、服务账户、高权限计划任务的历史变化。出问题的时候,这份台账能帮你快速判断哪些是正常变动、哪些是异常新增。这份台账不需要什么复杂的系统,一个共享表格就够了,但坚持维护下去,收益远超投入。