“Game of Rars” – 通过概念验证探索 WinRAR 中新的远程代码执行漏洞 (CVE-2023-40477) –
2023-9-2 12:45:28 Author: Ots安全(查看原文) 阅读量:21 收藏

执行摘要

  • WinRAR 拥有超过 500 亿用户,面临新漏洞(CVE-2023-40477、CVE-2023-38831)。
  • 今天,我们首次展示:CVE-2023-40477 的 PoC(撰写本文时)
  • 尽管 RCE 被认为是可利用的,但由于多种原因,它在现实中的影响看起来并不乐观。
  • 我们在此介绍全面的技术研究:其影响、可利用的场景和缓解措施。
  • 该漏洞已在最近的 Winrar v6.23 中修复,我们在这里还提供了另一种缓解措施

CVE-2023-40477:技术概述和概念验证

现在是 8 月中旬,Winrar 6.23 发布了,并带有一些关于严重漏洞的模糊警报。
我们所知道的是 – 漏洞 (CVE-2023-40477) 已修复,并且以下信息:
配备 BinDiff、IDA 和记事本,让我们深入研究。

比较二进制文件

我们知道 6.23 已修复,让我们尝试查找修复前后的最小版本,以便我们可以观察它。我已经下载了便携式 winrar-v6.23 + winrar-v6.22 并观察了它:

Winrar 目录结构和有趣的文件
人们可以立即观察到 winrar.exe 可能只是一个 GUI,如果提取中存在漏洞 - 它也可能存在于“unrar.exe”中。比较 6.23 和 6.22 给了我以下差异(忽略评论;)):
第一个 Bindiff 输出
通过查看流程图,我在 6.23 中添加了一些有趣的内容(在大函数图中——看起来像是主要的提取):
提取物中的高级 Bindiff 添加
仔细一看好像这些都是额外的检查!
Bindiff 的 x86 有趣的附加块

这看起来很有希望!我们在这里看到一些 var < 255 的额外检查!有趣的。看起来这里有溢出检查权限。
因此,是时候触发了(即将字节更改为最大值)。

我查看了 RAR 格式,从描述中我们知道这与 RAR4(vol3?)恢复卷有关,
因此我生成了具有这些功能的 RAR4,它给了我一个文件列表,如下所示:

  • RAR_FILE.rar
  • RAR_FILE.r00
  • RAR_FILE00.rev
  • RAR_FILE.r01
  • RAR_FILE01.rev

我尝试暴力破解“.rev”和“rXX”卷中任何“类字节”值的内容,但没有成功。它没有触发或改变任何东西。
然后,我尝试谷歌搜索一些“unrar”源代码——也许它作为其他项目的一部分存在?!
成功!我找到了这个旧存储库:https://github.com/aawc/unrar

现在查看源代码,我们看到多个“255”常量检查,特别是在“recvol3.cpp”中,它们也出现在原始 6.22 源代码,所以也许他们添加了额外的源代码,因为……溢出?
让我们检查一下,更深入地研究,我发现安全检查实际上与 0xff / 255 相关。

漏洞

recvol3.cpp 内的 CVE-2023-40477
这里,P[i]是从“.rev”文件本身中提取的。它们位于文件末尾。
这些P[i]用于确定它们代表哪个恢复卷以及它们适合什么FileNumber 。
FileNumber也在P[2]中从它们检索。
紧接着,File*被分配并放置在我们控制的大小为 256 的数组中的索引中!(第 241 行)。
这就解释了 255 次检查。
因为索引实际上等于:P[2]+P[0]-1。我们几乎可以通过“rev”卷内容任意控制它。
所以,毕竟,我们可以用指针覆盖该缓冲区(指向文件结构),它们会覆盖当前对象中的下一个属性。

PoC 编写

为了触发该漏洞,我们发现需要在recvol3.cpp中调用“Restore()”。
我们发现我们还需要进行重建步骤,因此将通过覆盖指针来完成一些操作。

为此,需要有一些缺失的 rar 卷(缺少 .r00)和 .rev 卷可用。
另外,我们需要确保 crc32 校验和正确,这意味着只需触发几行。
为了方便起见,我们使用了通过 GUI 生成的原始 rar4 恢复卷,但这肯定可以更小且更高效,最多可能包含 2-3 个文件。

# 1. re-generate malformed recovery vols.data = open('%s01.rev' % ARCHIVE_NAME, 'rb').read() # just use the first and malform it up.names = ['%s%s.rev' % (ARCHIVE_NAME, str(i).zfill(2)) for i in range(256)]# "destroy" the P[i]'sdatas = [data[:-7] + bytes([0xf0, 0x00, i]) + calc_crc(data[:-7] + bytes([0xf0, 0x00, i])) for i in range(256)]
# 2. overwrite malformed recovery vols.for i in range(256): fname = names[i] data = datas[i] open(fname, 'wb').write(data)
我们的 PoC @ https://github.com/wildptr-io/Winrar-CVE-2023-40477-POC/

找到它后不久,我们还在 rar-labs 网站上看到了https://www.rarlab.com/vuln_rev3_names.html,这很有可能证实了我们的发现。

使用它,我们在几种情况下成功地崩溃了 winrar / unrar:

1.Memset 用零覆盖无效内存(可能在缓冲区之后):
使用 winrar 的 unrar.exe 时崩溃 – 在Buf的 memset 上
来自源代码 – Buf的 memset
2.使用“提取到”时 winrar.exe 中可能发生堆溢出的情况
winrar.exe 中的堆溢出 – 可能的情况

可利用吗?

为了确定可利用性,让我们看看我们在 256 数组之后重写的结构。
让我们确定攻击者如何使用此原语来获取 RCE 以及存在哪些缓解措施。
// RecVolume3 struct - that gets overflowedclass RecVolumes3{ private: File *SrcFile[256]; // overflow in here with File* pointers. Array Buf;
#ifdef RAR_SMP ThreadPool *RSThreadPool;#endif public: RecVolumes3(CommandData *Cmd,bool TestOnly); ~RecVolumes3(); void Make(CommandData *Cmd,wchar *ArcName); bool Restore(CommandData *Cmd,const wchar *Name,bool Silent); void Test(CommandData *Cmd,const wchar *Name);};......// Array template class:template class Array{ private: T *Buffer; size_t BufSize; size_t AllocSize; size_t MaxSize; public: Array(); Array(size_t Size); Array(const Array &Src); // Copy constructor. ~Array();
所以,毕竟,我们用“File*”指针溢出了“Buffer”对象。
这很好,但还不够,人们可能需要绕过此处启用的许多防御措施。
幸运的是,里面有很多保护措施:ASLR、CFG、Stack-Cookie 和 DEP。
这还没有提及 winrar 版本之间的二进制差异。所有这些都使得利用成为可能,但对于普通威胁行为者来说可能性不大。

感谢您抽出

.

.

来阅读本文

点它,分享点赞在看都在这里


文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMjYyMzkwOA==&mid=2247501220&idx=3&sn=964292d264a5e7fe5dd29ac68513bcb1&chksm=9bad8cefacda05f9ceb10664e432aeffe1de7a0934d847aacc7fb0c3c432d08ce9191d1e62fa&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh