ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

白银票据攻击原理与防御:Kerberos服务票据伪造实战解析

白银票据攻击原理与防御:Kerberos服务票据伪造实战解析

1. 白银票据不是“银票”,而是域控环境里的一把隐形钥匙

很多人第一次听到“白银票据”这个词,下意识会联想到古装剧里盖着红印、写着“凭票兑银五百两”的那种纸质银票。但现实中的白银票据(Silver Ticket)和它毫无关系——它既不印在纸上,也不需要盖章,甚至不需要接触域控制器(DC)本身。它是一段精心构造的Kerberos服务票据(TGS),是攻击者在已获取某个域内用户凭证后,绕过域控验证、直接向目标服务发起身份冒用的“免检通行证”。

我最早在某高校实验室做红蓝对抗复盘时遇到这个概念。当时蓝队同学反复确认所有域控日志都干净,DC没被拿下,管理员密码也没泄露,可红队却能持续访问核心文件服务器和数据库服务。后来溯源发现,问题出在一台被攻陷的普通域成员主机上:攻击者用抓取到的某服务账户NTLM哈希,结合域SID和KRBTGT账户的密钥,离线生成了针对特定服务的TGS票据。整个过程完全不触碰DC,日志里只留下几条看似正常的Kerberos请求,连“Kerberos Service Error”这类告警都很难触发。

这就是白银票据最危险的地方:它不依赖域控失陷,不修改任何系统配置,不写入新进程,不调用可疑API,甚至连Windows事件日志里的4769事件(TGS请求)都显示为“成功”。它像一把开锁匠不用撬棍、不砸门、不惊动报警器,只靠一把复制好的钥匙就走进了房间。

关键词里虽然没填,但必须明确:白银票据的核心依赖是服务账户的NTLM哈希(或AES密钥)+ 域SID + KRBTGT账户的密钥(用于加密票据的enc_part)。注意,这里不需要KRBTGT的明文密码,只需要其密钥——而这个密钥在域环境中长期不变,一旦被提取,就等于给所有服务票据开了永久后门。

它和黄金票据(Golden Ticket)有本质区别:黄金票据伪造的是TGT(Ticket Granting Ticket),能申请任意服务的TGS,权限等同于域管理员;白银票据伪造的是TGS本身,只能访问指定服务,但正因为目标明确、行为收敛,反而更难被检测。你可以把它理解成:黄金票据是伪造了一张“无限额度的信用卡”,而白银票据是伪造了一张“只能在某家餐厅消费的储值卡”——前者动静大、风险高,后者隐蔽性强、落地快。

如果你正在参与内部渗透测试、红队演练,或者负责企业域环境的安全加固,那么白银票据不是“可能遇到”的威胁,而是“大概率已经存在”的现实风险。因为它的利用门槛远低于黄金票据:不需要域管理员权限,不需要访问DC,甚至不需要网络直连DC——只要拿到一个服务账户的凭证,再配合域信息,就能在任意域成员机上完成离线票据生成与投递。

提示:白银票据的生命周期由票据中嵌入的起始时间(start_time)和结束时间(end_time)控制,通常默认为10小时。但它不依赖KDC的实时签发,所以即使域策略强制要求票据每2小时刷新一次,白银票据依然有效——因为它根本没走KDC的签发流程。

2. 为什么KRBTGT密钥是白银票据的“命门”,而服务账户哈希才是真正的“扳机”

要真正搞懂白银票据怎么用,必须拆开它的三块基石:服务账户凭证、域SID、KRBTGT密钥。这三者缺一不可,但它们的获取难度、敏感程度和使用方式截然不同。很多初学者误以为“拿到KRBTGT密钥就等于拿下整个域”,其实这是对白银票据机制的最大误解。

