CVE-2023-29357 – Microsoft SharePoint ValidateTokenIssuer 身份验证绕过漏洞分析
source link: https://paper.seebug.org/3021/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
原文链接: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
枚举,以覆盖传入的令牌缺少算法的情况。
重写ReadToken
方法,并调用SPAuthenticationAlgorithmValidator.ValidateAlgorithm
。
ValidateAlgorithm
继续调用HasValidAlgorithm
方法来检查JWT中的alg
的值。
ZDI的公告中也描述了该漏洞存在于ValidateTokenIssuer
方法中。补丁代码添加了调用SPClaimsUtility.IsEnableOldHashedProofTokenFormat
方法的代码段。
调用堆栈到ValidateTokenIssuer
:
基于以上信息,可以用该算法制作 JWT 令牌并执行与 JWT 发行者( JWT 令牌 none 值)相关的操作。
为了进行身份验证,SharePoint会从以下两个位置获取令牌: GET param prooftoken/headerX-PROOF_TOKEN和 header Authorization。
该令牌需要具有以下值:
-
ver
: giá trị phải làhashedprooftoken
. -
nbf
和exp
: JWT 令牌的当前时间值和过期时间 -
aud
和iss
: 是目标受众和发行者的值,这里必须是00000003-0000-0ff1-ce00-000000000000
。该值00000003-0000-0ff1-ce00-000000000000
代表Office 365 SharePoint Online的应用程序ID,其也可以在本地部署的SharePoint版本中使用。
realm
: 这个值通过向API发送Authorization中的令牌值的请求,其会泄露该值。
在尝试使用上述格式发送JWT后,SharePoint识别出当前用户是“SharePoint App”。
虽然用户已经成功认证SharePoint App
,但该漏洞的目的是我们需要冒充farmadmin账户。使用/_api/web/siteusers
端点列出当前站点上具有权限的用户。
为了模拟其他账户,我们需要修改proof token中的nameid
字段.此时,我们的proof token如下所示:
在使用新令牌进行请求后,进程报错Specified method is not supported
。
进行调试找出原因,异常在SPApplicationPrincipalName.CreateFromString
方法中显现。
主要原因是我们当前的值applicationPrincipleName
没有@
字符,因此无法拆分成长度为2的数组。
根据堆栈跟踪定位到SPApplicationPrincipalName.CreateFromString
方法
从堆栈跟踪向上追溯一点,SharePoint会检查SPAppRequestContext.Current
是否有效,如果有效,则调用SPAppRequestContext.Current.ClientId
⇒ SPApplicationPrincipalName.CreateFromString
,如上面的堆栈跟踪截图所示。
因此,只需要将SPAppRequestContext.Current
的值设置为null
,就不会再调用ClientId
了。
经过一段时间的调试,我发现SPAppRequestContext.InitCurrent
方法负责给SPAppRequestContext.Current
赋值。其中调用了SPApplicationRequestHelper.IsApplicationRequest
方法来检查发送的请求是否是“应用程序请求”。
该方法如下:
在这里,我们只需要关注spincomingOAuthIdentityType
两个常量SPIncomingOAuthIdentityType.UserAndApplication
和SPIncomingOAuthIdentityType.ApplicationOnly
进行比较。只要我们的请求不符合这两个条件,SPAppRequestContext.Current
就是null
。
为了使spincomingOAuthIdentityType
不等于上述两个值,我们需要关注SPIncomingTokenContext.SetIdentityType
方法。该方法通过我们发送的proof token来确定我们的token是用户还是应用程序。
经过一段时间的调试,我们发现当我的proof token中的isuser
字段的值为true
时,可以将claimsIdentity.Actor
的值设置为null
,从而不进入if语句的内部代码块。
然后,程序继续执行到下面的SPIncomingTokenContext.IsProofToken
方法,该方法检查proof token中的tt
字段,如果该字段不存在,则跳过并返回false
。
因此,我们成功将IdentityType
设置为UserOnly
而不是UserAndApplication
或ApplicationOnly
。
此时,SPApplicationRequestHelper.IsApplicationRequest
的返回值为false
,app请求上下文设置为null
。
至此认证已经成功。
目前的proof token是:
在使用新的令牌重新尝试后,结果如下:
成功模拟farmadmin账户后,我们可以继续利用CVE-2023-24955来RCE,这个漏洞我会在下一篇博文中写到。
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/3021/
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK