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.

[0x68] kOSSerializeString | 0x1C<br />

[0x6C] {payload buffer}<br />

[0x88] kOSSerializeString | 0x1C<br />

[0x8C] {payload buffer}<br />

[0xA8] kOSSerializeEndCollect<strong>on</strong> | kOSSerializeObject | 5<br />

While structurally <str<strong>on</strong>g>the</str<strong>on</strong>g>y look somewhat different, ultimately <str<strong>on</strong>g>the</str<strong>on</strong>g>y both exploit <str<strong>on</strong>g>the</str<strong>on</strong>g> same UAF<br />

vulnerability. The simpler payload (for <strong>iOS</strong> 9.3.2 and later) is <str<strong>on</strong>g>the</str<strong>on</strong>g> easiest to understand. When<br />

OSUnserializeBinary begins <str<strong>on</strong>g>the</str<strong>on</strong>g> parsing process to deserialize <str<strong>on</strong>g>the</str<strong>on</strong>g> payload, <str<strong>on</strong>g>the</str<strong>on</strong>g> functi<strong>on</strong><br />

will create a new dicti<strong>on</strong>ary object as a result <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> entry at <str<strong>on</strong>g>of</str<strong>on</strong>g>fset 0x04. Within this dicti<strong>on</strong>ary<br />

are two unkeyed objects. The first object is an OSString object with <str<strong>on</strong>g>the</str<strong>on</strong>g> value sy2 (specified<br />

in <str<strong>on</strong>g>of</str<strong>on</strong>g>fsets 0x08 and 0x0C, respectively). Offset 0x10 specifies an OSData object <str<strong>on</strong>g>of</str<strong>on</strong>g> 0x14 (20)<br />

bytes in size. The OSData object c<strong>on</strong>tains <str<strong>on</strong>g>the</str<strong>on</strong>g> payload buffer data structure. Since <str<strong>on</strong>g>the</str<strong>on</strong>g> objects<br />

are unkeyed, OSUnserializeBinary will replace <str<strong>on</strong>g>the</str<strong>on</strong>g> OSString object with <str<strong>on</strong>g>the</str<strong>on</strong>g> OSData<br />

object but leave <str<strong>on</strong>g>the</str<strong>on</strong>g> pointers in place in objsArray. With <str<strong>on</strong>g>the</str<strong>on</strong>g> OSString object having no<br />

retain() calls, <str<strong>on</strong>g>the</str<strong>on</strong>g> OSString is deallocated, <str<strong>on</strong>g>the</str<strong>on</strong>g>reby putting two memory arrays into <str<strong>on</strong>g>the</str<strong>on</strong>g> free<br />

list (<strong>on</strong>e for <str<strong>on</strong>g>the</str<strong>on</strong>g> OSString object itself and <strong>on</strong>e for <str<strong>on</strong>g>the</str<strong>on</strong>g> string associated with <str<strong>on</strong>g>the</str<strong>on</strong>g> OSString<br />

object).<br />

When OSUnserializeBinary parses <str<strong>on</strong>g>the</str<strong>on</strong>g> kOSSerializeData entry, a new OSData object<br />

is allocated and thus c<strong>on</strong>sumes <strong>on</strong>e <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> freed memory locati<strong>on</strong>s from <str<strong>on</strong>g>the</str<strong>on</strong>g> free list. When <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

data associated with <str<strong>on</strong>g>the</str<strong>on</strong>g> kOSSerializeData entry is copied into <str<strong>on</strong>g>the</str<strong>on</strong>g> OSData object, a new<br />

buffer is allocated for <str<strong>on</strong>g>the</str<strong>on</strong>g> data, which c<strong>on</strong>sumes <str<strong>on</strong>g>the</str<strong>on</strong>g> remaining data locati<strong>on</strong> from <str<strong>on</strong>g>the</str<strong>on</strong>g> free list. At<br />

this point, <str<strong>on</strong>g>the</str<strong>on</strong>g> dangling pointer in objsArray has been replaced with an OSData object’s<br />

data. It is <str<strong>on</strong>g>the</str<strong>on</strong>g> data associated with <str<strong>on</strong>g>the</str<strong>on</strong>g> OSData object that c<strong>on</strong>tains <str<strong>on</strong>g>the</str<strong>on</strong>g> malicious payload that<br />

will ultimately give 32Stage2 write access into <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel in order to install <str<strong>on</strong>g>the</str<strong>on</strong>g> read/write<br />

primitives.<br />

Regardless <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> <strong>iOS</strong> versi<strong>on</strong>, <str<strong>on</strong>g>the</str<strong>on</strong>g> malicious payload c<strong>on</strong>tains <str<strong>on</strong>g>the</str<strong>on</strong>g> same payload buffer. The<br />

payload buffer is a 20-byte structure c<strong>on</strong>sisting <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> following elements:<br />

[00] address <str<strong>on</strong>g>of</str<strong>on</strong>g> uaf_payload_buffer + 8<br />

[04] {uninitialized data from stack}<br />

[08] address <str<strong>on</strong>g>of</str<strong>on</strong>g> uaf_payload_buffer<br />

[0C] static value <str<strong>on</strong>g>of</str<strong>on</strong>g> 20<br />

[10] address <str<strong>on</strong>g>of</str<strong>on</strong>g> OSSerializer::serialize<br />

The layout <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> payload must c<strong>on</strong>tain <str<strong>on</strong>g>the</str<strong>on</strong>g> pointer to <str<strong>on</strong>g>the</str<strong>on</strong>g> new retain functi<strong>on</strong> at <str<strong>on</strong>g>of</str<strong>on</strong>g>fset 0x10.<br />

32Stage2 uses <str<strong>on</strong>g>the</str<strong>on</strong>g> OSSerializer::serialize functi<strong>on</strong> as <str<strong>on</strong>g>the</str<strong>on</strong>g> replacement retain. This<br />

layout means that <str<strong>on</strong>g>the</str<strong>on</strong>g> remainder <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> payload must now mimic <str<strong>on</strong>g>the</str<strong>on</strong>g> vtable <str<strong>on</strong>g>of</str<strong>on</strong>g> an<br />

OSSerializer object. As explained previously in Establishing Read/Write/Execute Primitives<br />

<strong>on</strong> Previously Rooted Devices, <str<strong>on</strong>g>the</str<strong>on</strong>g> OSSerializer::serialize functi<strong>on</strong> will call <str<strong>on</strong>g>the</str<strong>on</strong>g> functi<strong>on</strong><br />

at <str<strong>on</strong>g>of</str<strong>on</strong>g>fset 0x10 <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> supplied vtable while passing <str<strong>on</strong>g>of</str<strong>on</strong>g>fsets 0x08 and 0x0C <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> vtable to <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

called functi<strong>on</strong>. Given that <str<strong>on</strong>g>of</str<strong>on</strong>g>fset 0x10 is set to OSSerializer::serialize, <str<strong>on</strong>g>the</str<strong>on</strong>g> functi<strong>on</strong> is<br />

Page 29

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

Saved successfully!

Ooh no, something went wrong!