Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
variables <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> JSGenericTypedArrayView can be read or corrupted. Specifically, <str<strong>on</strong>g>the</str<strong>on</strong>g> exploit<br />
writes to an <str<strong>on</strong>g>of</str<strong>on</strong>g>fset into <str<strong>on</strong>g>the</str<strong>on</strong>g> stale JSArray that overlaps with <str<strong>on</strong>g>the</str<strong>on</strong>g> length <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g><br />
JSGenericTypedArrayView, effectively setting <str<strong>on</strong>g>the</str<strong>on</strong>g> length <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> Uint32Array to 0xFFFFFFFF.<br />
Corrupting this value will allow <str<strong>on</strong>g>the</str<strong>on</strong>g> array to be treated as a view <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> entire virtual address<br />
space <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> WebC<strong>on</strong>tent process (an arbitrary read/write primitive).<br />
The exploit still must determine which <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> 4.25 milli<strong>on</strong> Uint32Arrays that were allocated aligns<br />
with <str<strong>on</strong>g>the</str<strong>on</strong>g> stale object. This can be determined by iterating through each <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> arrays and<br />
checking whe<str<strong>on</strong>g>the</str<strong>on</strong>g>r <str<strong>on</strong>g>the</str<strong>on</strong>g> length has changed to 0xFFFFFFFF. All o<str<strong>on</strong>g>the</str<strong>on</strong>g>r arrays will still have <str<strong>on</strong>g>the</str<strong>on</strong>g><br />
original backing ArrayBuffer (or a length <str<strong>on</strong>g>of</str<strong>on</strong>g> 80 / 4).<br />
for (x = attempts.length - 1; x >= 1; x--) {<br />
if (attempts[x].length != 80 / 4) {<br />
if (attempts[x].length == 0xFFFFFFFF) {<br />
memory_view = attempts[x];<br />
...<br />
break;<br />
Leaking an object address<br />
The final comp<strong>on</strong>ent needed to complete <str<strong>on</strong>g>the</str<strong>on</strong>g> exploit is <str<strong>on</strong>g>the</str<strong>on</strong>g> ability to leak <str<strong>on</strong>g>the</str<strong>on</strong>g> address <str<strong>on</strong>g>of</str<strong>on</strong>g> an<br />
arbitrary JavaScript object. The <str<strong>on</strong>g>Pegasus</str<strong>on</strong>g> exploit accomplishes this using <str<strong>on</strong>g>the</str<strong>on</strong>g> same mechanism<br />
that was used to corrupt <str<strong>on</strong>g>the</str<strong>on</strong>g> length <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> Uint32Array used for <str<strong>on</strong>g>the</str<strong>on</strong>g> read/write primitive. By<br />
writing to an <str<strong>on</strong>g>of</str<strong>on</strong>g>fset into <str<strong>on</strong>g>the</str<strong>on</strong>g> stale object, <str<strong>on</strong>g>the</str<strong>on</strong>g> buffer <str<strong>on</strong>g>of</str<strong>on</strong>g> a Uint32Array is corrupted to point to a<br />
user-c<strong>on</strong>trolled JSArray. By setting <str<strong>on</strong>g>the</str<strong>on</strong>g> first element <str<strong>on</strong>g>of</str<strong>on</strong>g> that JSArray to <str<strong>on</strong>g>the</str<strong>on</strong>g> JavaScript object to<br />
be leaked (by corrupting <str<strong>on</strong>g>the</str<strong>on</strong>g> pointer to <str<strong>on</strong>g>the</str<strong>on</strong>g> underlying storage <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> Uint32Array), <str<strong>on</strong>g>the</str<strong>on</strong>g> object’s<br />
address can be read back out <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> Uint32Array.<br />
Native code executi<strong>on</strong><br />
All that is left to do for <str<strong>on</strong>g>the</str<strong>on</strong>g> first stage <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> <str<strong>on</strong>g>Pegasus</str<strong>on</strong>g> exploit is to create an executable mapping<br />
that will c<strong>on</strong>tain <str<strong>on</strong>g>the</str<strong>on</strong>g> shellcode to be executed. To accomplish this purpose, a JSFuncti<strong>on</strong> object<br />
is created (c<strong>on</strong>taining hundreds <str<strong>on</strong>g>of</str<strong>on</strong>g> empty try/catch blocks that will later be overwritten). To help<br />
ensure that <str<strong>on</strong>g>the</str<strong>on</strong>g> JavaScript will be compiled into native code by <str<strong>on</strong>g>the</str<strong>on</strong>g> JIT, <str<strong>on</strong>g>the</str<strong>on</strong>g> functi<strong>on</strong> is<br />
subsequently called repeatedly. This behavior ensures that <str<strong>on</strong>g>the</str<strong>on</strong>g> JIT compiled (JITed) versi<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g><br />
<str<strong>on</strong>g>the</str<strong>on</strong>g> functi<strong>on</strong> (which will later be overwritten) will be marked as high priority code that is likely to<br />
be called regularly and should <str<strong>on</strong>g>the</str<strong>on</strong>g>refore not be released. Because <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> way that <str<strong>on</strong>g>the</str<strong>on</strong>g><br />
JavaScriptCore engine handles JITed code, this will reside in an area <str<strong>on</strong>g>of</str<strong>on</strong>g> memory that is mapped<br />
as read/write/execute.<br />
var body = ''<br />
for (var k = 0; k < 0x600; k++) {<br />
body += 'try {} catch(e) {};';<br />
}<br />
var to_overwrite = new Functi<strong>on</strong>('a', body);<br />
for (var i = 0; i < 0x10000; i++) {<br />
Page 9