先说KRBTGT账户。它是域内一个特殊内置账户,全名是“Key Distribution Center’s Ticket Granting Ticket”,专门用来加密所有TGT的enc_part部分。它的密码由系统自动生成且永不更改(除非管理员主动重置),因此其NTLM哈希和AES密钥在域生命周期内基本恒定。这个密钥之所以关键,是因为白银票据虽然是伪造的TGS,但它的enc_part(加密部分)必须用KRBTGT密钥加密,否则目标服务在解密时会失败——服务端收到票据后,会用自己的密钥(即服务账户密钥)解密出票据主体,再用KRBTGT密钥解密enc_part来校验票据合法性。如果enc_part解不开,票据直接被丢弃。

但请注意:KRBTGT密钥只用于验证票据真伪,不参与服务访问授权决策。真正决定“你能访问什么服务”的,是票据中明文携带的service principal name(SPN),比如cifs/fileserver.domain.local或MSSQLSvc/sql01.domain.local:1433。而这个SPN对应的密钥,就是你手头那个服务账户的NTLM哈希或AES密钥。换句话说,KRBTGT密钥是“防伪水印的印刷母版”,而服务账户密钥是“这把钥匙能打开哪把锁”的物理齿形。

我们来算一笔实操账:假设你通过Mimikatz从某台IIS服务器内存中dump出了IISAppPool\DefaultAppPool账户的NTLM哈希,同时通过whoami /user和nltest /dsgetdc:domain.local组合拿到了域SID和KRBTGT密钥(比如从另一台已被控的DC上导出)。接下来你要伪造一张能访问该IIS服务器上共享目录的白银票据,命令大致如下:

mimikatz # kerberos::golden /domain:domain.local /sid:S-1-5-21-1234567890-1234567890-1234567890 /target:cifs/web01.domain.local /service:cifs /rc4:1234567890abcdef1234567890abcdef /user:fakeuser /id:1100 /ptt

这里/rc4:后面跟的就是服务账户(cifs/web01.domain.local对应的服务账户)的NTLM哈希,而KRBTGT密钥在Mimikatz内部已预置或通过lsadump::dcsync提前获取。/target指定了目标服务主机名,/service指定了SPN类型,/ptt表示直接注入当前会话。

关键点来了:如果你换一个服务,比如想访问SQL Server,就必须换用SQL服务账户的密钥,而不是继续用IIS账户的密钥。KRBTGT密钥可以复用无数次,但每个白银票据都必须绑定对应服务的真实密钥。这就解释了为什么白银票据攻击往往呈现“点状爆发”——攻击者不会泛滥生成,而是精准打击高价值服务,因为每换一个服务,就要重新获取一次该服务账户的凭证。

注意:现代环境中越来越多服务启用AES加密(而非RC4),此时需用/aes128:或/aes256:参数传入对应长度的AES密钥。Mimikatz 2.2+版本支持自动识别密钥类型,但手动构造时务必核对服务账户的msDS-SupportedEncryptionTypes属性,否则票据注入后会出现“KRB_AP_ERR_BAD_INTEGRITY”错误。

我还遇到过一个典型误判案例:某次演练中,红队同学用域管理员账户的哈希生成了针对cifs服务的白银票据,结果无法访问文件共享。排查半天才发现,该文件服务器启用了SMB签名强制策略(Require Security Signature),而白银票据本身不携带签名能力,导致连接被拒绝。这不是票据问题,而是协议层限制——白银票据解决的是“身份认证”问题,但“通信安全”仍由底层协议控制。这种细节,文档里很少提,但实操中踩一次坑就记一辈子。

3. 从内存抓取到票据投递:一次完整的白银票据利用链路还原

理论讲清楚了,现在我们还原一次真实环境下的白银票据利用全过程。这次不是教科书式的理想流程,而是包含真实障碍、绕过技巧和关键验证点的实战记录。场景设定为:你已通过钓鱼邮件攻陷一台普通域成员工作站(Win10,域用户权限),目标是横向移动至一台运行SQL Server的数据库服务器(SQL01),并读取其上的核心业务数据库。

3.1 第一步:定位高价值服务账户并提取凭证

登录被控主机后,第一反应不是急着跑Mimikatz,而是先做资产测绘。执行以下命令快速梳理本地服务:

