CVE-2023-29357 – Microsoft SharePoint ValidateTokenIssuer 身份验证绕过漏洞分析
2023-9-1 16:22:0 Author: paper.seebug.org(查看原文) 阅读量:253 收藏

原文链接:Phân tích CVE-2023-29357 – Microsoft SharePoint ValidateTokenIssuer Authentication Bypass Vulnerability
译者:知道创宇404实验室翻译组

CVE 简要说明

CVE-2023-29357它允许攻击者绕过身份验证并升级权限,是一个影响SharePoint使用的漏洞。由于未正确验证 JWT 令牌的签名,该漏洞存在于 ValidateTokenIssuer 方法内部。

受影响的版本为:小于16.0.10399.20005。

相关公告:

解决办法

  • 升级到最新版本的SharePoint。
  • 启用AMSI集成功能并使用Windows Defender。

具体分析

SPJsonWebSecurityBaseTokenHandler类中添加MissingAlgorithm枚举,以覆盖传入的令牌缺少算法的情况。

img

重写ReadToken方法,并调用SPAuthenticationAlgorithmValidator.ValidateAlgorithm

img

ValidateAlgorithm继续调用HasValidAlgorithm方法来检查JWT中的alg的值。

img

ZDI的公告中也描述了该漏洞存在于ValidateTokenIssuer方法中。补丁代码添加了调用SPClaimsUtility.IsEnableOldHashedProofTokenFormat方法的代码段。

img

img

调用堆栈到ValidateTokenIssuer

img

基于以上信息,可以用该算法制作 JWT 令牌并执行与 JWT 发行者( JWT 令牌 none 值)相关的操作。

为了进行身份验证,SharePoint会从以下两个位置获取令牌: GET param prooftoken/headerX-PROOF_TOKEN和 header Authorization。

img

该令牌需要具有以下值:

img

  • ver: giá trị phải là hashedprooftoken.

  • nbfexp: JWT 令牌的当前时间值和过期时间

  • audiss: 是目标受众和发行者的值,这里必须是00000003-0000-0ff1-ce00-000000000000。该值00000003-0000-0ff1-ce00-000000000000代表Office 365 SharePoint Online的应用程序ID,其也可以在本地部署的SharePoint版本中使用。

img

图片来源:https://learn.microsoft.com/en-us/troubleshoot/azure/active-directory/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications
  • realm: 这个值通过向API发送Authorization中的令牌值的请求,其会泄露该值。

img

在尝试使用上述格式发送JWT后,SharePoint识别出当前用户是“SharePoint App”。

img

img

虽然用户已经成功认证SharePoint App,但该漏洞的目的是我们需要冒充farmadmin账户。使用/_api/web/siteusers端点列出当前站点上具有权限的用户。

img

为了模拟其他账户,我们需要修改proof token中的nameid字段.此时,我们的proof token如下所示:

img

在使用新令牌进行请求后,进程报错Specified method is not supported

img

进行调试找出原因,异常在SPApplicationPrincipalName.CreateFromString方法中显现。

img

主要原因是我们当前的值applicationPrincipleName没有@字符,因此无法拆分成长度为2的数组。

img

根据堆栈跟踪定位到SPApplicationPrincipalName.CreateFromString方法

从堆栈跟踪向上追溯一点,SharePoint会检查SPAppRequestContext.Current是否有效,如果有效,则调用SPAppRequestContext.Current.ClientIdSPApplicationPrincipalName.CreateFromString,如上面的堆栈跟踪截图所示。

img

因此,只需要将SPAppRequestContext.Current的值设置为null,就不会再调用ClientId了。

经过一段时间的调试,我发现SPAppRequestContext.InitCurrent方法负责给SPAppRequestContext.Current赋值。其中调用了SPApplicationRequestHelper.IsApplicationRequest方法来检查发送的请求是否是“应用程序请求”。

img

该方法如下:

img

在这里,我们只需要关注spincomingOAuthIdentityType两个常量SPIncomingOAuthIdentityType.UserAndApplicationSPIncomingOAuthIdentityType.ApplicationOnly进行比较。只要我们的请求不符合这两个条件,SPAppRequestContext.Current就是null

为了使spincomingOAuthIdentityType不等于上述两个值,我们需要关注SPIncomingTokenContext.SetIdentityType方法。该方法通过我们发送的proof token来确定我们的token是用户还是应用程序。

img

经过一段时间的调试,我们发现当我的proof token中的isuser字段的值为true时,可以将claimsIdentity.Actor的值设置为null,从而不进入if语句的内部代码块。

img

然后,程序继续执行到下面的SPIncomingTokenContext.IsProofToken方法,该方法检查proof token中的tt字段,如果该字段不存在,则跳过并返回false

img

因此,我们成功将IdentityType设置为UserOnly而不是UserAndApplicationApplicationOnly

img

此时,SPApplicationRequestHelper.IsApplicationRequest的返回值为false,app请求上下文设置为null

img

img

至此认证已经成功。

img

目前的proof token是:

img

在使用新的令牌重新尝试后,结果如下:

img

成功模拟farmadmin账户后,我们可以继续利用CVE-2023-24955来RCE,这个漏洞我会在下一篇博文中写到。


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/3021/



文章来源: https://paper.seebug.org/3021/
如有侵权请联系:admin#unsafe.sh