December 10, 2013

Flash Player Unloading Vulnerability II

UPDATED 20/February 2014: This vulnerability is CVE-2013-5332 and technical details were publicly announced on 10th December 2013 after the vendor patch was released to end users. On 19th of February 2014 I unexpectedly received an e-mail from HackerOne saying "The Internet Bug Bounty has awarded you a $2000.00 bounty for Flash memory corruption vulnerability could lead to code execution".

Adobe has notified me that it addressed the Flash Player Unloading vulnerability I reported them earlier. The patch is now released to end users and the security bulletin is published which contains the nature of the vulnerability.

In this post, I describe the technical details of the vulnerability in the hope that software developers can learn from it.

In the Windows version of Safari, when a Flash file is opened, the browser initiates to load the Flash Player into the process address space. When the Flash file is no longer opened the browser initiates to unload the Flash Player.

The Flash Player can display a dialog box using MessageBox API. While the dialog box is active, an other thread can unload the Flash Player module from the address space. When the execution returns back from the MessageBox call to the Flash Player module, which is already unloaded, the instruction dereferences freed memory causing data execution prevention exception.

This is a use-after-free vulnerability and it is same in nature to the one I reported Adobe earlier however this time the vulnerability is triggered via a different code path. The crash state looks like below, and it suggests the issue is most likely exploitable for code execution.
(3860.37ec): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=523bb781 ebx=00000001 ecx=006f0d68 edx=00000000 esi=523bb781 edi=00000000
eip=523bb781 esp=001deb90 ebp=001debb8 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210206
<Unloaded_NPSWF32_11_7_700_224.dll>+0x20b781:
523bb781 ??              ???
0:000> |.
.  0          id: 3860               attach    name: C:\Program Files (x86)\Safari\Apple Application Support\WebKit2WebProcess.exe
One possible fix would be to synchronize the DLL unloading thread with the code calling MessageBox.

The vulnerability I reported Adobe earlier is same in nature to this one. Also, if a developer purely adds a new MessageBox call he has a high probability to inherently create a new vulnerability that can be reached in the same way described in this post. Therefore, for Adobe, it would be beneficial to review the entire code base for unsafe dialog box calls.

Also, for Microsoft, hardening on OS level is worthy to consider which may involve to crash in a not exploitable manner when a bug is triggered. The problem looks to be more ubiquitous than the public vulnerability reports suggest. The approach to discover these issues is to identify dialog box and DLL unloading code fragments that can be manually attacked.

Since there may be many bugs that could end up dereferencing unloaded Flash Player, Mozilla long time back fixed the problem by permanently keeping the plugin in the memory in Firefox process.

I'm currently working on tools to identify attack surfaces. It involves to identify DLLs calling MessageBox, and identify ways to unload MessageBox DLLs from the process address space.

I created a sample implementation to represent the vulnerability including how the freed memory gets dereferenced. It is a good exercise for developers to think about how to make the code secure without removing the thread creation.
// This is the EXE file.
// Main thread loads the DLL file to call ShowMessageBox() export that calls MessageBox().
// Secondary thread frees DLL but the dialog box is still visible.
// When OK is clicked the freed memory is dereferenced.
#include <Windows.h>

static HMODULE handle;

DWORD WINAPI Thread(LPVOID lpParam)
{
   printf("[Thread] Waiting 5 seconds.\n");
   Sleep(5000);
   FreeLibrary(handle);
   printf("[Thread] FreeLibrary() called. Click OK to dereference freed memory.\n");
   return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
   typedef void (WINAPI *FUNC)(void);
   FUNC ShowMessageBox;

   handle = LoadLibrary(L"DialogDLL.dll");
   printf("LoadLibrary() called.\n");

   ShowMessageBox = (FUNC)GetProcAddress(handle, "ShowMessageBox");

   CreateThread(NULL, 0, Thread, NULL, NULL, NULL);
   printf("Thread created for FreeLibrary().\n");

   printf("MessageBox pops up.\n");
   ShowMessageBox();
   return 0;
}


// This is the DLL file.
// It has an export that calls MessageBox()
extern "C" __declspec( dllexport ) void ShowMessageBox();

void ShowMessageBox()
{
    MessageBox(NULL, L"...shown by the DLL that can be unloaded while this dialog box is still visible.\n\nThe unloaded DLL
can be dereferenced when OK is clicked.", L"This is a dialog box...", MB_OK);
}
The complete source code for Visual C++ 2010 can be downloaded from here. When executing the program it looks like below.

When OK is clicked the instruction dereferences freed memory.
Just a note that the control transfer instruction to dereference freed memory is not call that can be seen in v-table bugs but ret.
  This blog is written and maintained by Attila Suszter. Read in Feed Reader. Advert is experimentally shown.