研究人员:Nadav Grossman
介绍
在本文中,我们讲述了如何使用WinAFL模糊器找到逻辑错误并在WinRAR中利用它来获得对受害者计算机的完全控制的故事。该漏洞利用仅通过提取存档,并使超过5亿用户面临风险。此漏洞已存在超过19年(!)并迫使WinRAR完全放弃对易受攻击格式的支持。
背景
几个月前,我们的团队构建了一个多处理器模糊测试实验室,并开始使用WinAFL模糊器为Windows环境模糊二进制文件。在我们从Adobe Research获得的良好结果之后,我们决定扩展我们的模糊测试工作并开始模仿WinRAR。
模糊器产生的崩溃之一导致我们在2006年编译了一个旧的,过时的动态链接库(dll),没有保护机制(如ASLR,DEP等),并由WinRAR使用。
我们将焦点和模糊转向这个“低悬的水果”dll,并寻找一个内存损坏错误,希望导致远程执行代码。
然而,模糊器产生了一个具有“怪异”行为的测试用例。在研究了这种行为之后,我们发现了一个逻辑错误:Absolute Path Traversal。从这一点开始,将此漏洞利用到远程代码执行非常简单。
也许还值得一提的是,针对这些类型的漏洞提供了各种各样的bug赏金计划中的大量资金。
什么是WinRAR?
WinRAR是Windows的试用文件归档程序实用程序,可以创建和查看RAR或ZIP文件格式的归档,并解压缩大量归档文件格式。
据WinRAR网站称,全球超过5亿用户使WinRAR成为当今世界上最受欢迎的压缩工具。
这就是GUI的样子:
模糊过程背景
这些是开始模糊WinRAR所采取的步骤:
- 在WinRAR主函数内部创建内部线束,使我们能够模糊任何存档类型,而无需为每种格式拼接特定线束。这是通过修补WinRAR可执行文件来完成的。
- 消除需要用户交互的消息框和对话框等GUI元素。这也可以通过修补WinRAR可执行文件来完成。
即使在WinRAR的CLI模式下,也会弹出一些消息框。 - 使用奥卢大学2005年左右进行的一项有趣研究的巨型语料库。
- 使用WinRAR命令行开关使用WinAFL对程序进行模糊处理。这些强制WinRAR解析“已损坏的存档”并设置默认密码(“-p”表示密码,“ - kb”表示保留损坏的解压缩文件)。我们在WinRAR手册/帮助文件中找到了这些选项。
在短时间的模糊测试之后,我们发现了几个存档格式的崩溃,例如RAR,LZH和ACE,这些存档格式是由内存损坏漏洞引起的,例如Out-of-Bounds Write。但是,利用这些漏洞并非易事,因为原语提供了对覆盖缓冲区的有限控制。
然而,与解析ACE格式相关的崩溃引起了我们的注意。我们发现WinRAR使用一个名为unacev2.dll
解析ACE档案的DLL 。快速浏览一下这个dll就会发现它是2006年没有保护机制的旧版dll。最后,事实证明我们甚至不需要绕过它们。
建立一个特定的线束
我们决定专注于这个dll,因为它看起来很容易被利用。
另外,就WinRAR而言,只要存档文件具有.rar扩展名,它就会根据文件的魔术字节处理它,在我们的例子中是ACE格式。
为了提高模糊器的性能,并仅增加相关dll的覆盖范围,我们为其创建了一个特定的线束unacev2.dll
。
为此,我们需要了解如何unacev2.dll
使用。在对调用unacev2.dll
ACE归档提取的代码进行反向工程之后,我们发现应按以下顺序调用两个导出函数进行提取:
- 名为的初始化函数
ACEInitDll
,具有以下签名: •struct_1:指向未知结构的指针
INT __stdcall ACEInitDll(unknown_struct_1 *struct_1);
- 一个名为的提取函数
ACEExtract
,具有以下签名:• :指向要提取的ace文件的路径的字符串指针 • :指向未知结构的指针
INT __stdcall ACEExtract(LPSTR ArchiveName, unknown_struct_2 *struct_2);
ArchiveName
struct_2
这两个函数都需要我们不知道的结构。我们有两种方法可以尝试理解未知的结构:反转和调试WinRAR,或尝试查找使用这些结构的开源项目。
第一种选择更耗时,因此我们选择尝试第二种选择。我们在github.com上搜索了导出的函数ACEInitDll
,找到了一个名为FarManager的项目,它使用了这个dll并包含了一个未知结构的详细头文件。
注意:此项目的创建者也是WinRAR的创建者。
在将头文件加载到IDA之后,更容易理解两个函数(ACEInitDll
和ACEExtract
)之前的“未知结构” ,因为IDA为每个结构成员显示了正确的名称和类型。
从我们在FarManager项目中找到的标题中,我们提出了以下签名:
INT __stdcall ACEInitDll(pACEInitDllStruc DllData);
INT __stdcall ACEExtract(LPSTR ArchiveName, pACEExtractStruc Extract);
为了模仿WinRAR使用的方式unacev2.dll
,我们分配了与WinRAR一样的结构成员。
我们开始模糊这种特定的线束,但我们没有发现新的崩溃,并且覆盖范围没有在模糊测试的前几个小时内扩展。我们试图了解这种限制的原因。
我们首先查找有关ACE归档格式的信息。
了解ACE格式
我们没有找到该格式的RFC,但我们确实在互联网上找到了重要信息。
1.创建ACE存档受专利保护。唯一允许创建ACE存档的软件是WinACE
。该计划的最后一个版本是在2007年11月编制的。该公司的网站自2017年8月以来一直处于关闭状态。但是,提取ACE档案不受专利保护。
acefile
这个维基百科页面中提到了一个名为纯Python的项目。它最有用的功能是:
- 它可以提取ACE档案。
- 它包含有关ACE文件格式的简要说明。
- 它有一个非常有用的功能,打印文件格式标题和解释。
要理解ACE文件格式,让我们创建一个简单.txt
文件(名为“simple_file.txt”),并使用它进行压缩WinACE
。然后我们将使用检查ACE文件的标题acefile
。
这是 simple_file.txt
这些是我们选择WinACE
创建示例的选项:
此选项\users\nadavgr\Documents
在所选的提取目录下创建子目录,并将simple_file.txt提取到该相对路径。
simple_file.ace
使用标头标志acefile.py
从acefile
项目运行显示有关存档标头的信息:
这导致:
笔记:
-
filename
将上图中字段中的每个“\\” 视为单个斜杠“\”,这只是python转义。 - 为清楚起见,相同的字段在十六进制转储和输出中用相同的颜色标记
acefile
。
重要领域摘要:
- hdr_crc(标记为粉红色):
两个CRC字段存在于2个标头中。如果CRC与数据不匹配,则提取
被中断。这就是为什么模糊器找不到更多路径(扩展其覆盖范围)的原因。为了“解决”这个问题,我们修补了所有的CRC *校验unacev2.dll
。* 注 - CRC是 常规CRC-32的修改实现。
- filename(标记为绿色):
它包含文件的相对路径。在提取过程中(包括文件)创建相对路径中指定的所有目录。其大小filename
由十六进制转储中的黑色框标记的2个字节(小端)定义。 - advert(以黄色标记)
WinACE
如果使用未注册的版本创建存档,则在创建ACE存档期间会自动添加广告字段WinACE
。 - 文件内容:
- “
origsize
” - 内容的大小。内容本身位于定义文件的标题之后(“hdr_type”字段== 1)。 - “
hdr_size
” - 标题大小。由十六进制转储中的灰色框标记。 - 在第二个标题的偏移70(0x46)处,我们可以找到我们的文件内容:“Hello From Check Point!”
- “
因为文件名字段包含文件的相对路径,所以我们对该字段进行了一些手动修改尝试,以查看它是否容易受到“路径遍历”的影响
。例如,我们将简单的路径遍历小工具“\ .. \”添加到文件名字段和更复杂的“路径遍历”技巧,但没有成功。
在修补所有结构检查(例如CRC验证)之后,我们再次激活了我们的模糊器。在短时间的模糊测试之后,我们进入了主要的模糊测试目录,发现了一些奇怪的东西。但是,让我们首先描述一下我们的模糊机器以获得一些必要的背景。
模糊机
为了提高模糊器性能并防止I \ O瓶颈,我们使用了一个在模糊测试机上使用ImDisk工具包的RAM磁盘驱动器。
Ram磁盘映射到驱动器R:\,文件夹树如下所示:
检测路径遍历错误
启动模糊器后不久,我们在驱动器R的根目录中找到了一个名为sourbe的新文件夹,位于一个令人惊讶的位置:
指示线束将模糊化存档提取到“output_folders”下的子目录。例如,R:\ACE_FUZZER\output_folders\Slave_2\
。那么为什么我们在父目录中创建了一个新文件夹呢?
在sourbe
文件夹中,我们找到了一个名为RED VERSION_¶
以下内容的文件:
这是触发漏洞的测试用例的十六进制转储:
笔记:
- 我们对此测试用例进行了一些小的更改(例如调整CRC)以使其可解析
acefile
。 - 为方便起见,字段在十六进制转储和
输出 中用相同的颜色标记acefile
。
这是我们在查看十六进制转储和输出时注意到的前三件事acefile
:
- 模糊器将“广告”字段的一部分复制到其他字段:
- 压缩文件的内容为“SIO”,在十六进制转储中以橙色框标记。它是广告字符串“* UNREGISTERED VER SIO N *”的一部分。
- 文件名字段包含字符串“RED VERSION *”,它是广告字符串“* UNREGISTE RED VERSION * ”的一部分。
-
filename
字段中的路径在提取过程中用作“绝对路径”,而不是目标文件夹的相对路径(反斜杠是驱动器的根)。 - 提取文件名是“REDVERSION_¶”。似乎
filename
字段中的星号被转换为下划线,并且\ x14 \(0x14)值在提取文件名中表示为“¶”。该filename
字段的其他内容被忽略,因为在\ x14 \(0x14)值之后有一个null char终止字符串。
为了找到导致它忽略目标文件夹的约束并filename
在提取过程中将该字段用作绝对路径,我们根据我们的假设进行了以下尝试。
我们的第一个假设是该filename
字段的第一个字符('\'char)触发了漏洞。不幸的是,经过快速检查后我们发现事实并非如此。经过额外检查后,我们得出了以下结论:
- 第一个字符应该是'/'或'\'。
- '*'应
filename
至少包含一次; 位置无关紧要。
filename
触发错误的字段示例:\some_folder\some_file*.exe
将被解压缩到C:\some_folder\some_file_.exe
,并且星号将转换为下划线(_)。
现在它在我们的模糊测试工具上工作了,是时候在WinRAR上测试我们精心设计的存档(例如,利用文件)文件了。
在WinRAR上尝试利用
乍一看,看起来漏洞在WinRAR上按预期工作,因为sourbe
目录是在驱动器的根目录中创建的C:\
。但是,当我们进入“sourbe”文件夹(C:\sourbe
)时,我们注意到文件未创建。
这些行为引发了两个问题:
- 为什么线束和WinRAR的行为不同?
- 为什么创建了利用文件中指定的目录,并且未创建提取的文件?
为什么线束和WinRAR的行为不同?
我们预计漏洞利用文件在WinRAR上的行为与在我们的线束中表现的行为相同,原因如下:
- dll(
unacev2.dll
)将文件提取到目标文件夹,而不是外部可执行文件(WinRAR或我们的线束)。 - 当将参数/结构成员传递给dll时,我们的线束完美地模仿WinRAR。
更深入的观察表明我们在第二点中有一个错误的假设。我们的线程定义了4个回调指针,我们实现的回调与WinRAR的回调不同。让我们回到我们的线束实现。
我们在调用名为的导出函数时提到了这个签名 ACEInitDll
。
INT __stdcall ACEInitDll(pACEInitDllStruc DllData);
pACEInitDllStruc
是指向sACEInitDLLStruc
结构的指针。这个结构的第一个成员是tACEGlobalDataStruc
。此结构有许多成员,包括具有以下签名的回调函数的指针:
INT (__stdcall *InfoCallbackProc) (pACEInfoCallbackProcStruc Info);
INT (__stdcall *ErrorCallbackProc) (pACEErrorCallbackProcStruc Error);
INT (__stdcall *RequestCallbackProc) (pACERequestCallbackProcStruc Request);
INT (__stdcall *StateCallbackProc) (pACEStateCallbackProcStruc State);
这些回调unacev2.dll
在提取过程中由dll()调用。
回调用作即将发生的操作的外部验证器,例如创建文件,创建目录,覆盖文件等
。外部回调/验证器获取有关即将发生的操作的信息,例如,文件提取,并将其决定返回到dll。
如果允许该操作,则将以下常量返回给dll:ACE_CALLBACK_RETURN_OK
否则,如果回调函数不允许该操作,则返回以下常量:ACE_CALLBACK_RETURN_CANCEL
,并且操作被中止。
有关这些回调函数的详细信息,请参阅解释从FarManager。
我们的线束返回ACE_CALLBACK_RETURN_OK
所有回调函数,除了ErrorCallbackProc
它返回的位置ACE_CALLBACK_RETURN_CANCEL
。
事实证明,WinRAR对提取的内容进行了验证filename
(在它们被提取和创建之后),并且由于WinRAR回调中的那些验证,文件的创建被中止。这意味着在创建文件后,WinRAR会删除它。
WinRAR验证器/回调
这是阻止文件创建的WinRAR回调验证器伪代码的一部分:
“ SourceFileName
”表示将提取的文件的相对路径。
该功能执行以下检查:
- 第一个字符不等于“
\
”或“/
”。 - 文件名不以以下字符串“
..\
”或“../
” 开头,这些字符串是“Path Traversal”的小工具。 - 字符串中不存在以下“Path Traversal”小工具:
- “
\..\
” - “
\../
” - “
/../
” - “
/..\
”
- “
WinRAR 中的unacv2.dll
调用StateCallbackProc
中的提取函数,并将filename
ACE格式的字段作为要提取的相对路径传递。
WinRAR回调的验证器检查相对路径。验证器返回ACE_CALLBACK_RETURN_CANCEL
到dll,(因为该filename
字段以反斜杠“\”开头)并且文件创建被中止。
以下字符串传递给WinRAR回调的验证器:
“\ sourbe \ RED VERSION_”
注意:这是带有字段“\ sourbe \ RED VERSION *¶”的原始文件名。“ unacev2.dll
”用下划线替换“*”。
为什么创建漏洞利用文件中指定的文件夹并且未创建解压缩的文件?
由于dll(“ unacev2.dll
”)中的错误,即使ACE_CALLBACK_RETURN_CANCEL
从回调中返回,filename
也会由dll创建相对路径(ACE归档中的字段)中指定的文件夹。
这样做的原因是unacev2.dll
在创建文件夹之前调用外部验证器(回调),但是在创建文件夹之后它会过早地检查回调的返回值。因此,在调用WriteFile API 之前,它会在将内容写入提取的文件之前中止提取操作。
它实际上创建了提取的文件,而没有向其写入内容。它调用CreateFile API
,然后检查回调函数的返回码。如果返回代码是 ACE_CALLBACK_RETURN_CANCEL
,它实际上删除了以前通过调用CreateFile API创建的文件。
附注:
- 我们找到了绕过删除文件的方法,但它允许我们只创建空文件。我们可以通过在文件的末尾添加“:”来绕过文件删除,该文件被视为备用数据流。如果回调返回
ACE_CALLBACK_RETURN_CANCEL
,则dll会尝试删除文件的备用数据流而不是文件本身。 - 如果相对路径字符串以“ \ ”(斜杠)开头,则dll代码中还有另一个过滤函数会中止提取操作。在调用任何其他过滤器函数之前,这发生在第一个提取阶段。 但是,通过添加“*”或“ ?“字符(通配符)到压缩文件的相对路径(文件名字段),将跳过此检查,代码流可以继续并(部分)触发Path Traversal漏洞。这就是为什么由模糊器生成的漏洞利用文件触发了我们线束中的错误。由于WinRAR代码中的回调验证器,它不会触发WinRAR中的错误。
中级调查结果摘要
- 我们在中找到了一个Path Traversal漏洞
unacev2.dll
。它使我们的线束能够将文件提取到任意路径,并完全忽略目标文件夹,并将提取的文件相对路径视为完整路径。 - 两个约束导致Path Traversal漏洞(在前面的部分中总结):
1。第一个char应该是'/'或'\'。
2.'*'应filename
至少包含一次。位置无关紧要。 - WinRAR部分容易受到Path Traversal的攻击:
-
unacev2.dll
从WinRAR回调(ACE_CALLBACK_RETURN_CANCEL
)获取中止代码后不会中止操作。由于延迟检查WinRAR回调的返回代码,因此会创建漏洞利用文件中指定的目录。 - 提取的文件也是在exploit文件中指定的完整路径上创建的(没有内容),但在从回调中检查返回的代码(在调用WriteFile API之前)之后立即删除它。
- 我们找到了绕过删除文件的方法,但它允许我们只创建空文件。
-
找到根本原因
此时,我们想弄清楚为什么忽略目标文件夹,并将归档文件(filename
字段)的相对路径视为完整路径。
为了实现这个目标,我们可以使用静态分析和调试,但我们决定使用更快的方法。我们使用DynamoRio来记录unacev2.dll
常规ACE文件和触发该错误的漏洞利用文件的代码覆盖率。然后我们使用灯塔插件进行IDA,并从另一个中减去一个覆盖路径。
这些是我们得到的结果:
在“Coverage Overview”窗口中,我们可以看到单个结果。这意味着在第一次尝试中仅执行了一个基本块(在A中标记),在第二次尝试时未到达(在B中标记)。
灯塔插件用蓝色标记了变焦基本块的背景,如下图所示。
从代码覆盖率结果中,您可以理解漏洞利用文件不是通过diffed基本块(标记为蓝色),而是采用相反的基本块(错误条件,用红色箭头标记)。
如果代码流经过错误条件(红色箭头),则绿色框内的行用""
(空字符串)替换目标文件夹,然后调用sprintf
函数,将目标文件夹连接到提取的相对路径文件。
分别用绿色和红色箭头标记的真实和错误条件的代码流程
受到对名为GetDevicePathLen
(在红框内)的函数的调用的影响。
如果调用的结果GetDevicePathLen
等于0,则sprintf
如下所示:
sprintf(final_file_path, "%s%s", destination_folder, file_relative_path);
除此以外:
sprintf(final_file_path, "%s%s", "", file_relative_path);
最后一个 sprintf
是触发Path Traversal漏洞的错误代码。
这意味着相对路径实际上将被视为应写入/创建的文件/目录的完整路径。
让我们看一下GetDevicePathLen函数,以便更好地理解根本原因:
提取文件的相对路径传递给GetDevicePathLen
。
它检查设备或驱动器名称前缀是否出现在Path参数中,并返回该字符串的长度,如下所示:
- 该函数为此路径返回3:
C:\some_folder\some_file.ext
- 该函数为此路径返回1:
\some_folder\some_file.ext
- 该函数为此路径返回15:
\\LOCALHOST\C$\some_folder\some_file.ext
- 该函数为此路径返回21:
\\?\Harddisk0Volume1\some_folder\some_file.ext
- 该函数为此路径返回0:
some_folder\some_file.ext
如果返回值GetDevicePathLen
大于0,则提取文件的相对路径将被视为完整路径,因为在调用期间目标文件夹被空字符串替换 sprintf
,这会导致Path Traversal漏洞。
但是,有一个函数可以“清除”提取文件的相对路径,省略在调用之前不允许的任何序列GetDevicePathLen
。
这是一个清除路径“ ”的伪代码CleanPath
。
该函数省略了一些简单的Path Traversal序列,如“ \..\
”(它只省略了“ ..\
序列,如果它在路径的开头找到”)序列,它省略了驱动序列,如:“ C:\
” , “ ”,并且由于未知原因, “ ”也是。C:
C:\C:
请注意,它不关心第一个字母; 以下序列也将被省略:“ _:\
”,“ _:
”,“ _:\_:
”(在这种情况下,下划线表示任何值)。
把它放在一起
要创建漏洞利用文件,导致WinRAR将归档文件解压缩到任意路径(Path Traversal),请解压缩到启动文件夹(在重新启动后获取代码执行)而不是目标文件夹。
我们应该绕过两个过滤函数来触发bug。
要触发空字符串与压缩文件的相对路径的串联,而不是目标文件夹:
sprintf(final_file_path, "%s%s", "", file_relative_path);
代替:
sprintf(final_file_path, "%s%s", destination_folder, file_relative_path);
GetDevicePathLen
函数的结果应大于0.
这取决于相对路径的内容(“ file_relative_path”)。如果相对路径以这种方式启动设备路径:
- 选项1:
C:\some_folder\some_file.ext
- 选项2 :(
\some_folder\some_file.ext
第一个斜杠代表当前驱动器。)
返回值GetDevicePathLen
将大于0.
但是,在unacev2.dll
命名CleanPath
(图17)中有一个过滤函数,用于检查相对路径是否以C:\开头,并在调用之前将其从相对路径字符串中删除GetDevicePathLen
。
它省略了选项1字符串中的“ C:\
”序列,但没有从选项2字符串中省略“ \ ”序列。
为了克服这个限制,我们可以向选项1添加另一个“ C:\
”序列,它将被省略CleanPath
(图17),并保留字符串的相对路径,如我们想要的一个“ C:\
”,如:
- 选项1':=>
C:\C:\
some_folder\some_file.ext
C:\
some_folder\some_file.ext
但是,WinRAR代码中有一个回调函数(图13),它用作验证器/过滤器函数。在提取过程中,unacev2.dll
调用驻留在WinRAR代码中的回调函数。
回调函数验证压缩文件的相对路径。如果找到黑名单序列,则将中止提取操作。
回调函数进行的检查之一是以“ \ ”(斜杠)开头的相对路径。
但它没有检查“ C:\
” 。因此,我们可以使用选项1'来利用Path Traversal漏洞!
我们还发现了一个SMB攻击媒介,它可以连接到任意IP地址,并在SMB服务器上的任意路径中创建文件和文件夹。
示例:
C:\\\10.10.10.10\smb_folder_name\some_folder\some_file.ext
=> \\10.10.10.10\smb_folder_name\some_folder\some_file.ext
简单漏洞利用文件的示例
我们将.ace扩展名更改为.rar扩展名,因为WinRAR会根据文件内容检测格式,而不是扩展名。
这是从以下输出:acefile
我们通过制作的filename
字段字符串(绿色)触发漏洞。
C:\some_folder\some_file.txt
无论目标文件夹的路径是什么,都将提取此存档。
创建真正的漏洞利用
我们可以通过从ACE存档中提取压缩的可执行文件到其中一个启动文件夹来获得代码执行。驻留在Startup文件夹中的任何文件都将在引导时执行。
制作一个将其压缩文件提取到Startup文件夹的ACE存档似乎很简单,但事实并非如此。
以下路径中至少有2个Startup文件夹:
-
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp
-
C:\Users\<user name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Startup文件夹的第一个路径需要高权限/高完整性级别(如果启用了UAC)。但是,WinRAR默认以中等完整性级别运行。
Startup文件夹的第二个路径要求知道用户的名称。
我们可以尝试通过创建一个包含数千个精心设计的压缩文件的ACE归档文件来克服它,其中任何一个都包含Startup文件夹的路径但具有不同的路径<user name>
,并希望它可以在我们的目标中工作。
最强大的矢量
我们找到了一个向量,它允许我们将文件提取到Startup文件夹而不关心<user name>
。
通过filename
在ACE存档中使用以下字段:
C:\C:
C:../AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\some_file.exe
它被CleanPath
函数转换为以下路径(图17):
C:../AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\some_file.exe
因为该CleanPath
函数删除了“
C:\C:
”序列。
此外,此目标文件夹将被忽略,因为GetDevicePathLen
函数(图16)将为最后一个“ C: ”序列返回2 。
让我们分析最后的路径:
序列“ C:
”由Windows转换为正在运行的进程的“当前目录”。在我们的例子中,它是WinRAR的当前路径。
如果从其文件夹执行WinRAR,则“当前目录”将是此WinRAR文件夹: C:\Program Files\WinRAR
但是,如果通过双击存档文件或右键单击存档文件中的“extract”来执行WinRAR,则WinRAR的“当前目录”将成为存档所在文件夹的路径。
例如,如果存档位于用户的“下载”文件夹中,则WinRAR的“当前目录”将为: 如果存档位于Desktop文件夹中,则“当前目录”路径将为:
C:\Users\<user name>\Downloads
C:\Users\<user name>\Desktop
要从Desktop或Downloads文件夹到Startup文件夹,我们应该将一个文件夹“ ../
”返回到“user folder”,并连接到启动目录的相对路径:AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\
到以下序列:“ C:../
”
这是最终结果: C:../AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\some_file.exe
请记住,有两个针对路径遍历序列的检查:
- 在
CleanPath
跳过这样的序列的函数中。 - 在WinRAR的回调函数中,它中止了提取操作。
CleanPath
检查以下路径遍历模式:“ \..\
”
WinRAR的回调函数检查以下模式:
-
“\..\”
-
“\../”
-
“/../”
-
“/..\”
因为第一个斜杠或反斜杠不是我们序列“ C:../
”的一部分,所以我们可以绕过路径遍历验证。但是,我们只能返回一个文件夹。我们需要在不知道用户名的情况下将文件解压缩到Startup文件夹。
注意:如果我们想要返回多个文件夹,我们应该连接以下序列“ /../
”。例如,“ ”和“ ”序列将被捕获为回调验证器函数,并且将中止提取。C:../../
/../
示范(POC)
边注
在我们的研究结束时,我们发现WinACE
创建了一个类似于unacev2.dll
linux 的提取实用程序,称为unace-nonfree(使用Watcom编译器编译)。源代码可用。
Windows的源代码(由其unacev2.dll
构建)也包含在内,但它比上一版本更旧unacev2.dll
,并且无法为Windows编译/构建。此外,源代码中缺少某些功能 - 例如,不包括图17中的检查。
但是,图16取自源代码。
我们还在源代码中找到了Path Traversal bug。它看起来像这样:
CVE:
CVE-2018-20250,CVE-2018-20251,CVE-2018-20252,CVE-2018-20253。
WinRAR的回复
WinRAR决定从他们的软件包中删除UNACEV2.dll,而WinRAR不支持版本号为“5.70 beta 1”的ACE格式。
来自WinRAR网站的报价:
“来自Check Point Software Technologies的Nadav Grossman向我们介绍了UNACEV2.DLL库中的安全漏洞。 上述漏洞使得可以在目标文件夹内部或外部的任意文件夹中创建文件 解压ACE档案时。WinRAR使用此第三方库来解压缩ACE档案。 自2005年以来UNACEV2.DLL尚未更新,我们无法访问其源代码。 因此我们决定放弃ACE归档格式支持以保护WinRAR用户的安全性。 我们感谢Check Point Software Technologies报告此问题。“
Check Point的SandBlast Agent Behavioral Guard可以防御这些威胁。
Check Point的IPS刀片提供针对此威胁的保护:“RARLAB WinRAR ACE格式输入验证远程执行代码(CVE-2018-20250)”
非常感谢我的同事Eyal Itkin(@EyalItkin)和Omri Herscovici(@omriher)对本研究的帮助。
本文作者为Mr.Bai,转载请注明。