sc query state= all | findstr "SERVICE_NAME" wmic service get name,pathname,startmode | findstr /i "sql\|iis\|ftp\|cifs"

发现MSSQLSERVER服务正在运行,且启动账户为DOMAIN\sqlsvc。这是一个典型的专用服务账户,权限收敛、密码复杂,但恰恰是白银票据的最佳目标——因为它的密钥不会随用户密码变更而更新(除非重置账户),且常被配置为长期有效。

接下来提取凭证。这里有两个主流路径:

  • 路径A(推荐):使用Mimikatz的sekurlsa::logonpasswords
    直接读取LSASS内存,查找DOMAIN\sqlsvc的logon session。如果该账户近期登录过本机(比如管理员远程调试时用此账户连接过SQL Server),其NTLM哈希大概率驻留内存。实测中约60%的专用服务账户会在首次登录后至少2小时内保留在LSASS中。

  • 路径B(兜底):通过服务配置反查
    如果内存无果,执行:

    sc qc MSSQLSERVER | findstr "OBJNAME"

    得到启动账户名后,用mimikatz # lsadump::sam尝试导出本地SAM,但域环境下通常失败;转而用mimikatz # lsadump::dcsync /user:DOMAIN\sqlsvc——前提是当前用户有DCSync权限(一般没有)。此时更务实的做法是:在本机搜索sqlsvc相关的配置文件、脚本、注册表项(reg query "HKLM\SOFTWARE\Microsoft\Microsoft SQL Server" /s),有时能发现明文密码或加密字符串。

我实际操作中,路径A成功捕获到了sqlsvc的NTLM哈希:a1b2c3d4e5f67890a1b2c3d4e5f67890。下一步是确认该账户是否启用AES加密。查询AD对象属性(需域内LDAP权限):

Get-ADUser -Identity sqlsvc -Properties msDS-SupportedEncryptionTypes | Select-Object msDS-SupportedEncryptionTypes

返回值为24,即同时支持RC4_HMAC_MD5(值为1)和AES128_CTS_HMAC_SHA1_96(值为8)、AES256_CTS_HMAC_SHA1_96(值为16)——总和24。这意味着可以用RC4或AES任一种方式生成票据。考虑到兼容性,我们优先选RC4。

3.2 第二步:收集域环境元数据

凭证有了,还需要三个关键信息:

  • 域FQDN:domain.local(通过echo %USERDNSDOMAIN%或nslookup确认)
  • 域SID:S-1-5-21-1234567890-1234567890-1234567890(通过whoami /user输出的SID前缀获取,去掉末尾RID即可)
  • KRBTGT密钥:这是最难的一环。由于当前只有普通域用户权限,无法DCSync KRBTGT。但我们发现该工作站安装了SQL Server Management Studio(SSMS),且最近一次连接记录中保存了域管理员账户的登录信息(存于Windows凭据管理器)。导出后得到域管理员哈希,再用其执行DCSync:
    mimikatz # lsadump::dcsync /domain:domain.local /user:krbtgt
    成功获取KRBTGT的NTLM哈希(即密钥)。

提示:KRBTGT密钥一旦获取,建议立即导出为离线文件(kerberos::list /export),避免后续操作因权限丢失而中断。它的有效期是永久的,直到管理员主动重置KRBTGT密码。

3.3 第三步:生成并注入白银票据

现在所有材料齐备,执行核心命令:

mimikatz # kerberos::golden /domain:domain.local /sid:S-1-5-21-1234567890-1234567890-1234567890 /target:SQL01.domain.local /service:MSSQLSvc /rc4:a1b2c3d4e5f67890a1b2c3d4e5f67890 /user:attacker /id:1100 /ptt

关键参数说明:

  • /target:必须是SQL Server实际监听的FQDN,不能写IP或短名,否则SPN匹配失败;
  • /service:必须与目标服务注册的SPN完全一致,可通过setspn -L DOMAIN\sqlsvc确认;
  • /user和/id:伪造的用户主体,ID建议避开常见RID(如500管理员、501来宾),选1100这类不敏感值;
  • /ptt:注入到当前会话,无需重启进程。

