19.11.2016 Views

Technical Analysis of the Pegasus Exploits on iOS

eNQc3Ry

eNQc3Ry

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

}<br />

return JSValue::encode(jsUndefined());<br />

This binding takes two arguments: <str<strong>on</strong>g>the</str<strong>on</strong>g> first is an ImpureGetter, and <str<strong>on</strong>g>the</str<strong>on</strong>g> sec<strong>on</strong>d is a generic<br />

JSObject that will be set as <str<strong>on</strong>g>the</str<strong>on</strong>g> ImpureGetter’s delegate. The issue results from <str<strong>on</strong>g>the</str<strong>on</strong>g> lack <str<strong>on</strong>g>of</str<strong>on</strong>g><br />

validati<strong>on</strong> that <str<strong>on</strong>g>the</str<strong>on</strong>g> JSObject passed as <str<strong>on</strong>g>the</str<strong>on</strong>g> first argument is in fact a well-formed ImpureGetter.<br />

When ano<str<strong>on</strong>g>the</str<strong>on</strong>g>r object type is passed as <str<strong>on</strong>g>the</str<strong>on</strong>g> first argument, <str<strong>on</strong>g>the</str<strong>on</strong>g> object pointer will be improperly<br />

downcast to an ImpureGetter pointer.<br />

Subsequently, when <str<strong>on</strong>g>the</str<strong>on</strong>g> m_delegate member is set via setDelegate(), a pointer to <str<strong>on</strong>g>the</str<strong>on</strong>g> JSObject<br />

passed as <str<strong>on</strong>g>the</str<strong>on</strong>g> sec<strong>on</strong>d argument will be written to <str<strong>on</strong>g>the</str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g>fset that aligns with m_delegate (16<br />

bytes into <str<strong>on</strong>g>the</str<strong>on</strong>g> supplied object). This issue can be used to create a primitive that allows a pointer<br />

to an arbitrary JSObject to be written 16 bytes into any o<str<strong>on</strong>g>the</str<strong>on</strong>g>r JSObject.<br />

Exploitati<strong>on</strong><br />

<str<strong>on</strong>g>Pegasus</str<strong>on</strong>g> leverages this issue to achieve unsigned code executi<strong>on</strong> from within an <strong>iOS</strong><br />

applicati<strong>on</strong> c<strong>on</strong>text. In order to gain c<strong>on</strong>trol <str<strong>on</strong>g>of</str<strong>on</strong>g> executi<strong>on</strong> flow, <str<strong>on</strong>g>the</str<strong>on</strong>g> exploit uses a number <str<strong>on</strong>g>of</str<strong>on</strong>g><br />

DataView objects. DataViews are used because <str<strong>on</strong>g>the</str<strong>on</strong>g>y provide a trivial mechanism to read and<br />

write arbitrary <str<strong>on</strong>g>of</str<strong>on</strong>g>fsets into a vector. The DataView object also c<strong>on</strong>veniently has a pointer to <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

backing buffer at its 16 byte <str<strong>on</strong>g>of</str<strong>on</strong>g>fset. Using <str<strong>on</strong>g>the</str<strong>on</strong>g>se corrupted DataView objects, <str<strong>on</strong>g>the</str<strong>on</strong>g> exploit sets up<br />

<str<strong>on</strong>g>the</str<strong>on</strong>g> tools needed to gain arbitrary native code executi<strong>on</strong> - namely, a read/write primitive and <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

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 arbitrary JavaScript object. Once this setup is complete, <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

exploit can create an executable mapping c<strong>on</strong>taining <str<strong>on</strong>g>the</str<strong>on</strong>g> native code payload. The following<br />

secti<strong>on</strong>s detail <str<strong>on</strong>g>the</str<strong>on</strong>g> various stages <str<strong>on</strong>g>of</str<strong>on</strong>g> this process.<br />

Acquiring an arbitrary read/write primitive<br />

A read/write primitive for arbitrary <str<strong>on</strong>g>of</str<strong>on</strong>g>fsets into a DataView object can be obtained using <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

following code snippet.<br />

var dummy_ab = new ArrayBuffer(0x20);<br />

var dataview_init_rw = new DataView(dummy_ab);<br />

...<br />

var dataview_rw = new DataView(dummy_ab);<br />

…<br />

setImpureGetterDelegate(dataview_init_rw, dataview_rw);<br />

First, two DataViews are created using a dummy ArrayBuffer as <str<strong>on</strong>g>the</str<strong>on</strong>g> backing vector for both.<br />

Next, <str<strong>on</strong>g>the</str<strong>on</strong>g> issue is exploited to corrupt <str<strong>on</strong>g>the</str<strong>on</strong>g> m_vector member <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> dataview_init_rw object with<br />

a pointer to <str<strong>on</strong>g>the</str<strong>on</strong>g> dataview_rw object. Subsequent reads and writes into <str<strong>on</strong>g>the</str<strong>on</strong>g> dataview_init_rw<br />

DataView will allow arbitrary members <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> dataview_rw to be leaked or overwritten. Next,<br />

c<strong>on</strong>trol over this object is used to gain a read/write primitive for <str<strong>on</strong>g>the</str<strong>on</strong>g> entirety <str<strong>on</strong>g>of</str<strong>on</strong>g> process memory.<br />

Page 40

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!