原文链接:“Game of Rars” – Exploring a New Remote Code Execution Vulnerability in WinRAR with Proof-of-Concept (CVE-2023-40477)
译者:知道创宇404实验室翻译组
摘要
- 拥有5亿以上用户的WinRAR,曝出新的漏洞(CVE-2023-40477,CVE-2023-38831);
- CVE-2023-40477的PoC
- 虽然被认为是RCE假定可被利用,但实际上影响并不大;
- 本文研究内容包括:其影响、可被利用的场景以及缓解措施;
- 该漏洞已在最新的Winrar v6.23中得到修复,本文也会提出解决办法。
CVE-2023-40477:概述和PoC
八月中旬,WinRAR 6.23发布了一些关于关键漏洞的警告。我们了解到漏洞(CVE-2023-40477)目前已经修复,且公布了以下信息,具体内容详看下文:
二进制文件对比
我们知道6.23版本已经修复,为了复现找到了修复前的版本。通过下载便携版的WinRAR-v6.23和WinRAR-v6.22,观察了解到:
可以看到winrar.exe可能只是一个图形界面,如果在解压过程中存在漏洞,那么它也可能存在于“unrar.exe”中。通过对比6.23和6.22的差异(忽略注释),我们得到以下结果:
查看流程图,6.23版本中发现了几个有趣的新增内容(大型函数图中,看起来像是主要的提取):
仔细观察,这些似乎是额外的检查!
这看起来很有希望!我们在这里看到一些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有关。
漏洞
在这里,P[i]’s是从 ".rev" 文件中提取的。它们位于文件末尾。这些P[i]’s用于确定它们代表哪个恢复卷以及适用于哪个 FileNumber。FileNumber 也从中获取,存储在 P[2] 中。
紧接着,在我们控制的索引位置上分配并放置了 File\ ,而这个数组的大小是256!(第241行),而这解释了为什么有255次检查。
因为该索引实际上等于:P[2]+P[0]-1,我们几乎可以任意控制rev卷的内容。因此,我们可以用指针(指向 File 结构)来覆盖该缓冲区,它们将覆盖当前对象中的下一个属性。
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网站上的https://www.rarlab.com/vuln_rev3_names.html, 这基本上证实了我们的发现。
利用这一点,成功地在几种情况下使winrar/unrar崩溃:
- 内存集用零覆盖无效内存(可能在缓冲区之后):
- 在使用“提取到”功能时,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%5E%21/.
尽管没有代码参考表明其使用情况,但unrar库有可能作为第三方依赖项被集成到Chrome OS中。
解决措施
可考虑的应对措施:
-
完全修复:将Winrar更新到6.23+将完全修复。
-
补丁修复:如果更新不可用或难以部署,可以考虑阻止使用*.rev文件(最好同时阻止*.rXX文件和*.partXX.rar文件)。尽管并没有官方支持肯定,但这可能是目前的一个快速的修复方法。
参考链接
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/3019/