以最复杂的方式绕过 UAC

2022-03-25 11:12:51 浏览数 (2)

背景!

让我们从系统如何防止您绕过最无意义的安全功能开始。默认情况下,如果用户是本地管理员,LSASS 将过滤任何网络身份验证令牌以删除管理员权限。但是有一个重要的例外,如果用户是域用户和本地管理员,则 LSASS 将允许网络身份验证使用完整的管理员令牌。如果说您使用Kerberos在本地进行身份验证,这将是一个问题。这不是微不足道的 UAC 绕过吗?只需以域用户身份向本地服务进行身份验证,您就会获得绕过过滤的网络令牌?

不,Kerberos具有特定的附加功能来阻止这种攻击媒介。如果我是慈善家,我会说这种行为也确保了一定程度的安全。如果您没有以管理员令牌的身份运行,那么访问 SMB 环回接口不应突然授予您管理员权限,通过该权限您可能会意外破坏您的系统。

早在去年 1 月,我就阅读了  Microsoft 的 Steve  Syfuhs的一篇文章,内容是Kerberos如何防止这种本地 UAC 绕过。TL;DR; 当用户想要获得服务的Kerberos票证时,LSASS 将向 KDC 发送 TGS-REQ 请求。在请求中,它将嵌入一些表明用户是本地用户的安全信息。此信息将嵌入到生成的工单中。 

当该票证用于对同一系统进行身份验证时,Kerberos可以提取信息并查看它是否与它知道的信息匹配。如果是这样,它将获取该信息并意识到用户没有被提升并适当地过滤令牌。不幸的是,尽管很喜欢史蒂夫的帖子,但这篇文章对细节特别轻。我想我必须自己追踪它是如何工作的。让我们转储Kerberos票证的内容,看看我们是否可以看到票证信息:

PS> $c = New-LsaCredentialHandle -Package 'Kerberos' -UseFlag Outbound

PS> $x = New-LsaClientContext -CredHandle $c -Target HOST/$env:COMPUTERNAME

PS> $key = Get-KerberosKey -HexKey 'XXX' -KeyType AES256_CTS_HMAC_SHA1_96 -Principal $env:COMPTUERNAME

PS> $u = Unprotect-LsaAuthToken -Token $x.Token -Key $key

PS>格式-LsaAuthToken $u

<KerberosV5 KRB_AP_REQ>

选项:无

<门票>

门票版本:5

...

<授权数据 - KERB_AD_RESTRICTION_ENTRY>

标志:LimitedToken

诚信等级:中

机器编号:6640665F...

<授权数据 - KERB_LOCAL>

安全上下文:60CE03337E01000025FC763900000000

我已经突出显示了两个感兴趣的条目,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的信息应用到令牌(如果需要)。相关代码大致如下:

代码语言:javascript复制
NTSTATUS LsaISetSupplementalTokenInfo(PHANDLE phToken, 
                        PLSAP_TOKEN_INFO_INTEGRITY pTokenInfo) {
  // ...
  BOOL bLoopback = FALSE:
  BOOL bFilterNetworkTokens = FALSE;
  if (!memcmp(&LsapGlobalMachineID, pTokenInfo->MachineID,
       sizeof(LsapGlobalMachineID))) {
    bLoopback = TRUE;
  }
  if (LsapGlobalFilterNetworkAuthenticationTokens) {
    if (pTokenInfo->Flags & LimitedToken) {
      bFilterToken = TRUE;
    }
  }
  PSID 用户 = GetUserSid(*phToken);
  如果(!RtlEqualPrefixSid(LsapAccountDomainMemberSid,用户)
    || LsapGlobalLocalAccountTokenFilterPolicy 
    || NegProductType == NtProductLanManNt) {
    if ( !bFilterToken && !bLoopback )
      返回状态_成功;
  }
  /// 如果需要,过滤令牌并降低完整性级别。
}

我已经强调了这个函数中的三个主要检查,第一个比较KERB-AD-RESTRICTION-ENTRY的MachineID字段 是否与存储在 LSASS 中的匹配。如果是,则设置bLoopback标志。然后它检查 AFAIK 未记录的 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将忽略限制条目。您可以使用内置klistRubeus使用以下命令来完成:

PS> klist 获取 RPC/$env:COMPUTERNAME

PS> Rubeus.exe /dump /server:$env:COMPUTERNAME /nowrap

... 将 base64 票证复制到文件中。

然后重启:

PS> Rubeus.exe ptt /ticket:<BASE64 TICKET> 

您可以使用Kerberos身份验证通过命名管道或使用RPC/HOSTNAME SPN的 TCP 访问 SCM 。请注意,SCM 的 Win32 API 始终使用Negotiate身份验证,这会在工作中引发扳手,但还有其他 RPC 客户端;-) 虽然 LSASS 将在 AP-REQ 中的身份验证器中添加一个有效的限制条目,但它不会被使用因为票证中的那个会先被使用,由于机器ID不同而无法申请。

另一种方法是生成我们自己的票证,但我们不需要凭据吗?我相信 Benjamin Delpy发现了一个技巧并将其放入kekeo,它允许您滥用无约束委托来获取具有会话密钥的本地 TGT。使用此 TGT,您可以生成自己的服务票证,因此您可以执行以下操作:

  1. 使用委托技巧查询用户的 TGT。
  2. 使用 TGT 向 KDC 请求本地计算机的新服务票证。添加一个 KERB-AD-RESTRICTION-ENTRY但填写一个伪造的机器 ID。
  3. 将服务票证导入缓存。
  4. 访问 SCM 以绕过 UAC。

最终,这是一个合理数量的 UAC 绕过代码,至少与刚刚更改环境变量相比。但是,您可能可以使用kekeoRubeus等现有工具将其组合在一起,但我不会发布一个交钥匙工具来做到这一点,您需要靠自己 :-)

你没忘记 KERB-LOCAL 吗?

KERB-LOCAL的目的是什么?这是一种重用本地用户凭据的方式,这类似于 NTLM 环回,其中 LSASS 能够确定调用实际上来自本地经过身份验证的用户并使用他们的交互式令牌。可以根据 Kerberos 包中的已知凭据列表检查票证和身份验证器中传递的值,如果匹配,则将使用现有令牌。

这不会总是消除基于 KERB-AD-RESTRICTION-ENTRY值过滤令牌的需要吗?由于它的设计方式,这种行为似乎很少使用。首先,它仅在接受服务器使用Negotiate包时才有效,如果直接使用Kerberos包则不起作用(有点......)。这通常不是障碍,因为大多数本地服务都使用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 进行本地身份验证。

0 人点赞