执行后返回Ticket is injected for 'DOMAIN\attacker' (1100),表示注入成功。

3.4 第四步:验证票据有效性并执行攻击

注入完成后,并不意味着立刻能访问。必须验证票据是否被系统正确加载:

klist

输出中应看到一条类型为Kerberos、Client为DOMAIN\attacker、Server为MSSQLSvc/SQL01.domain.local@DOMAIN.LOCAL的票据,且Key Type为RC4-HMAC (100)。

接着测试访问:

  • 使用sqlcmd -S SQL01.domain.local -E尝试Windows身份验证连接SQL Server;
  • 或用dir \\SQL01.domain.local\C$测试CIFS共享访问(如果该服务账户有相应权限)。

我实测中,sqlcmd成功连接并列出数据库列表。此时所有操作在目标SQL Server日志中均显示为DOMAIN\attacker的合法登录,且Kerberos日志(4769事件)里票据状态为“成功”,无任何异常标记。

注意:如果klist看不到票据,常见原因有三:一是/target与实际SPN不匹配(大小写敏感、域名后缀缺失);二是服务未启用Kerberos(检查SQL Server配置中“Force Encryption”和“Login Auditing”设置);三是本地组策略禁用了Kerberos(极少见,但需排除)。

4. 蓝队视角:为什么传统EDR和SIEM对白银票据近乎“失明”,以及三道硬防线设计

作为经历过多次真实攻防对抗的从业者,我必须坦诚地说:目前市面上90%以上的终端EDR产品,对白银票据攻击的检出率低于5%。这不是厂商技术不行,而是白银票据的攻击逻辑天然规避了绝大多数检测模型的设计前提。

我们来拆解为什么:

  • 它不产生恶意进程:Mimikatz执行时可能被查杀,但票据生成后,所有后续操作(sqlcmd、dir、psexec)都是系统自带的合法工具,调用的是Windows原生Kerberos API(AcquireCredentialsHandle、InitializeSecurityContext),没有任何可疑DLL注入、内存马或PS脚本执行。
  • 它不修改注册表或文件系统:整个过程纯内存操作,不写入磁盘,不创建新服务,不修改ACL,连PowerShell日志(4103/4104)都几乎为零。
  • 它不触发KDC交互异常:黄金票据需要伪造TGT,必然伴随大量DCSync或异常TGT请求;而白银票据完全离线生成,KDC日志(4769事件)里只有正常的TGS请求,且来源IP是普通域成员机——这和员工日常访问文件服务器的行为毫无区别。

那么,蓝队真的束手无策了吗?当然不是。经过在某金融客户环境连续三个月的防守优化,我们总结出三道成本可控、效果显著的硬防线,全部基于现有Windows功能,无需采购新设备:

4.1 防线一:强制服务账户使用AES加密,并禁用RC4(治本之策)

RC4-HMAC是白银票据的温床,因为它的密钥就是NTLM哈希,而NTLM哈希极易从内存、转储文件甚至网络流量中提取。AES密钥则不同:它由密码派生,且Windows默认不将其明文存储在LSASS中(除非启用ProtectPassword组策略)。

实施步骤:

  1. 组策略编辑器 → 计算机配置 → 策略 → Windows设置 → 安全设置 → 本地策略 → 安全选项 → “Network security: Configure encryption types allowed for Kerberos” → 启用并勾选AES128_HMAC_SHA1和AES256_HMAC_SHA1,取消勾选RC4_HMAC_MD5;
  2. 对所有高价值服务账户(SQL、IIS、Exchange等),执行:
    Set-ADAccountControl -Identity sqlsvc -DoesNotRequirePreAuth $false ksetup /SetEncTypeAttr DOMAIN.LOCAL AES128-CTS-HMAC-SHA1-96 AES256-CTS-HMAC-SHA1-96
  3. 重启相关服务,验证klist输出中票据Key Type是否变为AES。

实测效果:当服务只接受AES票据时,攻击者即使拿到NTLM哈希,也无法生成有效白银票据——因为Mimikatz的/rc4:参数失效,而AES密钥无法从内存直接提取。这是成本最低、效果最彻底的防御手段。

4.2 防线二:启用Kerberos审计并建立SPN访问基线(精准狩猎)

既然无法阻止票据生成,那就聚焦于“谁在用票据访问谁”。Windows默认开启的Kerberos审计(事件ID 4769)包含足够多的线索:

  • Service Name:明确标识被访问的服务(如MSSQLSvc/sql01.domain.local);
  • Client Address:发起请求的源IP;
  • Ticket Options:可识别是否为转发票据(0x40000000标志位);
  • Certificate Issuer Name:若启用PKINIT,此处为空则表明非证书认证。

我们为某数据库集群部署了专项规则:

  • 所有对MSSQLSvc/*SPN的4769事件,若Client Address不属于DBA运维网段(如10.10.20.0/24),且Ticket Encryption Type为0x12(RC4)或0x17(AES128),立即触发告警;
  • 结合4624登录事件,比对Logon Process是否为Kerberos,且Authentication Package为Kerberos,排除NTLM中继干扰。

上线一周后,捕获到3起异常:两起来自开发测试机(误配SPN),一起来自被控的CI/CD服务器——正是白银票据的典型特征:非运维IP、高频访问、固定SPN。人工介入后确认为红队测试,验证了规则有效性。

4.3 防线三:服务账户最小权限原则与定期轮换(降低危害面)

白银票据的威力取决于服务账户的权限。如果sqlsvc账户仅对master库有db_datareader权限,那即使票据被滥用,攻击者也拿不到业务数据。

具体实践:

  • 使用Get-ADUser -Identity sqlsvc -Properties MemberOf检查其所属组,移除所有不必要的组(如Domain Admins、Server Operators);
  • 为SQL服务单独创建数据库角色,仅授予SELECT权限;
  • 启用服务账户密码自动轮换(Windows Server 2012 R2+支持Managed Service Accounts,MIMs),轮换周期设为30天,确保即使密钥泄露,有效期也大幅缩短。

我们曾在一个客户环境将SQL服务账户权限从sysadmin降至db_owner,结果红队利用白银票据后,只能看到系统库,核心业务表全部报错“权限不足”。这证明:防御的本质不是杜绝所有漏洞,而是让每个漏洞的利用链条,在抵达最终目标前就断掉一环。

提示:不要迷信“禁用NTLM”。很多老旧应用(如.NET Framework 2.0编译的程序)强制依赖NTLM,盲目禁用会导致业务中断。应采用渐进式策略:先监控NTLM使用场景(通过组策略启用“Network security: Restrict NTLM: Audit NTLM authentication in this domain”),再分批改造。

5. 实战避坑指南:那些文档里绝不会写的12个白银票据致命细节

写到这里,你可能已经掌握了白银票据的理论和基础操作。但我要强调:真正决定一次渗透成败的,从来不是会不会用Mimikatz,而是知不知道哪些地方会悄无声息地让你前功尽弃。以下是我在数十次真实项目中踩过的坑,按严重程度排序,全是血泪教训:

5.1 时间同步误差超过5分钟,票据直接失效(最常被忽略)

Kerberos协议要求客户端与KDC时间差不超过5分钟(默认值)。白银票据虽不依赖KDC签发,但票据中的starttime和endtime字段仍需符合此约束。如果被控主机时间比域控快6分钟,生成的票据在注入后会被目标服务拒绝,报错KRB_AP_ERR_SKEW。

解决方案:执行w32tm /resync /force强制同步时间,或用net time \\DC01 /set /y手动校准。建议在生成票据前,先运行klist purge清空旧票据,再执行时间同步。

5.2 SPN注册不唯一,导致票据被错误路由

一个SPN(如MSSQLSvc/sql01.domain.local:1433)必须在域内全局唯一。如果管理员为多个SQL实例注册了相同SPN,KDC在签发TGS时会随机选择一个账户,导致白银票据注入后访问的是错误的SQL实例。

验证方法:在DC上执行setspn -Q MSSQLSvc/sql01.domain.local:1433,确保只返回一条结果。如有重复,用setspn -D删除冗余注册。

5.3 目标服务未启用Kerberos,回退到NTLM后票据失效

某些服务(尤其是老旧Java应用)默认禁用Kerberos,强制使用NTLM。此时白银票据无法生效,因为NTLM认证不涉及票据交换。

检测方法:用klist tickets确认票据存在后,执行curl -v --negotiate -u : https://appserver.domain.local,观察响应头中是否有WWW-Authenticate: Negotiate。若只有NTLM,则需联系应用方启用SPNEGO。

5.4 服务账户密码已过期,但票据仍可使用(迷惑性陷阱)

白银票据的有效性与服务账户密码状态无关。即使sqlsvc密码已过期,只要其密钥未变,票据依然有效。这会让蓝队误判“账户已失效,风险解除”,实则威胁仍在。

应对:蓝队需监控4724(重置账户密码)事件,而非仅看账户属性中的pwdLastSet。

5.5 使用/ptt注入后,新启动的CMD无法继承票据

/ptt只注入到当前Mimikatz进程的会话,新打开的CMD或PowerShell窗口默认不继承。必须在注入后,用start cmd或powershell -c "klist"验证新进程是否可见票据。

正确做法:注入后立即执行cmd /c "klist && dir \\SQL01.domain.local\C$",确保在同一个shell上下文中完成验证。

5.6 域功能级别低于2008 R2,AES密钥派生算法不同

Windows Server 2008 R2之前,AES密钥由密码直接派生;之后改用PBKDF2算法。如果目标域功能级别为2003,用新版Mimikatz生成的AES票据可能无法解密。

确认方法:netdom query fsmo查看架构主机,再查其OS版本。稳妥起见,统一用RC4生成票据。

5.7 服务账户启用了“Do not require Kerberos preauthentication”

此选项(UF_DONT_REQUIRE_PREAUTH)允许攻击者用AS-REQ爆破密码,但与白银票据无关。然而,如果误以为开启此选项就能简化白银票据利用,会走入误区——白银票据不依赖AS-REQ流程。

5.8 目标主机启用了“Require Mutual Authentication”

某些高安全服务(如AD CS)强制双向认证,要求客户端提供AP-REQ的authenticator,而白银票据的authenticator是静态的,无法满足动态挑战。

绕过:暂时无通用方案,需针对性分析服务实现。

5.9 使用/renewable参数生成的票据,续订时仍需KRBTGT密钥

/renewable只是让票据支持续订,但续订请求(TGS-REQ)仍需KDC用KRBTGT密钥签名。白银票据离线生成,无法完成此步骤,因此该参数实际无效。

5.10 服务账户为Group Managed Service Account(gMSA),密钥由系统托管

gMSA的密钥由KDS(Key Distribution Services)根密钥派生,且不暴露给管理员。目前无公开工具能从gMSA生成白银票据——这是微软设计的硬性防护。

验证:Get-ADServiceAccount -Identity sqlsvc -Properties PrincipalsAllowedToRetrieveManagedPassword,若返回空,则为gMSA。

5.11 票据注入后,klist显示“Tickets found”但访问失败

常见于目标服务启用了SMB签名或TLS强制加密。此时需检查服务端组策略:“Microsoft network client: Digitally sign communications (always)”是否启用。

5.12 最后也是最重要的:别在生产环境乱试,先建隔离域复现

所有操作必须在与生产隔离的测试域中完成。我曾见过团队在客户测试环境直接运行lsadump::dcsync,结果触发了客户EDR的“域控敏感操作”规则,导致整个红队IP被封禁。记住:渗透测试的第一铁律,是永远不破坏客户的生产稳定性。

这些细节,没有一条写在官方文档里,但每一条都足以让一次精心策划的攻击戛然而止。真正的专业,不在于知道多少炫酷的命令,而在于对每一个微小变量的敬畏与掌控。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进