1377816: Security: WebAssembly UAF in catch block with stale memory start pointer
VULNERABILITY DETAILS
WebAssembly memory start and size are stored as wasm instance fields. The WasmGraphBuilder caches the corresponding TurboFan nodes and only reloads them when necessary. One such reload is following a function call:
CheckForException(
decoder, builder_->CallIndirect(
call_info.table_index(), call_info.sig_index(),
base::VectorOf(arg_nodes),
base::VectorOf(return_nodes), decoder->position()));
…
// The invoked function could have used grow_memory, so we need to
// reload mem_size and mem_start.
LoadContextIntoSsa(ssa_env_, decoder);
The invoked function may have increased memory size, which may have moved the memory, so memory start and size are reloaded within LoadContextIntoSsa().
Notice the CheckForException() though. It can jump to the catch block of a surrounding try-catch before the memory fields are reloaded. So suppose we have the following:
func thrower
grow memory
throw
func bad
/* cache memory start pointer */
load mem[0]
try
thrower()
catch
/* can use a stale memory start pointer */
store mem[0] = 42
The thrower() grows memory and then throws an exception. The catch block can UAF a stale memory start pointer.
VERSION
Chrome Version: 107.0.5304.54 beta
Operating System: Android 12, Pixel 4
MINIMAL POC
Open min.html. The renderer will SIGSEGV:
Thread 15 “CrRendererMain” received signal SIGSEGV, Segmentation fault.
(gdb) i r
…
r1 0x2a 42
r2 0x5f4f0000 1599012864
…
pc 0x3d4f6520 0x3d4f6520
…
(gdb) x/1i $pc
=> 0x3d4f6520: str r1, [r2]
The ‘str’ instruction is the i32.store in min.wat’s catch block:
i32.const 0
i32.const 42
i32.store
The r2 register holds the stale memory start pointer.
Tested on Pixel 4, 5, 6, dev, beta and stable and linux x64 stable.
32-BIT EXPLOIT
On a 64-bit chrome, the V8 sandbox should mitigate the immediate harm. 32-bit chrome is exploitable.
Here’s an exploit for Pixel 4, which still has a 32-bit chrome. It uses the UAF to write shellcode into another wasm module’s RWX code. Note that wasm code is normally W^X, but during tier-up it’s temporarily switched to RWX, which suffices to corrupt it.
Open exploit.html on Pixel 4 chrome 107.0.5304.54 beta. The shellcode renames the renderer thread to “pwned”:
flame:/ $ ps -AT -o CMD,CMDLINE | grep pwned
pwned com.chrome.beta:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:10
Reporter credit: [email protected]
Fuzzer: None
Job Type: linux32_asan_d8
Platform Id: linux
Crash Type: UNKNOWN WRITE
Crash Address: 0x674b0000
Crash State:
Builtins_InterpreterEntryTrampoline
Builtins_InterpreterEntryTrampoline
Builtins_JSEntryTrampoline
Sanitizer: address (ASAN)
Recommended Security Severity: High
Crash Revision: https://clusterfuzz.com/revisions?job=linux32_asan_d8&revision=83927
Reproducer Testcase: https://clusterfuzz.com/download?testcase_id=5206430526406656
To reproduce this, please build the target in this report and run it against the reproducer testcase. Please use the GN arguments provided at bottom of this report when building the binary.
If you have trouble reproducing, please also export the environment variables listed under “[Environment]” in the crash stacktrace.
If you have any feedback on reproducing test cases, let us know at https://forms.gle/Yh3qCYFveHj6E5jz5 so we can improve.
转载请注明:1377816: Security: WebAssembly UAF in catch block with stale memory start pointer | CTF导航
ViewDownload