绕过UAC的最复杂方法!
虽然我不常研究这个,但找到新的UAC绕过方法总是很有趣。在阅读Rubeus工具的一些功能时,我意识到可能有一种滥用Kerberos来绕过UAC的方法,至少在域加入系统上是这样。不清楚之前是否有人记录过这种方法,有篇文章似乎讨论了类似的内容,但依赖于从另一个系统执行UAC绕过,而我将要描述的方法可以在本地工作。即使这种技术之前被描述过,我也不确定其底层工作原理是否被记录过。
背景知识
让我们从系统如何阻止你绕过这个最无用的安全功能开始。默认情况下,如果用户是本地管理员,LSASS会过滤任何网络身份验证令牌以移除管理员权限。但有一个重要的例外:如果用户是域用户且是本地管理员,那么LSASS将允许网络身份验证使用完整的管理员令牌。如果你在本地使用Kerberos进行身份验证,这会是一个问题吗?这不就是一个简单的UAC绕过吗?只需以域用户身份向本地服务进行身份验证,你就会获得网络令牌,从而绕过过滤?
实际上不是这样,Kerberos有特定的附加功能来阻止这种攻击向量。如果我要客气一点,我会说这种行为也确保了一定程度的安全性。如果你没有以管理员令牌运行,那么访问SMB环回接口不应该突然授予你管理员权限,从而可能意外破坏你的系统。
去年一月,我读了微软Steve Syfuhs的一篇关于Kerberos如何防止这种本地UAC绕过的文章。简而言之,当用户想要获取服务的Kerberos票据时,LSASS会向KDC发送TGS-REQ请求。在请求中,它会嵌入一些表明用户是本地的安全信息。这些信息将被嵌入到生成的票据中。当该票据用于向同一系统进行身份验证时,Kerberos可以提取这些信息并检查是否与已知信息匹配。如果匹配,它将根据该信息意识到用户未提升权限,并相应地过滤令牌。不幸的是,尽管我很喜欢Steve的文章,但这篇尤其缺乏细节。我猜我得自己找出它的工作原理。
让我们转储Kerberos票据的内容,看看是否能找到票据信息:
|
|
我高亮了两个感兴趣的部分:KERB-AD-RESTRICTION-ENTRY和KERB-LOCAL条目。当然,我不是猜出这些名称的,它们在Microsoft Kerberos协议扩展(MS-KILE)规范中有所记载。KERB_AD_RESTRICTION_ENTRY显然最令人感兴趣,它包含了"LimitedToken"和"Medium Integrity Level"这两个词。
当通过SSPI从网络客户端接受Kerberos AP-REQ时,LSASS中的Kerberos模块将调用LSA函数LsaISetSupplementalTokenInfo,以根据需要将KERB-AD-RESTRICTION-ENTRY中的信息应用到令牌上。相关代码大致如下:
|
|
我高亮了此函数中的三个主要检查:第一个比较KERB-AD-RESTRICTION-ENTRY的MachineID字段是否与LSASS中存储的匹配。如果匹配,则设置bLoopback标志。然后它检查一个据我所知未记录的LSA标志以过滤所有网络令牌,此时它将检查LimitedToken标志并相应设置bFilterToken标志。此过滤模式默认关闭,因此通常bFilterToken不会被设置。
最后,代码查询当前创建的令牌SID,并检查以下任一条件是否为真:
- 用户SID不是本地帐户域的成员。
- LocalAccountTokenFilterPolicy LSA策略非零,这会禁用本地帐户过滤。
- 产品类型是NtProductLanManNt,这实际上对应于域控制器。
如果任一条件为真,那么只要令牌信息既不是环回也不是强制过滤,函数将返回成功,不会进行过滤。因此,在默认安装中,域用户不被过滤取决于机器ID是否匹配。
对于完整性级别,如果正在进行过滤,则将其降至KERB-AD-RESTRICTION-ENTRY认证数据中的值。但它不会将完整性级别提高到创建的令牌默认拥有的级别之上,因此不能被滥用以获得系统完整性。
注意,Kerberos将首先使用AP-REQ中票据的KERB-AD-RESTRICTION-ENTRY认证数据调用LsaISetSupplementalTokenInfo。如果该条目不存在,则它将尝试使用验证器中的条目进行调用。如果票据和验证器都没有条目,则永远不会调用该函数。我们如何移除这些值呢?
好吧,关于这个!
如何滥用此机制绕过UAC?
假设你作为域用户通过身份验证,最有趣的滥用方式是使机器ID检查失败。我们该怎么做?LsapGlobalMachineID值是LSASS启动时生成的随机值。我们可以利用这样一个事实:如果你查询用户的本地Kerberos票据缓存,即使你不是管理员,它也会返回服务票据的会话密钥(默认情况下不会返回TGT会话密钥)。
因此,一种方法是为本地系统生成服务票据,将生成的KRB-CRED保存到磁盘,重启系统以使LSASS重新初始化,然后在回到系统后重新加载票据。该票据现在将具有不同的机器ID,因此Kerberos将忽略限制条目。你可以使用内置的klist和Rubeus通过以下命令实现:
|
|
你可以使用Kerberos身份验证通过命名管道或TCP访问SCM,使用RPC/HOSTNAME SPN。注意,SCM的Win32 API始终使用Negotiate身份验证,这带来了一些麻烦,但有替代的RPC客户端;-) 虽然LSASS会在AP-REQ的验证器中添加有效的限制条目,但由于票据中的条目将首先被使用,而该条目会因机器ID不同而应用失败,因此它不会被使用。
另一种方法是生成我们自己的票据,但我们不需要凭据吗?有一个技巧,我相信是由Benjamin Delpy发现并放入kekeo中的,它允许你滥用无约束委派来获取带有会话密钥的本地TGT。有了这个TGT,你可以生成自己的服务票据,因此你可以执行以下操作:
- 使用委派技巧查询用户的TGT。
- 使用TGT向KDC请求本地计算机的新服务票据。添加一个KERB-AD-RESTRICTION-ENTRY但填入伪造的机器ID。
- 将服务票据导入缓存。
- 访问SCM以绕过UAC。
最终,对于UAC绕过来说,这是相当多的代码,至少与仅仅更改环境变量相比。但是,你可能可以使用现有工具(如kekeo和Rubeus)拼凑出解决方案,但我不打算发布一个现成的工具来做到这一点,你得靠自己了 :-)
你忘了KERB-LOCAL吗?
KERB-LOCAL的目的是什么?它是一种重用本地用户凭据的方式,类似于NTLM环回,LSASS能够确定调用实际上来自本地认证用户并使用他们的交互式令牌。传递在票据和验证器中的值可以根据Kerberos包中已知凭据列表进行检查,如果匹配,则将使用现有令牌。
这难道不是总是消除了基于KERB-AD-RESTRICTION-ENTRY值过滤令牌的需要吗?由于其设计方式,这种行为似乎很少被使用。首先,它仅在接受服务器使用Negotiate包时有效,如果直接使用Kerberos包则无效(有点…)。这通常不是障碍,因为大多数本地服务为了方便而使用Negotiate。
真正的问题在于,作为规则,如果你作为客户端使用Negotiate到本地机器,它将默认选择NTLM。这将使用已经内置到NTLM中的环回,而不是Kerberos,因此此功能不会被使用。注意,即使NTLM在域网络上被全局禁用,它仍然适用于本地环回身份验证。我猜KERB-LOCAL是为了与NTLM的功能对等而添加的。
回到博客开头的格式化票据,KERB-LOCAL值意味着什么?它可以解包为两个64位值,0x17E3303CE60和0x3976FC25。第一个值是LSASS堆中KERB_CREDENTIAL结构的堆地址!!第二个值是创建KERB-LOCAL结构时的票据计数。
幸运的是,LSSAS并不只是解引用凭据指针,它必须在有效凭据结构列表中。但这个值没有被盲化或引用随机生成的值似乎是一个错误,因为堆地址相当容易暴力破解。当然,这并不那么简单,Kerberos确实验证了票据PAC中的SID与凭据中的SID匹配,因此你不能只是欺骗SYSTEM会话,但是,好吧,我把这个留作一个思考点。
希望这能让你更深入了解这个功能的工作原理,以及你可以用新方法尝试绕过UAC的一些乐趣。
更新:这个简单的C++文件可用于修改Win32 SCM API以使用Kerberos进行本地身份验证。