SBN

SSD Advisory – Firefox Information Leak

Vulnerabilities Summary
A vulnerability where the JavaScript JIT compiler inlines Array.prototype.push with multiple arguments that results in the stack pointer being off by 8 bytes after a bailout. This leaks a memory address to the calling function which can be used as part of an exploit inside the sandboxed content process.

Vendor Response
“Security vulnerabilities fixed in Firefox 62.0.3 and Firefox ESR 60.2.2”

DevOps Connect:DevSecOps @ RSAC 2022

CVE
CVE-2018-12387

Credit
Independent security researchers, Bruno Keith and Niklas Baumstark, have reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.

Affected systems
Firefox 62.0
Firefox ESR 60.2

Vulnerability Details
While fuzzing Spidermonkey (Mozilla’s JavaScript engine written in C++), we trigger a debug assertion with the following minimized sample:

which triggered the following assertion:

Root Cause Analysis
The assertion described above happens while running the code generated by the JIT compiler for the function f.

Let’s look at the Intermediate representation (IR) of the JIT code:

We can see two instructions arraypusht. This can be explained looking at the code responsible for inlining calls to Array.prototype.push implemented at https://dxr.mozilla.org/mozilla-central/source/js/src/jit/MCallOptimize.cpp#812 The comments inside the function mention that a call to push with multiple argument will be broken down into multiple individual arraypush{t,v} instructions. However there is some complicated logic associated with bailouts where they wish to preserve the atomicity of the call and not resume execution in-between inlined calls to push. The assertion is triggered because the stack pointer is not correctly restored when bailing out from IonMonkey to the baseline JIT and will be off by 8 bytes and hence lead to a JS_IS_CONSTRUCTING value to be fetched from the stack instead of the Boolean class.

By understanding the failure condition, we know that we need to look for opcode handlers in BaselineCompiler.cpp that perform a syncStack(0) and then address stack values via peek(). An interesting one is BaselineCompiler::emit_JSOP_INITPROP:

This opcode is emitted for the following JavaScript code:

The handler tells us how this opcode gets compiled: R0 is set to stack[top-1] = o, R1 is set to stack[top] = y, then the property assignment R0.a = R1 is performed by an inline cache. Due to the shifted stack however, in the following code, the assignment stack[top].a = stack[top+1] is performed, so a JSValue is fetched from outside the stack. Due to NaN-boxing, a native pointer value will be treated as a double in this context.

Instruction 48 is there only to place a function on the stack so that the funcall instruction 85 does not throw an exception because it expects to fetch Array.prototype.push.call from the stack, but is off by 8. This prints 2.11951350117067e-310 on our system, which is the double representation of the integer value 0x27044d565235, which is a return address. The final exploit leverages this to leak a heap address, stack address as well as the base address of xul.dll.

Exploit

*** This is a Security Bloggers Network syndicated blog from SecuriTeam Blogs authored by SSD / Ori Nimron. Read the original post at: https://blogs.securiteam.com/index.php/archives/3766