文件名称:
Technical Analysis of the Pegasus Exploits on iOS
开发工具:
文件大小: 710kb
下载次数: 0
上传时间: 2019-03-23
详细说明:
Technical Analysis of the Pegasus Exploits on iOS
This section reports on first stage of the Pegasus exploit of the “Trident” zeroday vulnerabilities on iOS, discovered by researchers at Lookout and Citizen Lab. The first stage of the attack is triggered when the user clicks a spearphishing link that opens the Safari browser. This enables the exploit of a vulnerability in WebKit’s JavaScriptCore library (CVE20164657).Section 1: Pegasus Exploitation of Safari
(CVE2016-4657)
The First Stage of Infection
This section reports on first stage of the Pegasus exploit of the Trident zero-day
vulnerabilities on ioS, discovered by researchers at Lookout and Citizen Lab. The
first stage of the attack is triggered when the user clicks a spear-phishing link that
opens the Safari browser. This enables the exploit of a vulnerability in Webkit's
JavaScriptCore library (CVE-2016-4657)
Page 2
Analysis of the Pegasus Safari EXploit
The first stage of Pegasus exploits a vulnerability in WebKit's JavaScript Core library
CVE-2016-4657) The exploit uses the Safari web browser to run a Java Script payload that
exploits the initial vulnerability to gain arbitrary code execution in the context of the Safari
Web Content process
Background
The vulnerability exists within the slow Append method of MarkedArgument Buffer and can be
exploited via the usage of a MarkedArgument Buffer in the static define Properties( method.The
define Properties( method accepts as input an object whose own enumerable properties
constitute descriptors for the properties to be defined or modified on another target object. the
algorithm used to associate each of these properties with the target object does two iterations of
the provided list of properties In the first pass, each of the property descriptors is checked for
proper formatting and a property Descriptor object is created that references the underlying
value
size t numProperties= proper tyNames size()i
Vector descriptors;
MarkedArgumentBuffer markBuffer;
for (size t i =0; i< numProperties; i++)(
USValue prop propercies->get(exec, propertyNamesi])i
if(exec->hadException())
return i sNull()i
PropertyDescriptor descriptor
if(! topropertyDescriptor(exec, prop, descriptor))
return sNull():
descriptors append(descriptor)i
The second pass is performed after each property has been validated this pass associates
each of the user-supplied properties with the target object, using the type specific
define Own Property o method
for (size t i=0;i< numProperties; i++)i
Identifier propertyName propertyNames [i]i
f (exec->propertyNames().isPrivateName (propertyName )
continue
object-methodTable(exec->v())->defineownProper-y(object, exec, prcpertyName
descriptors[il, true)i
This method may result in user-defined JavaScript methods(that are associated with the
property being defined)being called. Within any of these user-defined methods, it is possible
that a garbage collection cycle may be triggered, resulting in any unmarked heap backed
objects being free(ed. Therefore, it is important that each of the temporary references to these
Page 3
objects, stored within the individual Property Descriptors in the descriptors vector, be individually
marked to ensure that these references to not become stale to achieve this a
MarkedArgumentBuffer is used. This class is intended to temporarily prevent the values
appended to it from being garbage collected during the period for which it is in scope
To understand how Marked argumentBuffers work we must first understand some basics of
Java script Core garbage collection. The garbage collector is responsible for deallocating abjects
that are no longer referenced and runs at random intervals that increase in frequency as more
memory is used by the WebContent process to determine whether an object is referenced, the
garbage collector walks the stack and looks for references to the object References to an object
may also exist on the application heap, however, so an alternate mechanism (which will be
explained in detail below)must be used for these cases
A MarkedArgumentBuffer initially attempts to maintain an inline stack buffer containing each
value. When the stack is walked within garbage collection each value will be noted and the
underlying objects will avoid deallocation
class MarkedArgumentBuffer I
private:
static const size t inlinecapacity =3;
MarkedArgumentBuffer(
m sIze
ty(inlines
ty)
m buffer(m inlineBuffer
m market(0
void append (uSvalue v
I(m size
n slow Append (v)i
lotFor(m size)= JSValue:: encode(v)i
十+ In sIZe
int m size
int m capa
EncodeduSValue m inlineBufier[inlinecapacity]i
m buffe
Page 4
The size of this inline stack buffer is limited to eight values. When the ninth value is added to a
MarkedArgumentBuffer, the underlying buffer is moved to the heap and the capacity is
expanded
void MarkedArgumentBuffer:: slowAppend (uSvalue v
int rewCapacity = m capacity 4
EncodedJsvaluex newBuffer new EncodedJSValue [newCapacity]i
for (int i =0, i m capacit
rewBuffer[-]= m bufferili
if(EncodeduSValue* base maliccBase())
delete base
m buffer newBuffer
m capacity newCapacityi
Once the underlying buffer has moved to the heap, values are not automatically protected from
garbage collection. To ensure that these objects are not deallocated the garbage collector
performs a MarkingArgumentBuffers phase in which each value contained within a
MarkedArgumentBuffer that has been added to the Heap's m marklistSet is marked( marking a
cell ensures that it will not be deallocated in a particular garbage collection cycle). For this
method of marking to work, the markedArgumentBuffer must be added to the mark List Set at the
same time that the markedargumentBuffer's underlying values are moved to the heap
// As long as our size stays within our Vector's inline
, capacity, a l our values are allocated on the stack, and
/ trerefore don't need exp_icit marking. Once our size exceeds
// our Vector's inline capacity, though, our values move to the
// heap, where they do need explicit marking
for (int i=0
Eeap* he
H
if ( heap)
heap->markListset()
breaki
The above code attempts to acquire the heap context for a value and add the
MarkedArgumentBuffer to the Heap s markListset However, this is only attempted once for the
ninth value added to the MarkedArgumentBuffer
inline Heap* Heap: hear(const uSVal
f (!v.isdell()
return heap(
11());
a USValue contains a tag which describes the type of the value that it encodes In the case of
complex objects this tag will be Cell Tag and the Js Value will encode a pointer to an underlying
item on the Heap. Alternatively, for simple types where the entire underlying value of the
variable can be encoded directly into a JSValue(ex Integers, Booleans, null, and undefined)
storing the value on the heap would be redundant and a different identifying tag will be used
The function JSValue: is Cello is used to determine whether a Js Value encodes a pointer to a
cell on the Heap. Because simple types do not point to the heap, attempting to acquire the Heap
(via a call to Heap: heap)for these types has no meaning and will therefore return NULL
inline bool JSValue:: isCell() const
return !(u. asInt64 TagMask)i
}
As a result, if the ninth value added to a markedArgumentBuffer is not a heap backed value
attempting to acquire the Heap context will return NULL and the marked Buffer will
never be added to the Heaps marklistset. This means that the markedArgumentBuffer will no
longer serve its purpose(to protect the items that it contains from deallocation) for any item after
the ninth. Any reference to a heap backed property(after the ninth )contained within the
descriptors vector has the potential to go stale. In reality, at least one other reference to these
values still exists(the Java Script variable that was passed to define Properties( ). In order for the
eferences within the descriptors vector to go stale, these remaining references to the jsvalue
must also be removed before garbage collection occurs
He
2. Walk mark ist
Hea
marksetlist
neta-Data
Link not
MarkedArgumentBuffel
I created
backing vector
Garbage
free
Collection
not number
Heap Chunks
arr
3. deallocate
unreferenced cells
target
free
tack
int: 0
not number
targ
The call to define Own Property(within the second loop of define Properties() may result in
calling user-controlled methods defined on property values. As a result, the last marked
Page 6
garbage collection can be triggered between the removal of all remaining references to"/
references to a property value could be removed within this user-defined JavaScript code
property value and the(now stale)value from the descriptors vector being defined on the target
object, a reference to free(ed memory will be defined as a property on the target object
Exploitation
The Pegasus exploit triggers this vulnerability by passing a specifically crafted sequence of
properties to the define Properties method. When these individual properties are subsequently
inserted into a MarkedArgumentBuffer the vulnerability is triggered such that a jsarray object
will be improperly deallocated if garbage collection can be triggered at a critical point in time
Because garbage collection can not be triggered deterministically, the exploit makes repeated
attempts to trigger the improper deallocation and subsequent reallocation(for a total of ten
attempts), testing each time whether a stale reference has been successfully acquired
Assuming garbage collection has been triggered at the correct time, another object is allocated
over the top of the now stale JSArray. The exploit then sets up the tools needed to gain arbitrary
native code execution, namely a read/write primitive and the ability to leak the address of an
arbitrary Java Script object. Once this is complete the exploit can create an executable mapping
containing the native code payload. The following sections detail the various stages of this
orocess
Setting up and triggering the vulnerability
In order to achieve arbitrary code execution, the exploit triggers the vulnerable code path using
a jSArray object The following pseudo code is used to trigger the vulnerability
var arr
ew Array(2047)
var not number
not number tostring function()(
null
props["stale"
// Trigger garbage collection and reallocation over stale object
return 10
p0: value :0 J
2: value 2 1
p
alue
5}
8: vall
stale :i value:
fter :i value 666)
Page 7
var target =[]i
Object. defineproperties(target, props)i
The specified props object has been specifically crafted to trigger the vulnerability in
slow(. When the ninth property is added to the markedArgumentBuffer(p8),
slow Append will fail to acquire a heap context(because the value is simple type, an integer,
and not backed by an item on the heap). Subsequent Heap-backed values(not_number and
arr) will not be explicitly protected from deallocation by the MarkedArgumentBuffer during
garbage collection
When defineOwnProperty( is called for the length property, it will attempt to convert the value
(not_number)to a number. As part of this code path, the toString( method will be called
allowing the last two references to the arr JSArray to be removed. Once removed, this JSArray
is no longer marked, and the next garbage collection pass will deallocate the object. Pegasus
creates memory pressure(allocates a large amount of memory) within the to String( method in
an attempt to force garbage collection to run(and deallocate the arr object
var attempts new Array(4250000)
var pressure new Array (100);
not number toString function() i
for (var i=0; - pressure. -ength; i++)
pressure[i new Uint32Array (262144)i
var buffer new ArrayBuffer(80)i
var uirtArray new Uint32Array (buffer
aRray[o]=0xAABECCDD;
for (i =0; i< attempts. length; i++)
attempts[i]= new Uint32Array (buffer)i
Each of the 4.25 million Uint32Arrays allocated for the attempts array use the same backing
Array Buffer. These objects are used to attempt to reallocate a series of uint32Arrays into the
same memory referenced by the jS Array object (arr)
Once complete, the exploit checks to see whether garbage collection was successfully
triggered
var before len arr length
Object. defineProperties (targe=, props)i
stale target sta e
var after len stale length:
if (before len
after len
hrow rew RecoverableException(8)i
Page 8
If the length of the jSarray remains the same it means that either garbage collection was not
triggered or that none of the allocated Uint 32Arrays were allocated into the same address as the
stale object. In these cases, the exploit has failed and the exploit is retried
Acquiring an arbitrary read/write primitive
Assuming the exploit has succeeded to this point, there are now two objects of different types
that are represented by the same memory. The first is the(now stale)JSArray, and the second
is one of the many Uint32Arrays that were allocated(in fact, the underlying templated type is
JS GenericTypedArray View) By reading from and writing to offsets into the stale object, member
variables of the JS Generic TypedArray View can be read or corrupted. Specifically, the exploit
writes to an offset into the stale jsarray that overlaps with the length of the
JSGenericTypedArray VieW, effectively setting the length of the Uint32Array to OXFFFFFFFF
Corrupting this value will allow the array to be treated as a view of the entire virtual address
space of the Web Content process (an arbitrary read/write primitive)
The exploit still must determine which of the 4.25 million Uint32Arrays that were allocated aligns
with the stale object. This can be determined by iterating through each of the arrays and
checking whether the length has changed to OXF FFFFFFF. All other arrays will still have the
original backing Array Buffer (or a length of 80/4)
(x== attempts -ength -l;x>=li x--)
if (attempts[x]. ength =80/2)
if (attempts[x,length = OXFFFFEFFF)
memory view attempts [x];
Leaking an object address
The final component needed to complete the exploit is the ability to leak the address of an
arbitrary JavaScript object. The Pegasus exploit accomplishes this using the same mechanism
that was used to corrupt the length of the Uint 2Array used for the read/write primitive By
writing to an offset into the stale object, the buffer of a Uint32Array is corrupted to point to a
user-controlled JSArray. By setting the first element of that JSArray to the Java Script object to
be leaked(by corrupting the pointer to the underlying storage of the Uint32Array), the object's
address can be read back out of the Uint32Array
Native code execution
All that is left to do for the first stage of the Pegasus exploit is to create an executable mapping
that will contain the shellcode to be executed. To accomplish this purpose, a JSFunction object
created (containing hundreds of empty try/catch blocks that will later be overwritten). To help
ensure that the JavaScript will be compiled into native code by the Jit, the function is
Page 9
(系统自动生成,下载前可以参看下载内容)
下载文件列表
相关说明
- 本站资源为会员上传分享交流与学习,如有侵犯您的权益,请联系我们删除.
- 本站是交换下载平台,提供交流渠道,下载内容来自于网络,除下载问题外,其它问题请自行百度。
- 本站已设置防盗链,请勿用迅雷、QQ旋风等多线程下载软件下载资源,下载后用WinRAR最新版进行解压.
- 如果您发现内容无法下载,请稍后再次尝试;或者到消费记录里找到下载记录反馈给我们.
- 下载后发现下载的内容跟说明不相乎,请到消费记录里找到下载记录反馈给我们,经确认后退回积分.
- 如下载前有疑问,可以通过点击"提供者"的名字,查看对方的联系方式,联系对方咨询.