Skip to content

Instantly share code, notes, and snippets.

@saelo
Created October 27, 2019 16:04
Show Gist options
  • Star 47 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save saelo/dd598a91a27ddd7cb9e410dc92bf37a1 to your computer and use it in GitHub Desktop.
Save saelo/dd598a91a27ddd7cb9e410dc92bf37a1 to your computer and use it in GitHub Desktop.
3 Years of Attacking JavaScript Engines
|=-----------------------------------------------------------------------=|
|=-------------=[ 3 Years of Attacking JavaScript Engines ]=-------------=|
|=-----------------------------------------------------------------------=|
|=------------------------------=[ saelo ]=------------------------------=|
|=-----------------------------------------------------------------------=|
The following are some brief notes about the changes that have taken place
since the release of the "Attacking JavaScript Engines" paper [1]. In
general, no big conceptional changes have happened since. Mitigations have
been added to break some of the presented techniques and, as expected, a
number of changes to engine implementation details have happened.
--[ 2 - The bug
The bug hunting focus seems to have shifted away from the interpreter and
runtime and more into the JIT compiler land.
----[ 2.2 - About JavaScript conversion rules
Additional callbacks, such as Symbol.ToPrimtive [2] as an alternative to
the valueOf and toString properties, have been added to the JavaScript
language and implemented by the popular engines.
----[ 3.1 - Garbage collector basics
In addition to the GC properties as described in the original paper, JSC's
garbage collector is now also concurrent [3].
----[ 3.3 - Copied space
The CopiedSpace has been removed from JavaScriptCore [4].
--[ 4 - Building exploit primitives
With regards to exploit primitives, only minor changes have taken place since
the release of the original paper, and the "addrof" and "fakeobj" primitives
are still alive and kicking. Alternatively, a somewhat more abstract
"corruptobj" primitive can also often be used to corrupt some part of an
existing object and that way gain for example memory R/W [5].
----[ 4.1 - Prerequisites: Int64
The Int64 module will (hopefully) soon no longer be necessary due to
BigInts [6] becoming widely available.
--[ 6 - Exploitation
A few mitigations have been put into place to break the exploit techniques
described in the original paper and are briefly described next.
----[ 6.1 - Predicting structure IDs
StructureID randomization has been implemented [7]. The idea here is to
randomize the Structure IDs so that predicting them in the way described in
the original paper is no longer possible. I haven't really seen any public,
generic bypasses for this. In any case, the same bug can often be exploited
to also leak a structure ID or corrupt an existing object, thus eliminating
the need to know a structure ID in the first place [8].
----[ 6.2 - Putting things together: faking a Float64Array
A "Gigacage" has been added to WebKit [9] which is designed to stop the
abuse of ArrayBuffers and other objects as described in the original paper
[10, 11]. The common bypass seems to be faking/corrupting JSArrays and that
way obtaining a (slightly limited) memory R/W [8]. Abusing ArrayBuffers to
gain memory R/W is, however, still possible in other engines.
----[ 6.3 - Executing shellcode
On iOS, various generations of JIT mitigations have been developed and
deployed [8], the latest of which uses custom CPU features to protect the
JIT region from an attacker with an arbitrary memory write primitive [12].
Further, on arm64e, PAC is now used to verify the integrity of the
generated machine code right before writing it into the executable JIT
region [13]. It remains to be seen what the new standard (public) post-R/W
exploitation technique will be.
--[ 7 - Abusing the renderer process
Disabling the SOP by compromising the renderer process is still possible in
WebKit but no longer in Chromium due to site isolation [14].
Happy hacking :)
~saelo
--[ 8 - References
[1] http://phrack.org/papers/attacking_javascript_engines.html
[2] https://tc39.es/ecma262/#sec-symbol.toprimitive
[3] https://webkit.org/blog/7122/introducing-riptide-webkits-retreating- wavefront-concurrent-garbage-collector/
[4] https://github.com/WebKit/webkit/commit/d1725cb590133728edf29fce5258c7320657e455
[5] http://phrack.org/papers/jit_exploitation.html
[6] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
[7] https://github.com/WebKit/webkit/commit/f19aec9c6319a216f336aacd1f5cc75abba49cdf
[8] http://iokit.racing/jsctales.pdf
[9] https://github.com/WebKit/webkit/commit/d2bbe276796add2f96b13717d703f86a588409c5
[10] https://phakeobj.netlify.com/posts/gigacage/
[11] https://labs.f-secure.com/archive/some-brief-notes-on-webkit-heap-hardening/
[12] https://siguza.github.io/APRR/
[13] https://github.com/WebKit/webkit/commit/80c907f12e5099c640897fb5e313ff1bd0dacf92
[14] https://www.chromium.org/Home/chromium-security/site-isolation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment