Analysis on CVE-2015-5119

Introduction

In this post, I will give a full COOP-like exploit based on CVE-2015-5119 as demonstrated on cover page. This post will contain two parts. The first part is about how to achieve arbitrary read/write primitive in 64-bit Flash. This part is based on [1][2] with some extra my own explanations. The second part is about how to achieve a COOP-like exploit with virtual function gadgets. I will discuss the dispatcher gadget, argument loading gadget and invoking gadget used in the exploit and pop up the calculator in the end. So I will skip the analysis of root cause of the vulnerability and focus on exploit development.

Environment

Testing against Flash_18_0_0_160.ocx in IE 9.0.8112.16421 on X64 Windows 7 SP1.

Obtain Read/Write Primitive

After the corruption of the metadata, the the corrupted Vector object looks like following:

With some knowledge on the data structure given in [1], we can know that the first 4-byte value at 0x7ffff550000 is a metadata of Vector object and represents the length of the Vector Object. At this point, we are facing the same problem as my exploit on CVE-2016-9079. In a 64-bit system, the corrupted length data can only allow attacker to search through at most 16GB memory space, which is far less than the address space on 64-bit system. Similar to what we do on CVE-2016-9079, we are further using a ByteArray object to achieve search through overall space.
Let’s take a look at the structure of a ByteArray object.

We can find the magic value 0xdeedbeef we put in the script. Then we can locate the address of ByteArray object. 0x69ca92b8 is the vtable pointer of the object. There is a buffer pointer in ByteArray object, which points to the allocated buffer storing data. If attacker can corrupt the pointer to arbitrary valid 64-bit address in memory, attacker can achieve reading and writing value at a given address.

Control Flow Hijacking

The control flow hijacking is achieved via various kinds of virtual function gadget. But the first step is still to overwrite the vtable pointer of the victim object. Different from the exploit given in [1] and [2], we are using the toString method to start our exploit. If we overwrite the vtable pointer to 0x4141414141414141, the crashing site is given below:

Next let me introduce various kinds of gadgets used in my exploit.

Invoking Gadget

We need a virtual function gadget to fetch and invoke function pointer in memory. Different from virtual function call, we want the function pointer to be any function gadget in text region. Therefore, we need to avoid the indirect call which matches the pattern of virtual function call mentioned in previous post Virtual Function.
In the end, we pick sub_307f56cc as our invoking gadget.

The memory layout of virtual table.

Dispatcher Gadget

At first, I was trying to look for some ML-G as in COOP. But I suddenly realise that I do not need so many gadgets. All I need is a function gadget containing two consecutive virtual function calls while this pointer used in those two calls must be different. In the first virtual function call, we change the protection flag of embedded shellcode to executable. In the second virtual function call, we hijacking the control flow to the shellcode.

To this end, we pick sub_304c8400 as our dispatcher gadget:

One thing to note is that this gadget is not a virtual function gadget. In my final working exploit, I use a vtable injection to start exploitation. If we want to use a full vtable reuse attack, we can first divert the control flow to the invoking gadget given above and then continue the following steps.

Argument Loading Gadget

Similar to what we did on Firefox, we try to use some virtual function gadgets to load value from memory to argument register.
First of all, I pick sub_3022a484 as the first argument loading gadget to load some value into rdx.

Then I pick sub_30241ef4 as the second argument loading gadget to properly set the value in rcx, rdx, r8, r9.

Wrapper function to call VirtualProtect

After the chain of argument loading gadget, the values in register except r8 are under control. In order to properly set the value in r8 and save the work of searching base address of kernel32 to invoke VirtualProtect, we decide to reuse some function code in Flash.
The wrapper function we pick in the end is sub_30819cb0 as below:

The logic of the function can be simplified as following pesudocode code (a mixed C and C++ style):

void changeProtection(void *address, int size, bool flag)
{
   int alignment = getAlignment(); //in our exploit, the value is 0x1000
   if( ((unsigned long)address % alignment != 0) || (size % alignment != 0) )
       abort();
   int protectionFlag = flag ? READ_EXECUTE : READ_WRITE;
   VirtualQuery(address, Buffer, 0x30);
   int length = size;
   if(length > Buffer.RegionSize);
         length = Buffer.RegionSize;
   int oldProtect;
   VirtualProtect(address, length, protectionFlag, &oldProtect);
}

From the code above, we can always change the protection flag of target memory region to executable as long as the value in r8 is not zero.

Final Exploit

Therefore, the final exploitation flow is given as following:

sub_304c8400--->sub_3022a484-->sub_30241ef4-->sub_307f56cc-->sub_30819cb0
             |
             |
             -->sub_307f56cc-->Shellcode

In the upper branch, we use the invoking gadget to change the protection flag of the shell code. In the lower branch, we use the invoking gadget to hijack the control flow to shell code.
The full exploit is given at my github repo [3], feel free to use and study.

Conclusion

In this post, I give an explanation on how to achieve arbitrary read/write primitive in the 64-bit Flash Player. Then I give a full exploit depending on the virtual function gadget in Flash module to pop up the calculator. Since this work is part of my PhD study, hope that you enjoy reading this post.
This post actually misses many knowledges on routine exploit techniques. In future, I may pick a CVE on 32-bit system as a tutorial to discuss those techniques step by step.

Reference

[1] https://blog.rapid7.com/2015/07/31/supporting-a-64-bits-renderer-on-flash-cve-2015-5119
[2] https://blog.rapid7.com/2015/08/04/exploiting-a-64-bit-browser-with-flash-cve-2015-5119-part-2/
[3] https://github.com/dangokyo/CVE-2015-5119

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.