“Game of Rars” – 通过概念验证探索 WinRAR 中新的远程代码执行漏洞
- WinRAR 拥有超过 500 亿用户,面临新漏洞(CVE-2023-40477、CVE-2023-38831)。
- 今天,我们首次展示:CVE-2023-40477 的 PoC。
- 尽管 RCE 被认为是可利用的,但由于多种原因,其在实现过程中看起来并不乐观。
- 我们在此展示全面的技术研究:其影响、可利用的场景和缓解措施。
- 该漏洞已在最近的 WinRAR v6.23 中修复,我们在这里还提供了另一种缓解措施。
CVE-2023-40477:技术概述和概念验证
8月2号,Winrar 6.23 发布了更新,并带有一些关于严重漏洞的模糊警报。
我们所知道的是 – 漏洞 (CVE-2023-40477) 已修复,如图:
配备 BinDiff、IDA 和记事本,让我们深入研究。
比较二进制文件
我们知道 v6.23 已修复了该漏洞,那么让我们尝试查找修复前后的版本,以便我们可以观察它。winrar-v6.22 与 winrar-v6.23 :

可以观察到 winrar.exe 只是一个 GUI,如果是解压缩中的漏洞 - 它也可能存在于“unrar.exe”中。比较 6.23 和 6.22 提供了以下差异:

在 6.23 中,通过查看流程图给了我几个有趣的补充(在大功能图中,看起来像是主提取):

仔细看,这些似乎是额外的检查!

这看起来很有希望!我们在这里看到一些 var < 255 的额外检查!有趣的是,看起来这里有溢出检查权限。
因此,触发时间到了(即将字节更改为最大值)。
我已经看过RAR格式,从描述中我们知道这与RAR4(vol3?)恢复卷有关,
所以我用这些特性生成了RAR4,它给了我一个文件列表,如下所示:
- RAR文件.RAR
- RAR_文件.r00
- RAR_FILE00.rev版本
- RAR_文件.r01
- RAR_FILE01.rev版
我曾试图强行删除“.rev”和“rXX”卷中任何“类字节”值的内容,但没有成功。它没有触发或改变任何事情。
然后,我试着用谷歌搜索一些“unrar”源代码——也许它是作为其他项目的一部分存在的?!
于是我成功找到了这个旧存储库:https://github.com/aawc/unrar
通过查看源代码,我们看到多个“255”常量选择,特别是在“recvol3.cpp”,它们也出现在原来的6.22源代码中,所以可能是因为…溢出而添加了额外的源代码?
让我们检查一下,深入一点,我发现安全检查实际上与0xff/255有关。
漏洞

这里,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]'s
datas = [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)
然而我们还在 rar-labs 网站上看到了 CVE-2023-40477 vulnerability,这很有可能证实了我们的发现。
我们在以下几种情况下成功地使 winrar/unrar Crash:
1、Memset 用零覆盖无效内存(可能在缓冲区之后):


使用“extract to”时winrar.exe中可能出现堆溢出的情况

可利用性
为了确定可利用性,让我们看看我们在256数组之后覆盖的结构。
让我们确定攻击者如何使用此原语获得RCE以及存在哪些缓解措施。
// RecVolume3 struct - that gets overflowed
class 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 版本之间的二进制差异。所有这些都使得利用成为可能,但对于普通威胁行为者来说可能性不大。
影响
尽管其 CVE 等级很高,但成功利用所需的复杂性表明广泛滥用的可能性很低,这与广泛利用的 Log4j RCE 漏洞不同。
有趣的是,Chromium似乎也利用了unrar库:https://chromium.googlesource.com/chromium/src//6ff23b0604e2edbe7ef282564ea340f5c72ab91a^/
unrar库作为第三方依赖项合并到Chrome OS中是合理的,尽管没有显示其用法的代码引用。
缓解措施
在缓解策略方面,有几种可行的选择可供考虑:
- 完全修复:将 Winrar 更新到 6.23+ 将完全修复该问题。
- 修补程序:如果更新不可用或难以部署 -阻止 *.rev 文件(最好也阻止:*.rXX 文件和 *.partXX.rar)。这可能是一个快速修复,尽管没有完全断言也没有官方。
完整项目下载
【CSDN下载】https://download.csdn.net/download/qq_39190622/88291093
如何测试?
您可以生成自己的PoC,或者只需测试附带的演示RAR文件(经验证,解压缩后会导致winrar-6.22崩溃)
- PoC生成 -
cve_2023_40477_poc.py
- 演示RAR文件 - 仅解压缩
Rar.rar
从示例 poc_after_gen
目录里。