深入挖掘已经在
客户端/服务器应用程序中讨论过的 Kerberos 约束委派,如何以域用户的身份在远程系统上创建进程而不将该用户的用户名/密码传输到远程系统?
使用 SSPI 支持多进程的 kerberos 约束委派
我有一个分布式应用程序在多个服务器上工作,并通过 Kerberos 令牌依赖 SSO 进行用户身份验证,并且所有内容都按照上述线程中的讨论进行布局(和工作)。简单来说,
- 用户连接到在 Server1 上运行的服务
- Server1 会将用户的作业分派给 Server2,后者正在服务主体帐户
a 下运行另一个服务。Server1 向相关 SPN 请求(并获取)一张票证
b。Server1 将票据传输到 Server 2 - Server2 解析该票证(即AcquireCredentialsHandle和AcceptSecurityContext),然后调用QuerySecurityContextToken,然后是DuplicateHandle, CreateProcess,将重复句柄传递给子进程,然后子进程调用ImpersonateLoggedOnUser
- Server2 上的子进程现在正在模拟原始用户运行,并且能够以某些 Server3 上的用户身份访问网络资源
所以,一切都很好……直到它不再起作用。在步骤 2a 中获得的服务票证的生命周期最长为 10 小时(假设 AD 设置为服务票证的默认 10 小时有效期)。票证生命周期有时远低于 10 小时的原因是因为步骤 1 和步骤 2 之间可能存在显着延迟,例如,用户可能会在提交作业进行处理之前进行一整天的准备工作。因此,服务票证的结束时间将是从原始用户登录时间算起的 10 小时,即与用户连接时生成的 TGT 的结束时间相匹配。
服务票证到期前大约 5 分钟,Server2 似乎尝试更新此票证,并且新票证确实出现在klist中,用于 Server2 上子进程的 LUID。然而,这个新的票据似乎“格式错误”,此时客户端进程失去了访问网络资源的能力,因为用户被冒充。具体来说,尽管客户端进程仍然持有到 Server3 资源的有效 Kerberos 服务票证,但当从 Server2 到达 Server3 时,它会从 Kerberos 身份验证下降到 NTLM 身份验证,此时它被 Server3 拒绝。
这是失败时在 Server2 上运行子进程的 LUID 的klist输出示例;
Current LogonId is 0:0x5777e
Targeted LogonId is 0:0x3966b5
Cached Tickets: (5)
#0> Client: user @ VNET.COM
Server: MSSQLSvc/sql.vnet.com:1433 @ VNET.COM
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:21:02 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0
Kdc Called: DC.Vnet.com
#1> Client: user @ VNET.COM
Server: ldap/DC.Vnet.com/Vnet.com @ VNET.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a50000 -> forwardable renewable pre_authent ok_as_delegate name_canonicalize
Start Time: 2/20/2020 22:21:02 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called: DC.Vnet.com
#2> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0xa10000 -> renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
#3> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0xa10000 -> renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
#4> Client: user @ VNET.COM
Server: SVCD/APP.Vnet.com @ VNET.COM
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:11:39 (local)
End Time: 2/20/2020 22:26:39 (local)
Renew Time: 0
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x8 -> ASC
Kdc Called:
在上面的清单中,票证#4 是步骤 2a 中请求的原始服务票证;SPN 是“<em>SVCD/APP.Vnet.com”,与此 SPN(并运行 Server2 服务进程)关联的域帐户是“<em>svc”。此票证用于在 Server2 上创建用户的安全上下文,并且子进程正在模拟该安全上下文。当子进程尝试访问 LDAP 和 MS SQL 服务器(用于子进程需要执行的工作)时,在模拟之后生成票证 #0 和 #1,因此这确认所有约束委派设置都很好并且子进程正在运行正如预期的那样长达 10 小时。在某些情况下,票 #0 和 #1 需要续订 - 它们已成功续订,并且该过程继续进行。
现在,问题是:ticktes #2 和 #3 是在 #4 结束前几分钟生成的,但我觉得奇怪的是 ServerRealm 部分,即“<em>svc @ ...</em>”是空白的。此外,在生成这些票证的那一刻,Server2 子进程停止能够打开与 Server3 的新 MS SQL 连接(并且在 Server3 上,匿名登录拒绝事件会被记录并带有匹配的时间戳)。我还应该提到,虽然在上面的示例中,“<em>Server: svc @”有两个相同的票证,但在某些情况下,我看到了 7、14 个,有时甚至是 30 多个类似的票证。全部同时发布,好像 Server2 疯狂地尝试从 KDC 获取所需的内容,但失败了。
我的解释是 Server2 想要更新在模拟中使用的服务票证,但没有这样做。
在这一点上,我不确定问题是否在;
a) AD 设置(即,具有受限委派详细信息),或
b) “<em>svc”域帐户的权限(它具有SetImpersonatePrivilege但可能需要其他内容),或
c) 传输用户安全上下文的方式Server2 中的父进程和子进程之间,或者
d) 完全不同的东西
到目前为止,在阅读和研究了相当长的时间之后,我尝试了 c) 的各种序列排列(例如,使用DuplicateTokenEx + CreateProcessAsUser代替,翻转各种标志以获取重复的句柄和令牌等),但我我不知道我可以并且应该用 a) 和 b) 做什么(如果有的话)。我尝试更改一些设置,但没有任何效果,但我避免使用“核”选项,例如在svc帐户上设置SeTcbPrivilege ,因为在我的情况下这不是可接受的解决方案。
最后一个观察结果是票证 #4 缺少“<em>Kdc Called”和“<em>Renew Time”,但我认为这是通过InitializeSecurityContext获得的不透明票证的正常现象。
为了让 Server2 上的子进程运行超过原来的 10 小时,我需要更改什么?