Browsers
, it should be noted that just like Operating Systems
, they make up a large area that includes countless Browser Engines
. Therefore, their exploitation can take various forms such as: JavaScript Engine Exploitation
, DOM Exploitation
... (diff.diff)
, and the /bin/d8
executable (d8 is the name for JavaScript REPL created by Google for v8).
diff.diff
file, we can see that 2 vulnerabilities were introduced in v8:
out-of-bounds read
for any String object. It is easy to notice that the piece of code responsible to restrict the access to memory outside the one allocated for the object, has been removed. Therefore, this allows us to read data from memory at arbitrary offset.
out-of-bounds write
introduced in the .fill()
method of TypedArray objects. Just like the previous vulnerability, we can say that the vulnerability stands out because of the way the changes were made. The code segment responsible for verifying the integrity of the parameters, of the fill method, has been altered, so we can overwrite up to 100000000 bytes after or before the Typed Array object.
gdb
.gdb /bin/d8
, but one features d8 has is called --allow-natives-syntax
. It gives us access to a wide range of runtime functions including %DebugPrint()
.offsets
between objects and use this information in the exploit. One last piece of information about debugging, which is very important, has to do with the last bit
of an address. v8 uses this bit to keep track of pointers. Thus, as can be seen in the image above, when we want to access data from an address we have to subtract that bit.For setting breakpoints, I recommend an easy trick:
b v8::base::ieee754::cosh
Remote Code Execution?
"function pointers
to overwrite and redirect the program execution in the desired direction. Analyzing the context, we notice that there are no such pointers, our plan is not feasible. ❎
read + write + execute
a shellcode
to reach our goal. Analyzing the process mappings, we can see that there is no such mapping. Fortunately, JavaScript is not the only one that gets compiled in v8, so is WebAssembly
. I will not detail what WebAssembly is, because it is not the purpose of the writeup, but for more information I recommend the documentation: https://developer.mozilla.org/en-US/docs/WebAssembly.
write-protect flag
to change the permissions of memory segments from rw
to rx
and vice versa, WebAssembly maps a rwx
memory area for the compiled code. ✅
WASM
compiled code is loaded, and a way to overwrite the data in that memory area.
String
and a WASM
instance
d8> const wasm = new Uint8Array([...]);
d8> let s = new String("MAMAMAMAMAMAMAM");
d8> const w_instance = new WebAssembly.Instance(new WebAssembly.Module(wasm));
d8> %DebugPrint(s)
...
- value: 0x23eb0820f501 <- The string will be at the address: 0x23eb0820f501-1+0xc
...
d8> %DebugPrint(w_instance)
DebugPrint: 0x23eb0820f829: [WasmInstanceObject] in OldSpace <- The pointer to the memory zone is at address: 0x23eb0820f829-1+0x68
...
(0x23eb0820f829-1 + 0x68)-(0x23eb0820f501-1 + 0xc)
we will get the offset we need 0x384
.WASM
and execute it.memory block
with the bytes we want to overwrite..fill()
method is invoked, but the address to which the bytes are written is taken from the property ->DataPtr()
.out-of-bounds write
to overwrite the pointer of the second array with the rwx
memory area.fill()
method to overwrite the memory area.shellcode
,and invoke the wasm function, we will trigger the shell
.