前阵子帮一家制造企业做内网安全排查登进他们的域控一看一个离职快两年的运维部门主管账号居然还挂在“域管理员”组里密码策略因为长期没登录而被跳过。我当场就绷不住了——这哪是账号分明是给攻击者留的后门钥匙。后来顺着这个账号一翻发现类似的“僵尸账号”远不止一个有的还连着 ERP 系统和堡垒机的高权限通道。这类问题在行业里有个很形象的名字孤儿账户也叫僵尸账号。它指的是员工离职、转岗或外包团队撤场后对应账号没有被及时禁用或删除继续在企业身份系统里残留。如果只是普通权限还好最怕的是那些挂在高权限组里的账号黑客拿到它就像捡到一张没人报失的门卡进出都畅通无阻。这篇文章我从排查思路、实操方法到长效治理把我踩过的坑和验证过有效的手段都摊开讲一遍适合安全运维、系统管理员、以及任何对账号安全有心无力的人参考。1. “僵尸账号”到底是什么先从一次排查说起1.1 孤儿账户的真实画像我记得当时在这家制造企业做账号专项排查第一步不是直接去域控里捞数据而是找人事那边要了一份近三年的离职名单。名单拿到手后和 AD 里的有效账号一比对结果让我吃了一惊离职名单上的 47 个人里还有 9 个账号处于启用状态其中 3 个竟然还在“域管理员”或者“本地管理员”这类敏感组里。换句话说这些账号和数据完全没有人维护却保留着大量系统权限。这里是关键孤儿账户不是简单的“残留账号”它有几个共同特征。第一长期没有登录记录密码失效时间被跳过因为没人用所以也不会有人发现异常。第二没有关联到真实在职员工没有办法通过部门交接或者申请流程来追踪。第三权限通常没有随人员离职而降级反而因为入职年限久、历史职责重往往留在权限金字塔的高层。第四没有任何人在运营层面为这个账号负责它就像一栋大楼里没有登记在册的空房间门锁还完好但谁都能撬开。说白了“僵尸账号”在技术层面是身份管理失效的产物但它的根源往往在流程层面。很多企业连离职名单都不是及时同步到 IT 的人事流程和安全流程各走各的路账号也就不可能及时被清理。做排查时如果只盯技术手段容易越查越乱因为头绪太多我习惯先把人、账号、权限这三层关系拉通后面所有操作才有抓手。1.2 为什么攻击者专门盯着这种账号下手攻击者突破一个企业的安全防线不一定非要正面硬刚防火墙或者挖 0day很多时候他们更喜欢去捡“没人管的钥匙”。为什么孤儿账户会成为头号突破口因为它在整个安全体系里是一个几乎完美的攻击跳板。正常账号有主人盯着登录时间异常、登录地点漂移、半夜跑批命令都会被安全运营发现。孤儿账户反正没人注意黑客用它做什么都不会引发警觉这是“无主”带来的天然隐身性。更麻烦的是权限往往还很高很多高权限账号是早期系统搭建时建立的员工离职后权限没有跟着业务一起收走于是黑客拿到这个账号后直接从普通用户权限跳到管理员权限。还有一点是凭证不会被重置账号长期不被使用没人想起去改密码密码可能还是几年前的弱密码或者已经泄露到各种公开的数据库里。从攻击者视角看一个账号同时具备“长时间无人使用、权限高、密码可能泄露”这三个条件那几乎就是明牌了。他们用这种方式进入企业内网拿到域管权限后再做凭证转储接着横向移动到服务器、数据库甚至备份系统。整个过程可能持续几个月都没人发现因为一开始登录用的就是一个被所有人遗忘的账号。所以我在做安全建设时有个原则宁可少给权限也必须盯住权限宁可账号删晚了也不能让高权限账号永久失联。2. 高权限孤儿账户为什么是“头号突破口”2.1 权限继承让账号的实际权力比看起来更大很多运维朋友有一个误区认为只要不把账号直接放进“域管理员”组它就没什么危险。这个想法特别危险因为企业目录系统里的权限往往有嵌套关系和继承机制。一个账号可能只被加进了“服务器操作员”这个普通管理组但这个组本身又继承了另一层委派权限或者它所在的 OU 上挂了一条“重置所有用户密码”的委派规则。你看到的是表面一个组实际拿到的是几十台服务器的控制权。这种权限上的“倍增效应”在离职账号身上会被放大。为什么因为离职账号往往是在系统上线的特殊时期创建的当时业务紧急、人员调整频繁为了图省事经常直接授予大范围权限而后来没有人重新评估过这些权限是否还合理。加上账号本身没有活跃用户去关心权限变化安全部门也很难追踪“谁在什么时候给谁授权”攻击者钻进这个缝隙后就拥有了合法的管理员身份。合法身份是做安全对抗里最值钱的东西因为它不会触发告警至少不会触发通常意义上的登录异常告警。我记得在一次模拟演练中安全团队用一个残留高权限账号成功登录了运维审计系统随后从那里导出了几十台核心服务器的账号密码表。整个过程没有利用任何漏洞纯粹就是“账号权限残留”加上“凭据随处存放”。这件事之后我们内部形成一个共识账号权限排查不能只看账号是不是启用要看它的有效权限、嵌套组关系、委派条目和历史申请记录。2.2 没人盯着失活账号的监管真空“无人维护”这四个字看起来轻飘飘放在账号安全里就是致命的监管空白。每一个活跃账号都对应一个真实的人人有异常行为可以被 HR 问询有设备指纹、刷卡记录、办公地点做交叉验证但孤儿账户对应的“人”已经不存在了这就是它最被攻击者喜欢的地方——没有任何行为基线。行为基线是什么意思一个正常用户每天登录时间大概在几点、常用哪台机器、习惯访问哪些服务器这些都是可以基于历史记录建立的。安全设备会基于这些数据判断当前登录是否异常。孤儿账户没有这种基线因为它几乎不登录一旦被黑客启用并开始操作系统完全没有历史数据的参照很难判断这个账号的行为是“第一次出现”还是“第一次异常出现”。更麻烦的是账号长期不用还会绕过很多密码策略比如强制改密周期、登录失败次数锁定等等。从实际案件里总结出来的规律黑客拿到失活账号后的操作路径通常是第一步登录内网第二步枚举域内其他账号和权限组第三步找到更高权限的凭据第四步关掉安全的日志或者针对性的隐藏自己。整个过程里失活账号扮演的是一个“合法身份”跳板它给了攻击者在潜伏期内不被重点关注的保护伞。我们后来在部署账号监控时专门增加了一条规则任何启用状态但超过 90 天没有登录的账号一旦出现登录行为立刻产生中高危告警并同步给安全负责人。这个规则上线后效果非常显著因为正常账号很少出现这种模式而攻击者偏偏一定触发这种模式。2.3 一个典型的入侵路径推演纸上谈兵讲这么多不如把一条真实出现过的入侵路径串起来讲。某家企业的域控日志里曾经留下过这样的痕迹攻击者用一个小写字母加数字组合的密码成功登录了一个停用状态下被重新启用的账号而这个账号居然是“域管理员”组的成员。背后的事实是这个账号对应的员工两年前离职但当时只是从邮箱系统里删除了账号AD 里的同一个身份因为不知道是谁维护反而留了下来。系统里甚至存在两条记录一条标记已删除另一条继续有效管理界面上看到的是“已清理”实际上后门还开着。拿到这个账号后攻击者第一晚只做了一件事查询域内所有管理员的最后登录时间。这个查询本身不敏感权限允许范围内就可以执行。第二天晚上他用同一账号建立了一条计划任务定时把域控上的安全日志事件 4732、4733 循环删除。之后才真正开始横向移动从域控管理员会话里提取了更高权限服务的凭证往服务器管理组、数据库管理组、甚至备份系统里埋了几个新账号。等我赶到现场做应急时最早的入侵痕迹已经被清掉了只剩下他遗漏在某个备份服务器上的一段 PowerShell 历史记录。这个案例里最让人后背发凉的细节是攻击者从头到尾用的所有跳板都是企业自己残留的合法账号绕过了绝大多数基于签名和特征检测的安全设备。所以我才反复强调账号治理不是合规应付它是防线里最容易被人忽视、却最容易被人利用的一环。安全建设的优先级里把账号生命周期管好性价比远高于盲目上各种高价检测设备。3. 怎么把藏起来的孤儿账户挖出来说点能直接落地的排查方法3.1 从身份源开始把离职名单和账号清单对齐我想先纠正一个习惯性错误很多运维拿到项目第一反应是去域控里查“最后登录时间超过 X 天的账号”然后把它们一批批禁用。这样做方向不错但容易误伤服务账号、共享账号还会漏掉那些最近刚被攻击者激活利用的“僵尸账号”。更稳妥的打法是先建立身份源对照关系把人事系统中的离职名单、外包合同结束日期、内部转岗记录与 AD 账号、企业应用账号、数据库账号做交叉比对。具体实操上我会先整理三份清单。第一份是员工在职名单从 HR 系统导出来包含工号、姓名、部门、入职日期、离职日期。第二份是账号清单从 AD 和各个应用系统导出包含账号名、创建时间、最后登录时间、所属组、启用状态。第三份是权限清单重点导出“域管理员”“企业管理员”“架构管理员”等敏感组里的成员以及各大系统本地管理员组里的账号。把这三份清单放到一张透视表里用员工工号作为关联键一眼就能找出“账号存在但员工已经离职”的匹配项。这里要特别说明人员信息会涉及隐私边界排查时我只用工号和账号做关联不去额外读取员工的薪资、绩效这些无关数据。权限上也需要提前和行政、人事部门确认避免安全排查触碰到不该碰的数据。这一步做扎实后面所有的人工复核和处置动作都能省下大量时间。3.2 用最后登录时间做第一轮筛选在身份源对照之外还需要从“活跃度”维度做一轮筛选。AD 里有一个用户属性叫 lastLogonTimestamp它会记录账号最后一次登录域的时间但它有两个先天缺陷一是默认有 14 天的精度损失二是域控制器之间同步可能会有延迟。所以我不建议用这个字段做精确判断但用来做粗筛非常合适。可以直接在域控上跑一条 PowerShell把超过 90 天没登录的用户提取出来再结合启用状态一起看。# 在域控上使用 ActiveDirectory 模块执行 $cutoffDate (Get-Date).AddDays(-90) # 提取超过90天未登录且处于启用状态的用户排除部分基础服务账号名 $inactiveUsers Get-ADUser -Filter { (Enabled -eq $true) -and (lastLogonTimestamp -lt $cutoffDate) } -Properties Name, SamAccountName, lastLogonTimestamp, MemberOf, Department foreach ($user in $inactiveUsers) { $lastLogon [datetime]::FromFileTime($user.lastLogonTimestamp) [PSCustomObject]{ 账号名 $user.SamAccountName 姓名 $user.Name 部门 $user.Department 最后登录 $lastLogon.ToString(yyyy-MM-dd HH:mm) 所属组数 ($user.MemberOf).Count } } | Sort-Object 最后登录 | Format-Table -AutoSize跑完这条命令之后拿到的列表只是候选清单还不能直接禁用。需要做人工分类排除掉那些明确标记为服务账号、系统内置账号、应急备用账号的条目对剩下的账号再查一遍最后一次修改密码的时间和创建时间。如果一个账号超过 90 天没登录、创建时间又很早还挂在敏感组里基本可以列进重点核查名单。后面要做的就是把这份名单提交给对应的业务负责人确认账号是否还需要保留。这个步骤千万不要跳过因为你不可能了解每个账号的业务背景盲禁容易把正在跑批的任务打断。3.3 查有效权限别被表面清单骗了排查孤儿账号最见功底的地方是如何准确判断账号的实际权限。只看“MemberOf”属性只能知道直接成员关系但 AD 里还有嵌套组、受保护组、委派权限、GPO 应用这些间接权限。同一个账号可能表面上只在“研发部成员”组里实际上因为研发部组里套着一个服务器管理员组它就能登录域内所有研发服务器并重启服务。这种间接权限靠肉眼盯组名单很容易漏。我建议在排查阶段引入一个查询“有效权限”的步骤。Windows 的 ADUC 管理工具里自带“属性编辑器”和“安全”标签可以查看账号对某个 OU 或对象的有效权限但账号量大的时候手工点效率太低。更实用的方式是用 PowerShell 调Get-ADPrincipalGroupMembership递归展开所有组关系再用dsacls查看指定对象的 ACL 继承情况。# 展开某个账号所属的所有组包括嵌套组 $account Get-ADUser -Identity zhangsan -Properties MemberOf $allGroups () $pending ($account.MemberOf) while ($pending.Count -gt 0) { $groupDN $pending[0] $pending $pending[1..($pending.Count-1)] $group Get-ADGroup -Identity $groupDN -Properties MemberOf $allGroups $group.Name $pending $group.MemberOf } $allGroups | Sort-Object -Unique如果团队里有预算或者已经部署了身份治理平台那直接用平台自带的权限分析报表会更省事。没有也没关系用上面的命令把结果导成 CSV再和企业内部的资产清单合并重点盯那些“组里有敏感关键字、账号归属人已经离职、最后登录时间超过半年”的组合。这一步跑完基本能还原攻击者眼里的画面知道哪些账号是可以直接通往核心系统的金钥匙。3.4 工具选型没有预算怎么先跑起来一讲到账号治理很多企业第一反应是买商业产品但现实中预算往往没那么快批下来。所以我把工具方案分成三个梯度按成本从低到高排列。第一梯度是纯手工脚本适合账号数量在几百至一千左右的场景。上面的 PowerShell 命令再加一个输出 CSV 的循环就能支撑一次比较完整的排查。劣势是没法做到持续自动化、实时告警所以只适合作为“体检”手段不适合作为“长期心电监护”。第二梯度是开源或免费工具比如用或平台里的密码审计模块做弱口令检查用系统自带的安全基线扫描工具检查敏感组变更。这部分能实现周级粒度的批量核查已经能覆盖大部分中小企业的需求。第三梯度才是商业身份治理平台适合账号规模上万、组织架构复杂的场景它可以自动拉取 HR 数据、自动发起离职流程、自动回收权限并留痕审计。我个人的建议是先别急着上第三梯度很多企业连“账号责任人字段”都没有维护好买平台回来也是空壳。先把前两个梯度跑熟积累出准确的责任人清单和资产清单再谈上平台。否则平台上线后还要花大量时间补数据项目容易烂尾。4. 定位到孤儿账户之后怎么处置流程和长效治理同样重要4.1 先冻结再处置别一删了之当我筛出重点账号后第一反应肯定是“把这账号禁用了”。这里我要提个醒禁用账号只是第一步而且禁用不等于删除删除也不等于安全。实际处置动作一定要按顺序来不能跳步。推荐的处理顺序是冻结、重置密码、移除高权限组、转移业务归属、隔离观察、最终归档或删除。冻结就是禁用账号这一步能立刻阻断攻击者利用凭证登录随后立刻重置密码把原来可能泄露的旧凭证变成无效接着移除它所在的高权限组把权限从根上收掉再去找业务负责人确认账号对应的业务是否还在运行如果在运行需要先把任务迁移到新账号观察一到两个业务周期确认没有报障后再把这个账号移动到“已禁用”的 OU 里留档。为什么不能上来就删除因为很多企业跑批任务、定时同步、系统间接口还在用这些“看起来没人用”的账号。我曾经遇到过一家企业清理账号时直接删了一个定时任务关联账号结果当天夜间批量任务大面积失败生产系统的第二天业务报表全乱了。从那以后我定了一条死规矩清理动作必须有观察期没有业务确认的账号一概先禁后观不做物理删除。4.2 降权、转移、清权限不是所有账号都得删处理过程中会碰到一个更棘手的问题有些“僵尸账号”关联的业务其实还在运转只是维护它的员工转岗或离职了。这种情况如果简单禁用等于把业务也停摆所以不能一刀切。我的处置字典里有一组常用动作账号保留、权限降级、所有权转移。首先判断账号是否还有业务依赖找系统负责人或是应用 Owner 去确认邮件里写清楚“这个账号关联的应用是否仍在使用”“是否有替代账号”。如果确认仍在用那就走“所有权转移”流程把账号纳入现有运维人员名下更新联系人和负责人字段并且把密码改掉、绑定新的双因素认证。接下来是“权限降级”把原来挂着的域管组、本地管理员组全部移除只保留完成任务所需的最小权限。如果业务后续确认不再使用就再走禁用和归档流程。这里想强调一个容易被忽视的点权限降级之后一定要复查继承关系。移除直接组成员容易但嵌套组里的权限可能在下一层被重新带回来。复查方式可以用第 3.3 小节里的展开命令反复确认账号的有效权限已经降到预期范围。处置记录要留痕包括谁批准的、什么时候做的、权限变更前后的差异清单这样后续被审计时才不会被质疑。4.3 把治理动作固化到流程里企业账号治理靠一次专项排查是不够的真正的关键是把它变成常态化流程。我个人在项目里推过的机制有两个一个是“季度账号健康度检查”另一个是“离职账号自动触发稽核”。季度检查的内容比较固定比对 HR 离职名单与账号清单筛出 90 天以上未登录的启用账号检查敏感组成员是否和在职名单一致抽查账号权限是否有不合理增长。这套检查的产出是一张清单按风险从高到低排好提交给对应的业务负责人逐项确认。只要坚持两个季度很多历史包袱就会被清理掉新产生的残留也会明显减少。这里整理了一份我常用的季度复核清单可以直接抄作业检查项数据来源判定标准处置动作离职账号残留HR 系统 AD离职日期早于核查日且账号仍启用禁用 移出敏感组长期未登录账号AD lastLogonTimestamp超过 90 天未登录且非服务账号列为候选清理名单敏感组成员变更域控安全日志组内成员变化未走审批流程回滚变更 复核权限服务账号密码状态密码管理平台超过密码有效期周期强制重置并关联负责人特权账号责任人人员信息库责任人字段为空挂到运维负责人名下另一个机制是在企业微信或 OA 流程里加一道“离职审批锁”HR 在系统里发起离职流程时自动通知 IT 管理员在一个工作日内完成账号禁用、邮箱转发、应用权限回收。这个流程看起来简单但很多企业做不到因为审批流里的 IT 节点经常被人事部门漏掉。把话说透一点流程断点的问题靠工具很难完全兜住需要从上到下明确账号回收的时限和责任人。只要有一个人明确负责“最后的删除”动作整个体系就不会滑向失控。5. 顺手整理的常见问题和排错记录5.1 最后登录时间不准问题可能出在这很多朋友跑完 PowerShell 后反馈明明账号昨天还在用查询结果却显示好几个月没登录。这个不奇怪lastLogonTimestamp 的复制策略本身有延迟而且它不是实时更新域控之间同步没完成时查询到的值就可能不是最新数值。更精确的字段是 lastLogon它不缓存、直接从目标域控读取但缺点是只代表“你当前查询的这台域控”视角多域控环境下需要汇总所有域控的值再取最大值。如果账号数量大需要更高精度可以用Get-ADUser加-Server参数逐台域控跑再做并集。精度和性能的平衡要按实际规模取舍账号五千以上的环境不建议每台域控全量扫会拖慢目录服务的响应。折中方案是先用 lastLogonTimestamp 做粗筛缩小范围后再对候选账号用 lastLogon 做精确确认。还有一类情况是账号虽然没登录过域但一直在用本地账号登录服务器。这不属于 AD 账号范畴需要把排查范围扩大到每台服务器的本地账户。比较省力的做法是先扫描资产清单把开放了 3389 或 SSH 端口的主机找出来再集中检查本机管理员组名单避免漏掉本地管理员这层风险。5.2 如何避免误杀服务账号和应急账号清理行动里最怕误伤尤其是一些名字看起来像“僵尸账号”、其实承担着无人值守任务的账号。我遇到过数据库同步账号三个月没登录实际上每天都在通过服务账户接口跑数只是因为不按交互式登录算所以时间一直不更新。这种账号一旦被批量禁用第二天就有业务告警轰炸。我的处理习惯是建立一份“例外账号清单”把服务账号、系统内置账号、灾难恢复备用账号、计划任务关联账号提前标记好并且给它们挂上明确的负责人。清单里要写清楚账号用途、允许的登录方式、是否纳入 90 天未登录清理范围。有了这份白名单批量筛选命令在执行时就加上Where-Object { $_.Name -notin $excludeList }把误伤概率降到最低。如果还是不小心误伤了服务账号也不用慌处置时不要直接删除账号走禁用流程还能随时启用。这也是我前面强调“先禁后删”的重要原因。应急账号也要单独考虑某些核心系统需要保留紧急本地管理员账号这种账号可以长期不登录但必须放在企业级密码保险箱里密码定期轮换并且只能在紧急审批流程下取用。它虽然也满足“长期未登录”的特征但不属于需要清理的对象反而值得重点保护。5.3 几个容易翻车的细节点账号治理实际操作中有个很容易踩坑的点是对内置账号和默认组的处理。比如域内置的 Administrator、Guest以及“Domain Admins”“Enterprise Admins”“Schema Admins” 这些默认高权限组改造时不能照普通账号的流程来。内置账号的很多属性不允许直接禁用组策略默认也会忽略部分操作强行修改可能导致域功能异常。稳妥做法是启用审计和监控持续盯住这些对象的变更行为而不是直接把它们纳入清理名单。另一个坑是权限委派记录。有的人清理账号时只查了组成员关系没查对象 ACL 上的单条委派授权清理后看似干净实际访问权限还留着。例如某个离职员工的账号已经从组里移除但共享文件夹或 OU 上单独给了它“写入”或“完全控制”权限只要账号还存在它就依然能访问这些资源。所以处置动作的最后一定要做一次“有效权限”复查拿账号重新对敏感路径做权限查询确认所有路径都已切断。再补一个细节远程桌面服务的用户配置文件也可能残留。账号删除后服务器上对应 sID 打头的配置文件文件夹如果不清会积累大量垃圾文件而且新账号恰好拿到相同 sID 映射时还可能串到旧配置引发权限异常。清理时最好顺带检查终端服务器上的 Profile 目录一并归档或删除避免后续莫名其妙的“分配配置文件错误”问题。我做了这么多年安全巡检最直观的感受是企业的安全防线从来不是毁在那些高深的攻击手法上而是毁在日常流程的缝隙里。孤儿账户就是最典型的缝隙之一它小到平时没人提大到攻击者可以直接拿到域管权限。每次处理完这类问题我都会在企业内部强调一句话权限是有生命周期的账号跟着人走人走了权限必须跟着收。希望这篇文章能帮你把自己身边的“僵尸账号”揪出来收掉它们防线才能真正闭合。