19.11.2016 Views

Technical Analysis of the Pegasus Exploits on iOS

eNQc3Ry

eNQc3Ry

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<str<strong>on</strong>g>Pegasus</str<strong>on</strong>g> Persistence Mechanism<br />

The persistence mechanism used by <str<strong>on</strong>g>Pegasus</str<strong>on</strong>g> to reliably execute unsigned code each time <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

device boots (and, ultimately, execute <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel exploit to again jailbreak <str<strong>on</strong>g>the</str<strong>on</strong>g> device) relies <strong>on</strong> a<br />

combinati<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> two distinct issues.<br />

The first issue is <str<strong>on</strong>g>the</str<strong>on</strong>g> presence <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> rtbuddyd service within a plist (to be launched <strong>on</strong> device<br />

boot). Note that prior to <strong>iOS</strong> 10, rtbuddyd is present <strong>on</strong> some iPh<strong>on</strong>e devices for example <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

iPh<strong>on</strong>e 6S, but not <strong>on</strong> o<str<strong>on</strong>g>the</str<strong>on</strong>g>rs like <str<strong>on</strong>g>the</str<strong>on</strong>g> iPh<strong>on</strong>e 6. As a result, any signed binary that can be copied<br />

into <str<strong>on</strong>g>the</str<strong>on</strong>g> specified path (/usr/libexec/rtbuddyd) will be executed at boot time with <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

arguments specified in <str<strong>on</strong>g>the</str<strong>on</strong>g> plist (specifically “--early-boot”).<br />

rtbuddyProgramArgumentsrtbuddyd --<br />

early-bootPerformInRestoreRequireSuccess<br />

Program/usr/libexec/rtbuddyd<br />

As a result <str<strong>on</strong>g>of</str<strong>on</strong>g> this behavior, any signed binary <strong>on</strong> <str<strong>on</strong>g>the</str<strong>on</strong>g> system can be executed at boot with a<br />

single argument. By creating a symlink named --early-boot within <str<strong>on</strong>g>the</str<strong>on</strong>g> current working<br />

directory, an arbitrary file can be passed as <str<strong>on</strong>g>the</str<strong>on</strong>g> first argument to <str<strong>on</strong>g>the</str<strong>on</strong>g> arbitrary signed binary that<br />

has been copied to <str<strong>on</strong>g>the</str<strong>on</strong>g> rtbuddyd locati<strong>on</strong>.<br />

The sec<strong>on</strong>d issue leveraged in this persistence mechanism is a vulnerability within <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

JavaScriptCore binary. <str<strong>on</strong>g>Pegasus</str<strong>on</strong>g> leverages <str<strong>on</strong>g>the</str<strong>on</strong>g> previously described behavior in order to<br />

execute <str<strong>on</strong>g>the</str<strong>on</strong>g> jsc binary (JavaScriptCore) by copying it to <str<strong>on</strong>g>the</str<strong>on</strong>g> path /usr/libexec/rtbuddyd.<br />

Arbitrary JavaScript code can <str<strong>on</strong>g>the</str<strong>on</strong>g>n be executed by creating a symlink named --early-boot<br />

that points to a file c<strong>on</strong>taining <str<strong>on</strong>g>the</str<strong>on</strong>g> code to be executed at boot time. <str<strong>on</strong>g>Pegasus</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g>n exploits a bad<br />

cast in <str<strong>on</strong>g>the</str<strong>on</strong>g> jsc binary to execute unsigned code and re-exploit <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel.<br />

JavaScriptCore Memory Corrupti<strong>on</strong> Issue<br />

The issue exists within <str<strong>on</strong>g>the</str<strong>on</strong>g> setImpureGetterDelegate() JavaScript binding (which is backed by<br />

functi<strong>on</strong>SetImpureGetterDelegate).<br />

EncodedJSValue JSC_HOST_CALL functi<strong>on</strong>SetImpureGetterDelegate(ExecState* exec)<br />

{<br />

JSLockHolder lock(exec);<br />

JSValue base = exec->argument(0);<br />

if (!base.isObject())<br />

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

JSValue delegate = exec->argument(1);<br />

if (!delegate.isObject())<br />

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

ImpureGetter* impureGetter = jsCast(asObject(base.asCell()));<br />

impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));<br />

Page 39

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

Saved successfully!

Ooh no, something went wrong!