| 关键词: 代码 漏洞 WebKit 函数 大小 asan 编译 分析 数组 |
今年的Pwn2Own比赛刚刚结束,在Pwn2Own温哥华站的比赛中,Fluoroacetate团队所使用的一个WebKit漏洞成功吸引了我的注意。这个漏洞是一个价值五万五千美金的漏洞利用链的一部分,在这篇文章中,我将会对这个漏洞进行深入分析,并对漏洞进行验证和研究。 当然了,在开始深入分析之前,我们先把该漏洞的概念验证PoC提供给大家: ![]() 首先,我们需要对受该漏洞影响的WebKit版本进行编译,即Safari v12.0.3版本,根据苹果的版本发布信息,该版本对应的是修订版v240322。 svn checkout -r 240322 https://svn.webkit.org/repository/webkit/trunk webkit_ga_asan 我们可以使用AddressSanitizer(ASAN)来完成编译操作,它可以允许我们在发生内存崩溃的时候第一时间检测到错误信息。 ZDIs-Mac:webkit_ga_asan zdi$ Tools/Scripts/set-webkit-configuration --asan ZDIs-Mac:webkit_ga_asan zdi$ Tools/Scripts/build-webkit # --jsc-only can be used here which should be enough 我们将使用11db来进行调试,因为macOS本身就自带了这个工具。由于PoC中没有包含任何的呈现代码,因此我们需要在11db中使用JavaScriptCore(JSC)来执行它。为了在11db中执行jsc,我们需要调用它的二进制代码文件,而不是之前的脚本run-jsc。这个文件可以从 WebKitBuild/Release/jsc路径获取,并且需要正确设置环境变量。 env DYLD_FRAMEWORK_PATH=/Users/zdi/webkit_ga_asan/WebKitBuild/Release 我们可以在11db中运行这条命令,或者把它放在一个文本文件中,然后传递到11db -s中。 ZDIs-Mac:webkit_ga_asan zdi$ cat lldb_cmds.txt 好的,接下来,我们可以开始调试了: ![]() 我们可以看到,代码在0x6400042d1d29处发生了崩溃:mov qword ptr [rcx + 8rsi], r8,经分析后我们确认为越界写入所导致的内存崩溃。栈追踪分析显示,它发生在虚拟机环境中,也就是编译过程或者JITed代码出了问题。我们还注意到的rsi索引,它包含了0x20000040,这个数字我们在PoC中是有见过的。 这个数字是bigarr! 的大小,即NUM_SPREAD_ARGS sizeof(a)。为了查看JITed代码,我们可以设置JSC_dumpDFGDisassembly环境变量,这样jsc就可以跳转到DFG和FTL的编译代码了。 ZDIs-Mac:webkit_ga_asan zdi$ JSC_dumpDFGDisassembly=true lldb -s lldb_cmds.txt WebKitBuild/Release/jsc ~/poc3.js 这将丢弃掉大量无关的代码集,那我们应该如何确定相关代码呢? 我们知道崩溃事件发生在0x6400042d1d29处:mov qword ptr [rcx + 8rsi], r8。那我们为何不尝试搜索这个地址呢? 没错,我们在DFG中找到了: ![]() 代码在使用DFG JIT的分布操作符来创建一个新数组时,调用了NewArrayWithSpread方法,整个行为发生在gen_func生成的一个函数f中,调用行为发生在一个循环中。 在对源代码进行分析后,我们发现了Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp文件中的SpeculativeJIT::compileNewArrayWithSpread函数。这是DFG代码的起始位置,启动代码意味着将JIT生成的机器代码写入内存以供以后执行。 我们可以通过查看compileNewArrayWithSpread方法来理解其中的机器代码。我们看到compileAllocateNewArrayWithSize()负责分配具有特定大小的新数组,它的第三个参数sizeGPR将作为第二个参数传递给emitAllocateButterfly(),这意味着它将为数组分配一个新的butterfly(包含JS对象值的内存空间)。如果您不熟悉JSObject的butterfly,可以点击【这里】了解更多信息。 跳转到EnITalListAtButoFuffE(),我们看到大小参数siZeGPR向左移动3位(乘以8),然后添加到常数sieof(IndexingHeader)。 方便起见,我们需要将实际的机器代码与我们在这个函数中的C++代码相匹配。m_jit字段的类型是JITCompiler。 JITCompiler负责根据数据流图生成JIT代码。它通过委托给jit来实现,后者生成一个宏汇编程序(JITCompiler通过继承关系拥有该程序)。JITCompiler保存编译期间所需信息的引用,并记录链接中使用的信息(例如,要链接的所有调用的列表)。 这意味着我们看到的调用,如m_jit.move()、m_jit.add32()等,是发出程序集的函数。通过跟踪每一个函数,我们将能够将其与C++对应的组件匹配。除了跟踪内存分配的malloc调试功能外,我们还根据自己对Intel程序集的偏好配置11db。 ZDIs-Mac:~ zdi$ cat ~/.lldbinit 由于在启用Guard Malloc的情况下正在分配大容量,我们需要设置另一个允许此类分配的环境变量。 ZDIs-Mac:webkit_ga_asan zdi$ cat lldb_cmds.txt JSC_dumpDFGDisassembly将以AT&T格式转储程序集,因此我们运行deassembly-s 0x6400042d1c22-c 70可以获得英特尔风格的程序集,结果如下: ![]() 让我们尝试匹配emitAllocateButterfly()中的一些代码。查看程序集列表,我们可以匹配以下内容: 接下来分析机器代码,此时需要设置断点。为此,我们在编译之前向jsc.cpp添加了一个dbg()函数。这将有助于在我们需要的时候进入JS代码。编译器报错显示未使用EncodedJSValue JSC_HOST_CALL functionDbg(ExecStateexec)函数中的exec,因此失败。为了解决这个问题,我们只添加了exec->argumentCount();这不会影响执行。 让我们在这里添加dbg(),因为实际的NewArrayWithSpread函数将在创建bigarr期间执行。 ![]() 再次JSC_dumpDFGDisassembly=true lldb -s lldb_cmds.txt WebKitBuild/Release/jsc ~/poc3.js运行将会导出编译代码: 在bigarr创建之前中断,您可以看到NewArrayWithSpread的机器代码。让我们在函数的开始处放置一个断点并继续执行。 断点生效: 接下来,我们需要仔细分析断点信息: ![]() 那么这里到底发生了什么?还记得PoC中的下面这部分信息吗? mk_arr函数创建一个数组,第一个参数作为大小,第二个参数作为元素。大小为(0x20000000+0x40)/8=0x4000008,这将创建一个大小为0x4000008、元素值为0x41414141410000的数组。i2f函数用于将整数转换为浮点值,以便最终在内存中得到预期值。 我们现在知道rcx指向对象a的butterfly-0x10,因为它的大小是rcx+8,这使得butterfly rcx+0x10。在这段代码的其余部分中,我们看到r8、r10、rdi、r9、rbx、r12和r13都指向对象a的一个副本-具体来说是八个副本,edx不断地添加每个副本的大小。 ![]() 此时,edx的值变成了0x20000040: 那么这八个a拷贝到了哪里呢?值0x20000040代表的又是什么呢? 重新看看PoC: ![]() 这意味f变成了: f通过扩展NUM_SPREAD_ARGS(8)第一个参数的副本和第二个参数的单个副本来创建数组。用对象a(80×04000008)和c(长度1)调用f。当NewArrayWithSpread被调用时,它为8个a和1个c腾出了空间。 最后一步到显示对象c的长度,这使得最终的edx值为0x20000041。 ![]() 下一步应该是长度的分配,它发生在emitAllocateButterfly()中。 ![]() 我们注意到shl r8d,0x3的溢出,其中0x20000041被封装到了0x208。当分配大小传递给emitAllocatevariableSize()时,它变为了0x210。 我们看到的越界读取访问冲突发生在mov qword ptr[rcx+8rsi],r8的以下代码片段中。这个代码片段的问题是用错误的大小0x20000041反向迭代新创建的butterfly,而溢出后的实际大小是0x210。然后,它将每个元素归零,但由于内存中的实际大小远小于0x20000041,因此在ASAN构建中发生了了越界访问冲突。 ![]() 下面给出的是整个越界访问行为的流程图: ![]()
总结 在这篇文章中,我们对WebKit版本v240322中的一个越界访问漏洞进行了深入分析,这个漏洞是一个价值五万五千美金的漏洞利用链中的一部分。Pwn2Own上出现的漏洞往往都是行业内较为优质的漏洞,而本文所分析的这个漏洞也不例外。在日常的漏洞研究过程中,我也希望大家能够学会使用11db,如果大家有更多关于该漏洞的想法,可以直接在我的推特上艾特我(@ziadrb)。希望本文能够给大家提供帮助! 原文链接:https://www.anquanke.com/post/id/194006 |
| 本文出处: https://www.toutiao.com/a6765811874555494924/ |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|